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