1 #!/usr/perl5/bin/perl -w 2 # 3 # CDDL HEADER START 4 # 5 # The contents of this file are subject to the terms of the 6 # Common Development and Distribution License (the "License"). 7 # You may not use this file except in compliance with the License. 8 # 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 # or http://www.opensolaris.org/os/licensing. 11 # See the License for the specific language governing permissions 12 # and limitations under the License. 13 # 14 # When distributing Covered Code, include this CDDL HEADER in each 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 # If applicable, add the following below this CDDL HEADER, with the 17 # fields enclosed by brackets "[]" replaced with your own identifying 18 # information: Portions Copyright [yyyy] [name of copyright owner] 19 # 20 # CDDL HEADER END 21 # 22 # 23 # Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 # Use is subject to license terms. 25 # 26 27 # auditxml takes the audit record description (.xml file) and 28 # generates the files needed for the C audit api. 29 30 my $prog = $0; $prog =~ s|.*/||g; 31 my $usage = <<EOF; 32 33 Usage: $prog [options] <xml-input-file> 34 Options: 35 -d Enable debug output 36 -e pfx Internal event prefix (default: AUE) 37 -i pfx Interface prefix (default: adt) 38 External event prefix is uppercase version of this string. 39 -o dir Output directory (default: current dir) 40 41 EOF 42 43 use auditxml; 44 use Getopt::Std; 45 use strict; 46 47 our $debug = 0; # normal use is to set via the file being parsed. 48 # <debug set="on"/> or <debug set="off"/> or <debug/> 49 # if the set attribute is omitted, debug state is toggled 50 # Override with appDebug, but toggle won't do what you 51 # want. 52 my $appDebug = 0; # used after return from "new auditxml"; 53 54 # Process command-line options 55 our ($opt_d, $opt_e, $opt_i, $opt_o); 56 $opt_e = ""; 57 $opt_i = ""; 58 $opt_o = ""; 59 if (!getopts('de:i:o:') || $#ARGV != 0) { 60 die $usage; 61 } 62 my $outdir = $opt_o || "."; 63 my $pfx_adt = lc($opt_i) || "adt"; 64 my $pfx_ADT = uc($pfx_adt); 65 my $pfx_AUE = uc($opt_e) || "AUE"; 66 67 $appDebug = $opt_d; 68 69 my $uniLabel = "adr"; 70 my $xlateUniLabelInc = 0; 71 72 73 # where everything comes from and where it goes: 74 75 my $xlateFile = "$outdir/${pfx_adt}_xlate.c"; 76 my $headerFile = "$outdir/${pfx_adt}_event_N.h"; 77 78 my $filename = $ARGV[0]; # input XML file 79 my $doc = new auditxml ($filename); 80 $filename =~ s|.*/||g; 81 82 $debug = $appDebug; 83 84 my $genNotice = " 85 DO NOT EDIT. This file is auto generated by the Solaris Audit 86 system from $filename. 87 88 See http://opensolaris.org/os/project/audit/ 89 "; 90 91 # trim leading/trailing newlines 92 $genNotice =~ s/^\n//s; 93 $genNotice =~ s/\n$//s; 94 95 my %xlateEventTable = (); 96 my @xlateTypeList = (); 97 my %xlateTypeList = (); 98 my %eventAPI = (); 99 my %eventExtra = (); 100 my %headers = (); 101 my %externalIdNo = (); 102 my @outputState = (); 103 my %nameTranslation = (); 104 my @xlateDefaults = (); 105 my %xlateDefault = (); 106 my %msg_list = (); 107 108 my $event; 109 while ($event = $doc->getNextEvent()) { 110 my $eventId = $event->getId(); 111 my $eventHeader = $event->getHeader(); 112 my $idNo = $event->getIdNo(); 113 $externalIdNo{$eventId} = $idNo; 114 addHeader($eventHeader) if defined ($eventHeader); 115 my $super; 116 my $omit = $event->getOmit(); 117 my $eventType = ''; 118 if ($super = $event->getSuperClass()) { 119 $event = $super; 120 $eventType = 'instance'; 121 } else { 122 $eventType = $event->getType(); 123 } 124 125 # header file for API use 126 generateAPIFile($event, $eventId, $eventType, $eventHeader, $idNo) 127 unless $omit eq 'always'; 128 129 # c file table for translation 130 generateTableC($event, $eventId, $eventType, $eventHeader, $omit); 131 } 132 133 my $textList; 134 while ($textList = $doc->getNextMsgId()) { 135 generateMsgLists($textList); # enum -> text mappings 136 } 137 138 printTableC($xlateFile); 139 printAPIFile($headerFile, $doc); 140 141 exit 0; 142 143 144 sub printTableC { 145 my $file = shift; 146 147 unless (open(Cfile, ">$file")) { 148 print STDERR "can't open output file ($file): $!\n"; 149 return; 150 } 151 152 my $notice = $genNotice; 153 $notice =~ s/\n/\n * /gs; 154 $notice =~ s/\s+\n/\n/gs; 155 print Cfile <<EOF; 156 /* 157 * $notice 158 */ 159 160 #include <bsm/libbsm.h> 161 #include <adt_xlate.h> 162 #include <libintl.h> 163 164 EOF 165 print Cfile "#ifndef _PRAUDIT\n"; 166 print Cfile "/* Internal data type definitions */\n\n"; 167 my $extDef; 168 foreach $extDef (@xlateTypeList) { 169 print Cfile "static $extDef\n"; 170 } 171 @xlateTypeList = (); 172 173 print Cfile "\n/* External event structure to internal event structure */\n\n"; 174 175 my @pointers = (); 176 177 foreach my $eventId (sort keys %xlateEventTable) { 178 if ($xlateEventTable{$eventId}) { 179 my ($ref1, $eventType, $firstToken, $eventHeader) = 180 @{$xlateEventTable{$eventId}}; 181 my @entries = @$ref1; 182 my $entry; 183 my $entries = $#entries; 184 my $count = $entries + 1; 185 my $externalName = $nameTranslation{$eventId}; 186 my $externalRoot = $externalName; 187 $externalRoot =~ s/${pfx_AUE}_//; 188 my $structName = "XX_$externalRoot"; 189 my $root = $eventId; 190 $root =~ s/${pfx_AUE}_//; 191 my $externalId = $eventId; 192 $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/; 193 194 unless ($eventType eq 'generic') { 195 print Cfile "static struct entry $structName\[$count\] = {\n"; 196 foreach $entry (@entries) { 197 if ($entries--) { 198 $entry =~ s/EOL/,/; 199 } 200 else { 201 $entry =~ s/EOL//; 202 } 203 $entry =~ s/selfReference/$structName/; 204 print Cfile "\t$entry\n"; 205 } 206 print Cfile "};\n"; 207 208 print Cfile "static struct translation X_$externalRoot = {\n"; 209 push (@pointers, "X_$externalRoot"); 210 211 print Cfile "\t0,\n"; # tx_offsetsCalculated = 0 212 print Cfile "\t$externalId,\n"; 213 print Cfile "\t$externalName,\n"; 214 215 print Cfile "\t$count,\n"; 216 print Cfile "\t&XX_$externalRoot\[$firstToken\],\n"; 217 print Cfile "\t&XX_$externalRoot\[0\]\n};\n"; 218 } 219 } else { 220 print STDERR "expected entry for $eventId but none found\n"; 221 } 222 } 223 224 my $count = $#pointers + 2; 225 print Cfile "adt_translation_t *${pfx_adt}_xlate_table[$count] = {\n"; 226 227 my $firstEvent = 1; 228 foreach my $eventId (@pointers) { 229 if ($firstEvent) { 230 $firstEvent = 0; 231 } 232 else { 233 print Cfile ",\n"; 234 } 235 print Cfile "\t&$eventId"; 236 } 237 print Cfile ",\n\tNULL\n};\n"; 238 239 # generate the Event preload() function 240 241 print Cfile <<EOF; 242 243 void 244 ${pfx_adt}_preload(au_event_t event_id, adt_event_data_t *event_data) 245 { 246 switch (event_id) { 247 EOF 248 249 foreach my $id (@xlateDefaults) { 250 my $adtID = $id; 251 $adtID =~ s/${pfx_AUE}/${pfx_ADT}/; 252 253 print Cfile <<EOF; 254 case $adtID: 255 EOF 256 my @preloads = @{$xlateDefault{$id}}; 257 while (@preloads) { 258 my $fieldName = shift @preloads; 259 my $default = shift @preloads; 260 $id =~ s/${pfx_AUE}_/${pfx_adt}_/; 261 262 print Cfile <<EOF; 263 event_data->$id.$fieldName = $default; 264 EOF 265 } 266 267 print Cfile <<EOF; 268 break; 269 EOF 270 } 271 272 print Cfile <<EOF; 273 default: 274 break; 275 } 276 } 277 #endif 278 279 EOF 280 281 print Cfile "/* message lists */\n\n"; 282 my $listName; 283 my @listName; 284 foreach $listName (sort keys %msg_list) { 285 my ($listRef, $headref) = @{$msg_list{$listName}}; 286 my ($header, $start, $public, $deprecated) = @$headref; 287 288 my @listValue = @$listRef; 289 my $listValue; 290 my $listLength = $#listValue + 1; 291 292 $listName = 'NULL' if ($#listValue < 0); 293 294 push (@listName, [$listName, $listLength - 1, $start, $public]); 295 296 next if ($#listValue < 0); 297 298 print Cfile "/* Deprecated message list */\n" if ($deprecated); 299 print Cfile "static char *msg_$listName\[$listLength] = {\n"; 300 301 my $ffirst = 1; 302 foreach $listValue (@listValue) { 303 print Cfile ",\n" unless $ffirst; 304 $ffirst = 0; 305 my ($id, $text) = split(/\s*::\s*/, $listValue); 306 if ($text) { 307 print Cfile "\t\"$text\""; 308 } 309 else { 310 print Cfile "\tNULL"; 311 } 312 } 313 print Cfile "\n};\n"; 314 } 315 316 if ($#listName >= 0) { 317 print Cfile "\nstruct msg_text ${pfx_adt}_msg_text[", $#listName + 1, 318 "] = {\n"; 319 my $ffirst = 1; 320 foreach $listName (@listName) { 321 my ($name, $max, $start) = @$listName; 322 $start = -$start if $start; 323 print Cfile ",\n" unless $ffirst; 324 $ffirst = 0; 325 $name = "msg_$name" if ($name ne 'NULL'); 326 print Cfile "\t{0, $max, $name, $start}"; 327 } 328 print Cfile "\n};\n"; 329 } 330 331 close Cfile; 332 } 333 334 sub printAPIFile { 335 my $file = shift; 336 my $xmlDoc = shift; 337 338 my @Hfile; 339 @Hfile = openHeaderFiles($file); 340 341 my $notice = $genNotice; 342 $notice =~ s/\n/\n * /gs; 343 $notice =~ s/\s+\n/\n/gs; 344 345 foreach my $header (keys %headers) { 346 next unless $Hfile[$header]; 347 *Hfile = $Hfile[$header]; 348 my $include = "adt.h"; 349 my $adt_event_n = "_${pfx_ADT}_EVENT_H"; 350 if ($header > 0) { 351 $include = "${pfx_adt}_event.h"; 352 $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H"; 353 } 354 print Hfile <<EOF; 355 /* 356 * $notice 357 */ 358 359 #ifndef $adt_event_n 360 #define $adt_event_n 361 362 #include <bsm/$include> 363 364 #ifdef __cplusplus 365 extern "C" { 366 #endif 367 368 /* 369 * adt_put_event() status values. Positive values are for kernel-generated 370 * failure, -1 for user-space. For ADT_SUCCESS, the adt_put_event() return_val 371 * is not used; the convention is to set it to ADT_SUCCESS. 372 */ 373 #define ADT_SUCCESS 0 374 #define ADT_FAILURE -1 375 376 EOF 377 } 378 379 foreach my $listName (sort keys %msg_list) { 380 my $shortName = uc $listName; 381 $shortName =~ s/_TEXT//; 382 383 my ($listRef, $headref) = @{$msg_list{$listName}}; 384 my ($header, $start, $public, $deprecated) = @$headref; 385 next unless $Hfile[$header]; 386 *Hfile = $Hfile[$header]; 387 388 print Hfile "/* Deprecated message list */\n" if $deprecated; 389 print Hfile "#define\t${pfx_ADT}_$shortName\t$start\n" if $start; 390 391 my @listValue = @$listRef; 392 next unless ($#listValue >= 0); 393 print Hfile "enum\t${pfx_adt}_$listName", " {\n"; 394 395 my $listValue; 396 my $i = 0; 397 my $j = $#listValue; 398 my $comma = ','; 399 foreach $listValue (@listValue) { 400 my ($id, $text) = split(/\s*::\s*/, $listValue); 401 $comma = '' if $i++ == $j; 402 if ($start) { 403 $start = " = $start$comma"; 404 } else { 405 $start = "$comma\t"; 406 } 407 $text = "(no token will be generated)" unless $text; 408 my $line = "\t${pfx_ADT}_$shortName"."_$id$start\t/* "; 409 # ensure whole line does not exceed 80 chars 410 my $eline = $line.$text; 411 #expand tabs 412 1 while $eline =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; 413 if ((length($eline) > 77) && ($line =~ /\t\t/)) { 414 # 77 = 80 - length(" */") 415 # strip off double tab so that comment can be longer 416 $line =~ s/\t\t/\t/; 417 # shorten eline; don't mind where the spaces are removed, it is 418 # only $eline length which matters 419 $eline =~ s/ {8}//; 420 } 421 if (length($eline) > 77) { # 80 - length(" */") 422 # here we use negative length in substr to leave off from the 423 # right side; 74 = 77 - length("...") 424 $line .= substr($text, 0, 74 - length($eline)); 425 # strip off part of last word (already cut) 426 $line =~ s/\s(\S+)$/ /; 427 $line .= "..."; 428 } else { 429 $line .= $text; 430 } 431 print Hfile "$line */\n"; 432 $start = ''; 433 } 434 print Hfile "};\n"; 435 } 436 437 # generate defines for external event names 438 439 foreach my $eventId (sort keys %eventAPI) { 440 my ($header, $idNo) = @{$eventExtra{$eventId}}; 441 unless (defined ($header)) { 442 print STDERR "missing header selection for $eventId\n"; 443 next; 444 } 445 *Hfile = $Hfile[$header]; 446 next unless $Hfile[$header]; 447 448 my $l = length($eventId) + 8; # label plus preceding #define\t 449 $l = 5 - int(($l + 8)/8); 450 $l = 1 if $l < 1; 451 my $tab = "\t" x $l; 452 453 print STDERR "missing id number for $eventId\n" unless $idNo; 454 455 $eventId =~ s/${pfx_AUE}_/${pfx_ADT}_/; 456 print Hfile "#define\t$eventId$tab$idNo\n"; 457 } 458 459 460 # generate per-event structures 461 462 foreach my $eventId (sort keys %eventAPI) { 463 my ($header, $idNo) = @{$eventExtra{$eventId}}; 464 my $dataId = $eventId; 465 $dataId =~ s/^${pfx_AUE}_/${pfx_adt}_/; 466 unless(defined ($header)) { 467 print STDERR "$eventId is missing the header assignment\n"; 468 next; 469 } 470 *Hfile = $Hfile[$header]; 471 next unless $Hfile[$header]; 472 473 my $externalId = $eventId; 474 $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/; 475 476 print Hfile "\nstruct $dataId {\t/* $externalId */\n"; 477 478 my @entries = @{$eventAPI{$eventId}}; 479 my $entry; 480 if ($#entries < 0) { 481 print Hfile "\tint\tdummy;\t/* not used */\n"; 482 } else { 483 foreach $entry (@entries) { 484 $entry =~ s/termid/adt_termid_t/; 485 print Hfile "\t$entry\n"; 486 } 487 } 488 print Hfile "};\n"; 489 $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/; 490 print Hfile "typedef struct $dataId $eventId","_t;\n"; 491 } 492 493 foreach my $header (sort keys %headers) { 494 $outputState[$header] = 0; 495 } 496 497 foreach my $eventId (sort keys %eventAPI) { 498 my ($header, $idNo) = @{$eventExtra{$eventId}}; 499 unless(defined ($header)) { 500 # don't print duplicate error message 501 next; 502 } 503 *Hfile = $Hfile[$header]; 504 next unless $Hfile[$header]; 505 if ($outputState[$header] == 0) { 506 $outputState[$header] = 1; 507 my $suffix = ''; 508 $suffix = "_$header" if $header; 509 print Hfile "\nunion adt_event_data$suffix {\n"; 510 } 511 my $elementName = $eventId; 512 $elementName =~ s/^${pfx_AUE}_/${pfx_adt}_/; 513 $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/; 514 $elementName =~ s/_t$//; 515 516 print Hfile "\t\t$eventId","_t\t$elementName;\n"; 517 } 518 foreach my $header (sort keys %headers) { 519 if ($outputState[$header]) { 520 *Hfile = $Hfile[$header]; 521 next unless $Hfile[$header]; 522 print Hfile "};\n"; 523 } 524 } 525 foreach my $header (keys %headers) { 526 next unless $Hfile[$header]; 527 *Hfile = $Hfile[$header]; 528 my $adt_event_n = "_${pfx_ADT}_EVENT_H"; 529 if ($header > 0) { 530 $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H"; 531 } 532 print Hfile <<EOF; 533 534 535 #ifndef ${pfx_ADT}_PRIVATE 536 #define ${pfx_ADT}_PRIVATE 537 538 /* 539 * These interfaces are project private and will change without 540 * notice as needed for the Solaris Audit project. 541 */ 542 543 extern void adt_get_auid(const adt_session_data_t *, au_id_t *); 544 extern void adt_set_auid(const adt_session_data_t *, const au_id_t); 545 546 extern void adt_get_mask(const adt_session_data_t *, au_mask_t *); 547 extern void adt_set_mask(const adt_session_data_t *, const au_mask_t *); 548 549 extern void adt_get_termid(const adt_session_data_t *, au_tid_addr_t *); 550 extern void adt_set_termid(const adt_session_data_t *, 551 const au_tid_addr_t *); 552 553 extern void adt_get_asid(const adt_session_data_t *, au_asid_t *); 554 extern void adt_set_asid(const adt_session_data_t *, const au_asid_t); 555 extern au_asid_t adt_get_unique_id(au_id_t); 556 extern void adt_load_table(const adt_session_data_t *, adt_translation_t **, 557 void (*preload)(au_event_t, adt_event_data_t *)); 558 559 extern void ${pfx_adt}_preload(au_event_t, adt_event_data_t *); 560 561 extern adt_translation_t *${pfx_adt}_xlate_table[]; 562 563 #endif 564 565 #ifdef __cplusplus 566 } 567 #endif 568 569 #endif /* $adt_event_n */ 570 EOF 571 } 572 closeHeaderFiles(@Hfile); 573 } 574 575 sub generateTableC { 576 my $event = shift; 577 my $eventId = shift; 578 my $eventType = shift; 579 my $eventHeader = shift; 580 my $omit = shift; 581 582 my %tokenType = ( 583 # 584 # tokenTypes are the ones that are actually defined 585 # for use in adt.xml audit records 586 # 587 588 # 'acl' => 'AUT_ACL', # not defined 589 # 'arbitrary' => 'AUT_ARBITRARY', # not defined 590 # 'arg' => 'AUT_ARG', # not defined 591 # 'attr' => 'AUT_ATTR', 592 'command' => 'AUT_CMD', 593 'command_alt' => 'ADT_CMD_ALT', # dummy token id 594 # 'date' => 'AUT_TEXT', # not used 595 # 'exec_args' => 'AUT_EXEC_ARGS', # not defined 596 # 'exec_env' => 'AUT_EXEC_ENV', # not defined 597 # 'exit' => 'AUT_EXIT', # not defined 598 'fmri' => 'AUT_FMRI', 599 # 'groups' => 'AUT_GROUPS', # not defined 600 # 'header' => 'AUT_HEADER', # not defined 601 'in_peer' => 'ADT_IN_PEER', # dummy token id 602 'in_remote' => 'ADT_IN_REMOTE', # dummy token id 603 # 'ipc' => 'AUT_IPC', # not defined 604 # 'ipc_perm' => 'AUT_IPC_PERM', # not defined 605 'iport' => 'AUT_IPORT', 606 'label' => 'AUT_LABEL', 607 'newgroups' => 'AUT_NEWGROUPS', 608 # 'opaque' => 'AUT_OPAQUE', # not defined 609 'path' => 'AUT_PATH', 610 'path_list' => '-AUT_PATH', # dummy token id 611 'process' => 'AUT_PROCESS', 612 'priv_effective' => 'ADT_AUT_PRIV_E', # dummy token id 613 'priv_limit' => 'ADT_AUT_PRIV_L', # dummy token id 614 'priv_inherit' => 'ADT_AUT_PRIV_I', # dummy token id 615 'return' => 'AUT_RETURN', 616 'secflags' => 'AUT_SECFLAGS', 617 # 'seq' => 'AUT_SEQ', # not defined 618 # 'socket' => 'AUT_SOCKET', # not defined 619 # 'socket-inet' => 'AUT_SOCKET_INET', 620 'subject' => 'AUT_SUBJECT', 621 'text' => 'AUT_TEXT', 622 'tid' => 'AUT_TID', 623 # 'trailer' => 'AUT_TRAILER', # not defined 624 'uauth' => 'AUT_UAUTH', 625 'user' => 'AUT_USER', 626 'zonename' => 'AUT_ZONENAME' 627 ); 628 629 my @xlateEntryList = (); 630 631 my $external = $event->getExternal(); 632 my $internal = $event->getInternal(); 633 634 unless ($external) { 635 print STDERR "No external object captured for event $eventId\n"; 636 return; 637 } 638 if ($eventType) { 639 $nameTranslation{$eventId} = $eventId; 640 } else { 641 $nameTranslation{$eventId} = $external->getInternalName(); 642 } 643 unless ($internal) { 644 print STDERR "No internal object captured for event $eventId\n"; 645 return; 646 } 647 my @entryRef = $internal->getEntries(); 648 my $entryRef; 649 my @tokenOrder = (); 650 my $firstTokenIndex = 0; # djdj not used yet, djdj BUG! 651 # needs to be used by translate table 652 653 if ($internal->isReorder()) { # prescan the entry list to get the token order 654 my @inputOrder; 655 foreach $entryRef (@entryRef) { 656 my ($intEntry, $entry) = @$entryRef; 657 push (@inputOrder, $intEntry->getAttr('order')); 658 } 659 660 my $i; # walk down the inputOrder list once 661 my $k = 1; # discover next in line 662 my $l = 0; # who should point to next in line 663 for ($i = 0; $i <= $#inputOrder; $i++) { 664 my $j; 665 for ($j = 0; $j <= $#inputOrder; $j++) { 666 if ($k == $inputOrder[$j]) { 667 if ($k == 1) { 668 $firstTokenIndex = $j; 669 } else { 670 $tokenOrder[$l] = "&(selfReference[$j])"; 671 } 672 $l = $j; 673 last; 674 } 675 } 676 $k++; 677 } 678 $tokenOrder[$l] = 'NULL'; 679 } 680 else { # default order -- input order same as output 681 my $i; 682 my $j; 683 for ($i = 0; $i < $#entryRef; $i++) { 684 my $j = $i + 1; 685 $tokenOrder[$i] = "&(selfReference[$j])"; 686 } 687 $tokenOrder[$#entryRef] = 'NULL'; 688 } 689 690 my $sequence = 0; 691 foreach $entryRef (@entryRef) { 692 my ($intEntry, $entry) = @$entryRef; 693 my $entryId = $entry->getAttr('id'); 694 695 my ($extEntry, $unusedEntry, $tokenId) = 696 $external->getEntry($entryId); 697 my $opt = $extEntry->getAttr('opt'); 698 699 if ($opt eq 'none') { 700 if (defined ($doc->getToken($tokenId))) { 701 if (defined ($tokenType{$tokenId})) { 702 $tokenId = $tokenType{$tokenId}; 703 } 704 else { 705 print STDERR "token id $tokenId not implemented\n"; 706 } 707 } 708 else { 709 print STDERR "token = $tokenId is undefined\n"; 710 $tokenId = 'error'; 711 } 712 my ($xlate, $jni) = 713 formatTableEntry ('', $tokenId, $eventId, '', 0, 0, 714 $tokenOrder[$sequence], 'NULL', '', $omit); 715 push (@xlateEntryList, $xlate); 716 } 717 else { 718 my $dataType = $extEntry->getAttr('type'); 719 $dataType =~ s/\s+//g; # remove blanks (char * => char*) 720 721 my $enumGroup = ''; 722 if ($dataType =~ /^msg/i) { 723 $enumGroup = $dataType; 724 $enumGroup =~ s/^msg\s*//i; 725 $enumGroup = "${pfx_adt}_" . $enumGroup; 726 } 727 my $required = ($opt eq 'required') ? 1 : 0; 728 my $tsol = 0; 729 my $tokenId = $intEntry->getAttr('token'); 730 my $token; 731 my $tokenName; 732 my $tokenFormat = $intEntry->getAttr('format'); 733 if (defined ($tokenFormat)) { 734 $tokenFormat = "\"$tokenFormat\""; 735 } 736 else { 737 $tokenFormat = 'NULL'; 738 } 739 740 if (defined ($token = $doc->getToken($tokenId))) { 741 $tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0; 742 if (defined ($tokenType{$tokenId})) { 743 $tokenName = $tokenType{$tokenId}; 744 } 745 else { 746 print STDERR "token id $tokenId not implemented\n"; 747 } 748 } 749 else { 750 print STDERR 751 "$tokenId is an unimplemented token ($entryId in $eventId)\n"; 752 $tokenName = 'AUT_TEXT'; 753 } 754 my ($xlate, $jni) = 755 formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required, 756 $tsol, $tokenOrder[$sequence], $tokenFormat, 757 $enumGroup, $omit); 758 push (@xlateEntryList, $xlate); 759 } 760 $sequence++; 761 } 762 $xlateEventTable{$eventId} = [\@xlateEntryList, $eventType, $firstTokenIndex, 763 $eventHeader]; 764 } 765 766 sub formatTableEntry { 767 my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, 768 $enumGroup, $omitEntry) = @_; 769 770 771 # does this map belong in the xml source? (at least the defaults?) 772 # fill in the default value only if it is other than zero. 773 # base type adt name, default value 774 my %entryDef = ( 'au_asid_t' => ['ADT_UINT32', ''], 775 'uint_t' => ['ADT_UINT32', ''], 776 'int' => ['ADT_INT', ''], 777 'int32_t' => ['ADT_INT32', ''], 778 'uid_t' => ['ADT_UID', 'AU_NOAUDITID'], 779 'gid_t' => ['ADT_GID', 'AU_NOAUDITID'], 780 'uid_t*' => ['ADT_UIDSTAR', ''], 781 'gid_t*' => ['ADT_GIDSTAR', ''], 782 'char' => ['ADT_CHAR', ''], 783 'char*' => ['ADT_CHARSTAR', ''], 784 'char**' => ['ADT_CHAR2STAR', ''], 785 'long' => ['ADT_LONG', ''], 786 'pid_t' => ['ADT_PID', ''], 787 'priv_set_t*' => ['ADT_PRIVSTAR', ''], 788 'ulong_t' => ['ADT_ULONG', ''], 789 'uint16_t', => ['ADT_UINT16', ''], 790 'uint32_t' => ['ADT_UINT32', ''], 791 'uint32_t*' => ['ADT_UINT32STAR', ''], 792 'uint32_t[]' => ['ADT_UINT32ARRAY', ''], 793 'uint64_t' => ['ADT_UINT64', ''], 794 'uint64_t*' => ['ADT_UINT64STAR', ''], 795 'm_label_t*' => ['ADT_MLABELSTAR', ''], 796 'fd_t' => ['ADT_FD', '-1'], 797 ); 798 my $xlateLabel = $uniLabel.$xlateUniLabelInc; 799 my $xlateLabelInc = 0; 800 my $xlateLine = ''; 801 my @jniLine = (); 802 803 # the list handling should be a simple loop with a loop of one 804 # falling out naturally. 805 806 unless ($type =~ /,/) { # if list, then generate sequence of entries 807 my $dataType; 808 my $dataSize; 809 my $xlateLabelRef = ''; 810 811 my $arraySize = ''; 812 $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/); 813 814 my $entryType = ${$entryDef{$type}}[0]; 815 816 my @xlateType = (); # for adt_xlate.c 817 my $typeCount = 1; 818 819 if ($entryType) { 820 $dataType = $entryType; 821 $type =~ s/([^*]+)\s*(\*+)/$1 $2/; 822 $type =~ s/\[\]//; 823 $dataSize = "sizeof ($type)"; 824 if ($arraySize) { 825 $dataSize = "$arraySize * " . $dataSize; 826 } 827 $xlateLine = "{{$dataType, $dataSize}}"; 828 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); 829 } elsif ($type eq '') { 830 $xlateLabelRef = 'NULL'; 831 } elsif ($type =~ /^msg/i) { 832 $type =~ s/^msg//i; 833 $dataType = 'ADT_MSG'; 834 my $dataEnum = 'ADT_LIST_' . uc $type; 835 $xlateLine = "{{$dataType, $dataEnum}}"; 836 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); 837 } elsif ($type =~ /time_t/i) { 838 $dataType = 'ADT_DATE'; 839 $dataSize = "sizeof (time_t)"; 840 $xlateLine = "{{$dataType, $dataSize}}"; 841 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); 842 } elsif ($type =~ /termid/i) { 843 $dataType = 'ADT_TERMIDSTAR'; 844 $dataSize = "sizeof (au_tid_addr_t *)"; 845 $xlateLine = "{{$dataType, $dataSize}}"; 846 push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); 847 } elsif (uc $omitEntry eq 'JNI') { 848 $xlateLabelRef = 'NULL'; 849 } else { 850 print STDERR "$type is not an implemented data type\n"; 851 $xlateLabelRef = 'NULL'; 852 } 853 if ($xlateLine && !($xlateTypeList{$xlateLine})) { 854 $xlateTypeList{$xlateLine} = $xlateLabel; 855 push (@xlateTypeList, "datadef\t$xlateLabel\[1\] =\t$xlateLine;"); 856 $xlateLabelInc = 1; 857 } else { 858 $xlateLabel = $xlateTypeList{$xlateLine}; 859 } 860 $xlateLabelRef = '&' . $xlateLabel . '[0]' 861 unless $xlateLabelRef eq 'NULL'; 862 863 # "EOL" is where a comma should go unless end of list 864 $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" . 865 "\t\t0,\t$required,\t$tsol,\t$format}EOL"; 866 867 if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$type}}[1]) { 868 my @list = (); 869 if ($xlateDefault{$eventId}) { 870 @list = @{$xlateDefault{$eventId}}; 871 } else { 872 push (@xlateDefaults, $eventId); 873 } 874 push (@list, $id, ${$entryDef{$type}}[1]); 875 $xlateDefault{$eventId} = \@list; 876 } 877 } else { # is a list 878 my @type = split(/,/, $type); 879 my @arraySize = (); 880 my @id = split(/,/, $id); 881 my @jniId = @id; 882 my $dataType; 883 my $typeCount = ($#type + 1); 884 my @xlateType = (); 885 my @default = (); 886 887 foreach my $dtype (@type) { 888 my $jniId = shift @jniId; 889 my $id = shift @id; 890 my $arraySize = ''; 891 $arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/); 892 893 my $entryType = ${$entryDef{$dtype}}[0]; 894 if ($entryType) { 895 my $type = $dtype; 896 $type =~ s/([^*]+)\s*(\*+)/$1 $2/; 897 $type =~ s/\[\]//; 898 899 my $sizeString = "sizeof"; 900 $sizeString = "$arraySize * " . $sizeString if $arraySize; 901 push (@xlateType, "\{$entryType, $sizeString ($type)\}"); 902 push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); 903 } elsif ($type =~ /^msg/i) { 904 $type =~ s/^msg//i; 905 $dataType = 'ADT_MSG'; 906 my $dataEnum = 'ADT_LIST_' . uc $type; 907 push (@xlateType, "\{$dataType, $dataEnum\}};"); 908 push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); 909 } elsif ($type =~ /time_t/i) { 910 $dataType = 'ADT_DATE'; 911 push (@xlateType, "\{$entryType, sizeof ($type)\}"); 912 push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); 913 } elsif ($type =~ /termid/i) { 914 $dataType = 'ADT_TERMIDSTAR'; 915 push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}"); 916 push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); 917 } elsif (uc $omitEntry eq 'JNI') { 918 # nothing to do. 919 } else { 920 print STDERR "$dtype is not an implemented data type\n"; 921 } 922 if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$dtype}}[1]) { 923 push (@default, $id, ${$entryDef{$dtype}}[1]); 924 } 925 } 926 my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};"; 927 928 unless ($xlateTypeList{$xlateArray}) { 929 $xlateTypeList{$xlateArray} = $xlateLabel; 930 $xlateArray = "datadef\t$xlateLabel" . $xlateArray; 931 push (@xlateTypeList, $xlateArray); 932 $xlateLabelInc = 1; 933 } else { 934 $xlateLabel = $xlateTypeList{$xlateArray}; 935 } 936 $xlateLine = 937 "{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" . 938 "\t\t0,\t$required,\t$tsol,\t$format}EOL"; 939 if (@default) { 940 my @list = (); 941 if ($xlateDefault{$eventId}) { 942 @list = @{$xlateDefault{$eventId}}; 943 } else { 944 push (@xlateDefaults, $eventId); 945 } 946 push (@list, @default); 947 $xlateDefault{$eventId} = \@list; 948 } 949 } 950 $xlateUniLabelInc++ if $xlateLabelInc; 951 return ($xlateLine, \@jniLine); 952 } 953 954 sub generateAPIFile { 955 my $event = shift; 956 my $eventId = shift; 957 my $eventType = shift; 958 my $eventHeader = shift; 959 my $idNo = shift; 960 961 my @entryList = (); 962 963 my $external = $event->getExternal(); 964 965 if ($eventType && $debug) { 966 print STDERR "event $eventId is of type $eventType\n"; 967 } 968 969 return unless $external; 970 971 my ($extEntry, $entry, $tokenId, $format); 972 while (($extEntry, $entry, $tokenId, $format) = $external->getNextEntry()) { 973 last unless $entry; 974 my $entryId = $entry->getAttr('id'); 975 976 unless (defined $entryId) { 977 print STDERR "undefined entry id for external $eventId\n"; 978 next; 979 } 980 my $option = $extEntry->getAttr('opt'); 981 next if ($option eq 'none'); 982 983 if (defined (my $token = $doc->getToken($tokenId))) { 984 $option = 'Trusted Solaris only' 985 if (lc $token->getUsage() eq 'tsol') ? 1 : 0; 986 } 987 $option .= " (format: $format)" if $format; 988 989 my $dataType = $extEntry->getAttr('type'); 990 unless (defined $dataType) { 991 print STDERR "no type defined for external tag for $eventId\n"; 992 $dataType = "error"; 993 } 994 995 my $comment = $entry->getContent(); 996 997 if (($dataType =~ /,/) || ($entryId =~ /,/)) { 998 my @type = split(/\s*,\s*/, $dataType); 999 my @id = split(/\s*,\s*/, $entryId); 1000 if ($#type != $#id) { 1001 print STDERR 1002 "number of data types ($dataType) does not match number of ids ($entryId)", 1003 " for event $eventId\n"; 1004 if ($#type < $#id) { 1005 $#id = $#type; 1006 } 1007 else { 1008 $#type = $#id; 1009 } 1010 } 1011 1012 my $i; 1013 my $line = ''; 1014 $line = "/* $comment */\n\t" if defined $comment; 1015 for ($i = 0; $i <= $#type; $i++) { 1016 my ($primitive, $dereference) = 1017 ($type[$i] =~ /([^\*]+)\s*(\**)/); 1018 $id[$i] .= $1 if ($primitive =~ s/(\[\d+\])//); 1019 $line .= "$primitive\t$dereference$id[$i];\t/* $option */"; 1020 push (@entryList, $line); 1021 $line = ''; 1022 } 1023 } 1024 else { 1025 my $line = ''; 1026 $line = "/* $comment */\n\t" if defined $comment; 1027 if ($dataType =~ /^msg/i) { 1028 $dataType =~ s/^msg\s*//i; 1029 $line .= "enum ${pfx_adt}_$dataType" . "\t$entryId;\t/* $option */"; 1030 } 1031 elsif ($dataType =~ /time_t/i) { 1032 $line .= "time_t\t$entryId;\t/* $option */"; 1033 } 1034 else { 1035 my ($primitive, $dereference) = 1036 ($dataType =~ /([^\*]+)\s*(\**)/); 1037 $entryId .= $1 if ($primitive =~ s/(\[\d+\])//); 1038 $line .= "$primitive\t$dereference$entryId;\t/* $option */"; 1039 } 1040 push (@entryList, $line); 1041 } 1042 } 1043 $eventExtra{$eventId} = [$eventHeader, $idNo]; 1044 $eventAPI{$eventId} = \@entryList; 1045 } 1046 1047 sub generateMsgLists { 1048 my $textList = shift; 1049 1050 my $textName = $textList->getId(); 1051 my $header = $textList->getHeader(); 1052 my $start = $textList->getMsgStart(); 1053 my $public = $textList->getMsgPublic(); 1054 my $deprecated = $textList->getDeprecated(); 1055 1056 addHeader($header); 1057 print "$textName starts at $start\n" if $debug; 1058 1059 my $entry; 1060 my @entry; 1061 while ($entry = $textList->getNextMsg()) { 1062 if ($debug) { 1063 my ($id, $text) = split(/\s*::\s*/, $entry); 1064 print " $id = $text\n"; 1065 } 1066 unshift (@entry, $entry); 1067 } 1068 $msg_list{$textName} = 1069 [\@entry, [$header, $start, $public, $deprecated]]; 1070 } 1071 1072 sub addHeader { 1073 my $header_index = shift; 1074 1075 die "invalid adt_event_N.h index: $header_index\n" 1076 unless ($header_index =~ /^\d+$/); 1077 1078 $headers{$header_index} = $header_index; 1079 } 1080 1081 # $header = 0 is a special case; it is for adt_event.h 1082 # $header > 0 creates adt_event_N.h, where N = $header 1083 1084 sub openHeaderFiles { 1085 my $outfile = shift; # path to an adt_event_N.h file 1086 1087 my $header; 1088 my @Hfile = (); # potentially sparse array of file handles 1089 my @HfileName = (); # parallel array to Hfile, file name (not path) 1090 foreach $header (sort keys %headers) { 1091 my $file = $outfile; 1092 if ($header > 0) { 1093 $file =~ s/_N/_$header/; 1094 } else { 1095 $file =~ s/_N//; 1096 } 1097 unless (open($Hfile[$header], ">$file")) { 1098 print STDERR "can't open output ($file): $!\n"; 1099 $HfileName[$header] = ''; 1100 $Hfile[$header] = ''; 1101 } else { 1102 my @tmp = split(/\//, $file); 1103 $HfileName[$header] = $tmp[$#tmp]; 1104 } 1105 } 1106 return (@Hfile); 1107 } 1108 1109 sub closeHeaderFiles { 1110 my @Hfile = @_; 1111 1112 my $header; 1113 foreach $header (sort keys %headers) { 1114 close $Hfile[$header] if $Hfile[$header]; 1115 } 1116 }