1 # 2 # CDDL HEADER START 3 # 4 # The contents of this file are subject to the terms of the 5 # Common Development and Distribution License (the "License"). 6 # You may not use this file except in compliance with the License. 7 # 8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 # or http://www.opensolaris.org/os/licensing. 10 # See the License for the specific language governing permissions 11 # and limitations under the License. 12 # 13 # When distributing Covered Code, include this CDDL HEADER in each 14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 # If applicable, add the following below this CDDL HEADER, with the 16 # fields enclosed by brackets "[]" replaced with your own identifying 17 # information: Portions Copyright [yyyy] [name of copyright owner] 18 # 19 # CDDL HEADER END 20 # 21 # 22 # Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 # Use is subject to license terms. 24 # 25 # ident "%Z%%M% %I% %E% SMI" 26 # 27 28 use xmlHandlers; 29 30 package externalEvent; 31 32 1; 33 34 sub new { 35 my $pkg = shift; 36 my $id = shift; 37 my $obj = shift; 38 39 my @kid = $obj->getKids(); # kids of event are entry or allowed_types 40 41 # separate kids into classes and create hash of entries and an 42 # array of includes 43 44 my %entry = (); 45 my @entry = (); 46 my @allowed_types = (); 47 my @include = (); 48 my $internalName = ''; 49 50 my $kid; 51 foreach $kid (@kid) { 52 my $class = $kid->getClass(); 53 my $kidId = $kid->getAttr('id'); 54 55 if ($class eq 'entry') { 56 my $tokenId = 'undefined'; 57 my $format = ''; 58 my $internal = $kid->getKid('internal'); 59 if (defined $internal) { 60 $tokenId = $internal->getAttr('token'); 61 $format = $internal->getAttr('format'); 62 $format = '' unless defined $format; 63 } 64 my $comment; 65 my $commentKid = $kid->getKid('comment'); 66 if (defined $commentKid) { 67 $comment = $commentKid->getContent; 68 } 69 my $external = $kid->getKid('external'); 70 if (defined ($external)) { 71 $entry{$kidId} = [$external, $kid, $tokenId, $format, $comment]; 72 push (@entry, $kidId); 73 } 74 else { 75 print STDERR "no external attributes defined for $id/$kidId\n"; 76 } 77 } # handle event id translation... 78 elsif ($class eq 'altname') { 79 $internalName = $kid->getAttr('id'); 80 unless (defined $internalName) { 81 print STDERR "missing id for internal name of $id\n"; 82 $internalName = 'error'; 83 } 84 } 85 elsif ($class eq 'allowed_types') { 86 my $content = $kid->getContent(); 87 @allowed_types = (@allowed_types, split(/\s*,\s*/, $content)); 88 } 89 } 90 my @entryCopy = @entry; 91 return bless {'id' => $id, 92 'internalName' => $internalName, 93 'allowed_types' => \@allowed_types, 94 'entry' => \%entry, 95 'entryList' => \@entry, 96 'entryListCopy' => \@entryCopy, 97 'include' => \@include, 98 'xmlObj' => $obj}, $pkg; 99 } 100 101 # return id 102 103 sub getExternalName { 104 my $pkg = shift; 105 106 return $pkg->{'id'}; 107 } 108 109 110 # return internal name if it exists, else id 111 112 sub getInternalName { 113 $pkg = shift; 114 115 if ($pkg->{'internalName'}) { 116 return $pkg->{'internalName'}; 117 } 118 else { 119 return $pkg->{'id'}; 120 } 121 } 122 123 # getNextEntry reads from 'entryList' destructively 124 # but resets when the list after the list is emptied 125 126 sub getNextEntry { 127 my $pkg = shift; 128 129 unless (@{$pkg->{'entryList'}}) { 130 @{$pkg->{'entryList'}} = @{$pkg->{'entryListCopy'}}; 131 return undef; 132 } 133 my $id = shift @{$pkg->{'entryList'}}; 134 135 return ($pkg->getEntry($id)); # getEntry returns an array 136 } 137 138 # getEntryIds returns list of all ids from entryList 139 140 sub getEntryIds { 141 my $pkg = shift; 142 return (@{$pkg->{'entryList'}}); 143 } 144 145 # getEntry returns a selected entry for the current event 146 147 sub getEntry { 148 my $pkg = shift; 149 my $id = shift; #entry id 150 151 my $ref = $pkg->{'entry'}; 152 my $array = $$ref{$id}; 153 154 return @$array; 155 } 156 157 # getNextInclude reads from 'include' destructively 158 159 sub getNextInclude { 160 my $pkg = shift; 161 162 return shift @{$pkg->{'include'}}; 163 } 164 165 # getIncludes returns list of 'include' 166 167 sub getIncludes { 168 my $pkg = shift; 169 return @{$pkg->{'include'}}; 170 } 171 172 # return a reference to the list of event id's allowed for 173 # this generic event 174 175 sub getAllowedTypes { 176 my $pkg = shift; 177 178 return $pkg->{'allowed_types'}; 179 } 180 181 package internalEvent; 182 183 1; 184 185 sub new { 186 my $pkg = shift; 187 my $id = shift; 188 my $obj = shift; 189 190 my @kid = $obj->getKids(); # kids of event are entry 191 192 my @entry = (); 193 194 my $reorder = 0; 195 if ($reorder = $obj->getAttr('reorder')) { 196 $reorder = 1 if $reorder eq 'yes'; 197 } 198 my $kid; 199 foreach $kid (@kid) { 200 my $class = $kid->getClass(); 201 my $id = $kid->getAttr('id'); 202 203 if ($class eq 'entry') { 204 my $internal = $kid->getKid('internal'); 205 if (defined ($internal)) { 206 push (@entry, [$internal, $kid]); 207 } 208 else { 209 print STDERR "no internal attributes defined for $id\n"; 210 } 211 } 212 } 213 return bless {'id' => $id, 214 'reorder' => $reorder, 215 'entry' => \@entry, 216 'xmlObj' => $obj}, $pkg; 217 } 218 219 # getEntries returns a list of all entry references 220 221 sub getEntries { 222 my $pkg = shift; 223 224 return undef unless @{$pkg->{'entry'}}; 225 226 return @{$pkg->{'entry'}}; 227 } 228 229 sub isReorder { 230 my $pkg = shift; 231 232 return $pkg->{'reorder'}; 233 } 234 235 sub getId { 236 my $pkg = shift; 237 238 return $pkg->{'id'}; 239 } 240 241 package eventDef; 242 243 %uniqueId = (); 244 245 1; 246 247 sub new { 248 my $pkg = shift; 249 my $id = shift; 250 my $obj = shift; 251 my $super = shift; 252 253 my $omit; 254 my $type; 255 my $header; 256 my $idNo; 257 my $javaToo; 258 my $title = ''; 259 my @program = (); 260 my @see = (); 261 262 $omit = '' unless $omit = $obj->getAttr('omit'); 263 $type = '' unless $type = $obj->getAttr('type'); 264 $header = 0 unless $header = $obj->getAttr('header'); 265 $idNo = '' unless $idNo = $obj->getAttr('idNo'); 266 267 if ($idNo ne '' && $uniqueId{$idNo}) { 268 print STDERR "$uniqueId{$idNo} and $id have the same id ($idNo)\n"; 269 } 270 else { 271 $uniqueId{$idNo} = $id; 272 } 273 274 return bless {'id' => $id, 275 'header' => $header, 276 'idNo' => $idNo, 277 'omit' => $omit, 278 'super' => $super, 279 'type' => $type, 280 'title' => $title, 281 'program' => \@program, 282 'see' => \@see, 283 'external' => 0, 284 'internal' => 0}, $pkg; 285 } 286 287 # putDef is called at the end of an <event></event> block, so 288 # it sees a completed object. 289 290 sub putDef { 291 my $pkg = shift; 292 my $obj = shift; # ref to xmlHandlers event object 293 my $context = shift; 294 295 my $id = $pkg->{'id'}; 296 297 if ($context eq 'internal') { 298 $pkg->{$context} = new internalEvent($id, $obj); 299 return undef; 300 } elsif ($context eq 'external') { 301 my $ref = $pkg->{$context} = new externalEvent($id, $obj); 302 return $ref->{'internalName'}; 303 } 304 } 305 306 sub getId { 307 my $pkg = shift; 308 309 return $pkg->{'id'}; 310 } 311 312 sub getHeader { 313 my $pkg = shift; 314 315 return $pkg->{'header'}; 316 } 317 318 sub getIdNo { 319 my $pkg = shift; 320 321 return $pkg->{'idNo'}; 322 } 323 324 sub getSuperClass { 325 my $pkg = shift; 326 327 return $pkg->{'super'}; 328 } 329 330 sub getOmit { 331 my $pkg = shift; 332 333 return $pkg->{'omit'}; 334 } 335 336 sub getType { 337 my $pkg = shift; 338 339 return $pkg->{'type'}; 340 } 341 342 sub getTitle { 343 return shift->{'title'}; 344 } 345 346 sub getProgram { 347 return shift->{'program'}; 348 } 349 350 sub getSee { 351 return shift->{'see'}; 352 } 353 354 sub getInternal { 355 my $pkg = shift; 356 357 return $pkg->{'internal'}; 358 } 359 360 sub getExternal { 361 my $pkg = shift; 362 363 return $pkg->{'external'}; 364 } 365 366 # this isn't fully implemented; just a skeleton 367 368 package tokenDef; 369 370 1; 371 372 sub new { 373 my $pkg = shift; 374 my $obj = shift; 375 my $id = shift; 376 377 $usage = $obj->getAttr('usage'); 378 $usage = '' unless defined $usage; 379 380 return bless {'id' => $id, 381 'usage' => $usage 382 }, $pkg; 383 } 384 385 sub getId { 386 my $pkg = shift; 387 388 return $pkg->{'id'}; 389 } 390 391 sub getUsage { 392 my $pkg = shift; 393 394 return $pkg->{'usage'}; 395 } 396 397 package messageList; 398 399 1; 400 401 sub new { 402 my $pkg = shift; 403 my $obj = shift; 404 my $id = shift; 405 my $header = shift; 406 my $start = shift; 407 my $public = shift; 408 my $deprecated = shift; 409 410 my @msg = (); 411 412 my @kid = $obj->getKids(); # kids of msg_list are msg 413 my $kid; 414 foreach $kid (@kid) { 415 my $class = $kid->getClass(); 416 if ($class eq 'msg') { 417 my $text = $kid->getContent(); 418 $text = '' unless defined ($text); 419 my $msgId = $kid->getAttr('id'); 420 if (defined ($msgId)) { 421 push(@msg, join('::', $msgId, $text)); 422 } 423 else { 424 print STDERR "missing id for $class <msg>\n"; 425 } 426 } 427 else { 428 print STDERR "invalid tag in <msg_list> block: $class\n"; 429 } 430 } 431 432 return bless {'id' => $id, 433 'header' => $header, 434 'msg' => \@msg, 435 'start' => $start, 436 'public' => $public, 437 'deprecated' => $deprecated 438 }, $pkg; 439 } 440 441 sub getId { 442 my $pkg = shift; 443 444 return $pkg->{'id'}; 445 } 446 447 sub getMsgStart { 448 my $pkg = shift; 449 450 return $pkg->{'start'}; 451 } 452 453 sub getDeprecated { 454 my $pkg = shift; 455 456 return $pkg->{'deprecated'}; 457 } 458 459 sub getMsgPublic { 460 my $pkg = shift; 461 462 return $pkg->{'public'}; 463 } 464 465 sub getHeader { 466 my $pkg = shift; 467 468 return $pkg->{'header'}; 469 } 470 471 # destructive read of @msg... 472 473 sub getNextMsg { 474 my $pkg = shift; 475 476 my @msg = @{$pkg->{'msg'}}; 477 478 return undef unless @msg; 479 480 my $text = pop(@msg); 481 $pkg->{'msg'} = \@msg; 482 return $text; 483 } 484 485 # returns all msgs 486 sub getMsgs { 487 my $pkg = shift; 488 489 return @{$pkg->{'msg'}}; 490 } 491 492 493 package auditxml; 494 495 # These aren't internal state because the callback functions don't 496 # have the object handle. 497 498 @debug = (); # stack for nesting debug state 499 %event = (); # event name => $objRef 500 @event = (); # event id 501 %token = (); # token name => $objRef 502 @token = (); # token id 503 %msg_list = (); # messageList string list id to obj 504 @msg_list = (); # id list 505 %service = (); # valid service names 506 %externalToInternal = (); # map external event name to internal event name 507 508 1; 509 510 sub new { 511 my $pkg = shift; 512 my $file = shift; # xml file to be parsed 513 514 register('event', \&eventStart, \&eventEnd); 515 register('entry', 0, \&entry); 516 register('external', 0, \&external); 517 register('internal', 0, \&internal); 518 register('include', 0, \&include); 519 register('token', 0, \&token); 520 register('service', 0, \&service); 521 register('msg_list', 0, \&msg_list); 522 register('msg', 0, \&msg); 523 524 # do not use register() for debug because register generates extra 525 # debug information 526 527 xmlHandlers::registerStartCallback('debug', \&debugStart); 528 xmlHandlers::registerEndCallback('debug', \&debugEnd); 529 530 $xml = new xmlHandlers(0, 'top level', $file); 531 532 return bless {'xmlObj' => $xml, 533 'firstToken' => 1, 534 'firstEvent' => 1}, $pkg; 535 } 536 537 # local function -- register both the auditxml function and the 538 # xmlHandler callback 539 540 sub register { 541 my $localName = shift; 542 my $startFunction = shift; 543 my $endFunction = shift; 544 545 if ($startFunction) { 546 xmlHandlers::registerStartCallback($localName, \&completed); 547 $startFunction{$localName} = $startFunction; 548 } 549 if ($endFunction) { 550 xmlHandlers::registerEndCallback($localName, \&completed); 551 $endFunction{$localName} = $endFunction; 552 } 553 } 554 555 sub completed { 556 my $obj = shift; 557 my $callbackSource = shift; 558 559 my $id = $obj->getAttr('id'); 560 my $class = $obj->getClass(); 561 562 if ($main::debug) { 563 print "*** $callbackSource: $class", (defined ($id)) ? "= $id\n" : "\n"; 564 565 my %attributes = $obj->getAttributes(); 566 my $attribute; 567 foreach $attribute (keys %attributes) { 568 print "*** $attribute = $attributes{$attribute}\n"; 569 } 570 my $content = $obj->getContent(); 571 print "*** content = $content\n" if defined $content; 572 } 573 if ($callbackSource eq 'start') { 574 &{$startFunction{$class}}($obj); 575 } 576 elsif ($callbackSource eq 'end') { 577 &{$endFunction{$class}}($obj); 578 } 579 else { 580 print STDERR "no auditxml function defined for $class\n"; 581 } 582 } 583 584 # getNextEvent reads from @event destructively. 'firstEvent' could 585 # be used to make a copy from which to read. 586 587 sub getNextEvent { 588 my $pkg = shift; 589 590 return undef unless (@event); 591 if ($pkg->{'firstEvent'}) { 592 @token = sort @token; 593 $pkg->{'firstEvent'} = 1; 594 } 595 596 my $id = shift @event; 597 598 return $event{$id}; 599 } 600 601 # returns all event ids 602 sub getEventIds { 603 my $pkg = shift; 604 605 return @event; 606 } 607 608 # returns event for id 609 sub getEvent { 610 my $pkg = shift; 611 my $id = shift; 612 613 return $event{$id}; 614 } 615 616 sub getToken { 617 my $pkg = shift; 618 my $id = shift; 619 620 return $token{$id}; 621 } 622 623 # getNextToken reads from @token destructively. 'firstToken' could 624 # be used to make a copy from which to read. 625 626 sub getNextToken { 627 my $pkg = shift; 628 629 return undef unless (@token); 630 631 if ($pkg->{'firstToken'}) { 632 @token = sort @token; 633 $pkg->{'firstToken'} = 1; 634 } 635 my $id = shift @token; 636 637 return $token{$id}; 638 } 639 640 # return token Ids 641 642 sub getTokenIds { 643 my $pkg = shift; 644 645 return @token; 646 } 647 648 # getNextMsgId reads from @msg_list destructively. 649 650 sub getNextMsgId { 651 my $pkg = shift; 652 653 return undef unless (@msg_list); 654 655 my $id = shift @msg_list; 656 657 return ($id, $msg_list{$id}); 658 } 659 660 sub getMsgIds { 661 my $pkg = shift; 662 663 return @msg_list; 664 } 665 666 sub getMsg { 667 my $pkg = shift; 668 my $id = shift; 669 670 return $msg_list{$id}; 671 } 672 673 sub external { 674 } 675 676 sub internal { 677 678 } 679 680 sub eventStart { 681 my $obj = shift; 682 683 my $id = $obj->getAttr('id'); 684 685 unless ($id) { 686 print STDERR "eventStart can't get a valid id\n"; 687 return; 688 } 689 unless (defined $event{$id}) { 690 my $super; 691 if ($super = $obj->getAttr('instance_of')) { 692 $super = $event{$super}; 693 } else { 694 $super = 0; 695 } 696 $event{$id} = new eventDef($id, $obj, $super); 697 push (@event, $id); 698 } else { 699 print STDERR "duplicate event id: $id\n"; 700 } 701 } 702 703 sub eventEnd { 704 my $obj = shift; 705 706 my $id = $obj->getAttr('id'); 707 unless (defined $id) { 708 print STDERR "event element is missing required id attribute\n"; 709 return; 710 } 711 print "event = $id\n" if $main::debug; 712 713 foreach my $kid ($obj->getKids) { 714 my $class = $kid->getClass; 715 next unless ($class =~ /title|program|see/); 716 my $content = $kid->getContent; 717 if ($class eq 'title') { 718 $event{$id}->{$class} = $content; 719 } else { 720 push @{$event{$id}->{$class}}, $content; 721 } 722 } 723 $event{$id}->putDef($obj, 'internal'); 724 725 my $internalName = $event{$id}->putDef($obj, 'external'); 726 727 $externalToInternal{$id} = $internalName if $internalName; 728 } 729 730 # class method 731 732 #sub getInternalName { 733 # my $name = shift; 734 # 735 # return $externalToInternal{$name}; 736 #} 737 738 sub entry { 739 } 740 741 #sub include { 742 # my $obj = shift; 743 # 744 # my $id = $obj->getAttr('id'); 745 # 746 # if (defined $id) { 747 # print "include = $id\n" if $main::debug; 748 # } 749 # else { 750 # print STDERR "include element is missing required id attribute\n"; 751 # } 752 #} 753 754 sub token { 755 my $obj = shift; 756 757 my $id = $obj->getAttr('id'); 758 759 if (defined $id) { 760 print "token = $id\n" if $main::debug; 761 $token{$id} = new tokenDef($obj, $id); 762 push (@token, $id); 763 } 764 else { 765 print STDERR "token element is missing required id attribute\n"; 766 } 767 } 768 769 sub msg_list { 770 my $obj = shift; 771 772 my $id = $obj->getAttr('id'); 773 my $header = $obj->getAttr('header'); 774 my $start = $obj->getAttr('start'); 775 my $public = $obj->getAttr('public'); 776 my $deprecated = $obj->getAttr('deprecated'); 777 778 $header = 0 unless $header; 779 $start = 0 unless $start; 780 $public = ($public) ? 1 : 0; 781 $deprecated = ($deprecated) ? 1 : 0; 782 783 if (defined $id) { 784 print "msg_list = $id\n" if $main::debug; 785 $msg_list{$id} = new messageList($obj, $id, $header, $start, 786 $public, $deprecated); 787 push (@msg_list, $id); 788 } 789 else { 790 print STDERR 791 "msg_list element is missing required id attribute\n"; 792 } 793 } 794 795 sub msg { 796 # my $obj = shift; 797 } 798 799 # Service name was dropped during PSARC review 800 801 sub service { 802 my $obj = shift; 803 804 my $name = $obj->getAttr('name'); 805 my $id = $obj->getAttr('id'); 806 807 if ((defined $id) && (defined $name)) { 808 print "service $name = $id\n" if $main::debug; 809 $service{$name} = $id; 810 } 811 elsif (defined $name) { 812 print STDERR "service $name is missing an id number\n"; 813 } 814 elsif (defined $id) { 815 print STDERR "service name missing for id = $id\n"; 816 } 817 else { 818 print STDERR "missing both name and id for a service entry\n"; 819 } 820 } 821 822 #sub getServices { 823 # 824 # return %service; 825 #} 826 827 # <debug set="on"> or <debug set="off"> or <debug> 828 # if the set attribute is omitted, debug state is toggled 829 830 # debugStart / debugEnd are used to insure debug state is 831 # scoped to the block between <debug> and </debug> 832 833 sub debugStart { 834 my $obj = shift; 835 836 push (@debug, $main::debug); 837 my $debug = $main::debug; 838 839 my $state = $obj->getAttr('set'); 840 841 if (defined $state) { 842 $main::debug = ($state eq 'on') ? 1 : 0; 843 } 844 else { 845 $main::debug = !$debug; 846 } 847 if ($debug != $main::debug) { 848 print 'debug is ', $main::debug ? 'on' : 'off', "\n"; 849 } 850 } 851 852 sub debugEnd { 853 my $obj = shift; 854 855 my $debug = $main::debug; 856 $main::debug = pop (@debug); 857 858 if ($debug != $main::debug) { 859 print 'debug is ', $main::debug ? 'on' : 'off', "\n"; 860 } 861 } 862