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 28use xmlHandlers; 29 30package externalEvent; 31 321; 33 34sub 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 103sub getExternalName { 104 my $pkg = shift; 105 106 return $pkg->{'id'}; 107} 108 109 110# return internal name if it exists, else id 111 112sub 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 126sub 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 140sub getEntryIds { 141 my $pkg = shift; 142 return (@{$pkg->{'entryList'}}); 143} 144 145# getEntry returns a selected entry for the current event 146 147sub 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 159sub getNextInclude { 160 my $pkg = shift; 161 162 return shift @{$pkg->{'include'}}; 163} 164 165# getIncludes returns list of 'include' 166 167sub 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 175sub getAllowedTypes { 176 my $pkg = shift; 177 178 return $pkg->{'allowed_types'}; 179} 180 181package internalEvent; 182 1831; 184 185sub 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 221sub getEntries { 222 my $pkg = shift; 223 224 return undef unless @{$pkg->{'entry'}}; 225 226 return @{$pkg->{'entry'}}; 227} 228 229sub isReorder { 230 my $pkg = shift; 231 232 return $pkg->{'reorder'}; 233} 234 235sub getId { 236 my $pkg = shift; 237 238 return $pkg->{'id'}; 239} 240 241package eventDef; 242 243%uniqueId = (); 244 2451; 246 247sub 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 290sub 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 306sub getId { 307 my $pkg = shift; 308 309 return $pkg->{'id'}; 310} 311 312sub getHeader { 313 my $pkg = shift; 314 315 return $pkg->{'header'}; 316} 317 318sub getIdNo { 319 my $pkg = shift; 320 321 return $pkg->{'idNo'}; 322} 323 324sub getSuperClass { 325 my $pkg = shift; 326 327 return $pkg->{'super'}; 328} 329 330sub getOmit { 331 my $pkg = shift; 332 333 return $pkg->{'omit'}; 334} 335 336sub getType { 337 my $pkg = shift; 338 339 return $pkg->{'type'}; 340} 341 342sub getTitle { 343 return shift->{'title'}; 344} 345 346sub getProgram { 347 return shift->{'program'}; 348} 349 350sub getSee { 351 return shift->{'see'}; 352} 353 354sub getInternal { 355 my $pkg = shift; 356 357 return $pkg->{'internal'}; 358} 359 360sub getExternal { 361 my $pkg = shift; 362 363 return $pkg->{'external'}; 364} 365 366# this isn't fully implemented; just a skeleton 367 368package tokenDef; 369 3701; 371 372sub 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 385sub getId { 386 my $pkg = shift; 387 388 return $pkg->{'id'}; 389} 390 391sub getUsage { 392 my $pkg = shift; 393 394 return $pkg->{'usage'}; 395} 396 397package messageList; 398 3991; 400 401sub 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 441sub getId { 442 my $pkg = shift; 443 444 return $pkg->{'id'}; 445} 446 447sub getMsgStart { 448 my $pkg = shift; 449 450 return $pkg->{'start'}; 451} 452 453sub getDeprecated { 454 my $pkg = shift; 455 456 return $pkg->{'deprecated'}; 457} 458 459sub getMsgPublic { 460 my $pkg = shift; 461 462 return $pkg->{'public'}; 463} 464 465sub getHeader { 466 my $pkg = shift; 467 468 return $pkg->{'header'}; 469} 470 471# destructive read of @msg... 472 473sub 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 486sub getMsgs { 487 my $pkg = shift; 488 489 return @{$pkg->{'msg'}}; 490} 491 492 493package 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 5081; 509 510sub 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 540sub 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 555sub 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 587sub 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 602sub getEventIds { 603 my $pkg = shift; 604 605 return @event; 606} 607 608# returns event for id 609sub getEvent { 610 my $pkg = shift; 611 my $id = shift; 612 613 return $event{$id}; 614} 615 616sub 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 626sub 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 642sub getTokenIds { 643 my $pkg = shift; 644 645 return @token; 646} 647 648# getNextMsgId reads from @msg_list destructively. 649 650sub 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 660sub getMsgIds { 661 my $pkg = shift; 662 663 return @msg_list; 664} 665 666sub getMsg { 667 my $pkg = shift; 668 my $id = shift; 669 670 return $msg_list{$id}; 671} 672 673sub external { 674} 675 676sub internal { 677 678} 679 680sub 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 703sub 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 738sub 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 754sub 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 769sub 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 795sub msg { 796# my $obj = shift; 797} 798 799# Service name was dropped during PSARC review 800 801sub 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 833sub 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 852sub 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