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