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