| #!/usr/perl5/bin/perl -w |
| # |
| # CDDL HEADER START |
| # |
| # The contents of this file are subject to the terms of the |
| # Common Development and Distribution License (the "License"). |
| # You may not use this file except in compliance with the License. |
| # |
| # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| # or http://www.opensolaris.org/os/licensing. |
| # See the License for the specific language governing permissions |
| # and limitations under the License. |
| # |
| # When distributing Covered Code, include this CDDL HEADER in each |
| # file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| # If applicable, add the following below this CDDL HEADER, with the |
| # fields enclosed by brackets "[]" replaced with your own identifying |
| # information: Portions Copyright [yyyy] [name of copyright owner] |
| # |
| # CDDL HEADER END |
| # |
| # |
| # Copyright 2010 Sun Microsystems, Inc. All rights reserved. |
| # Use is subject to license terms. |
| # |
| |
| # auditxml takes the audit record description (.xml file) and |
| # generates the files needed for the C audit api. |
| |
| my $prog = $0; $prog =~ s|.*/||g; |
| my $usage = <<EOF; |
| |
| Usage: $prog [options] <xml-input-file> |
| Options: |
| -d Enable debug output |
| -e pfx Internal event prefix (default: AUE) |
| -i pfx Interface prefix (default: adt) |
| External event prefix is uppercase version of this string. |
| -o dir Output directory (default: current dir) |
| |
| EOF |
| |
| use auditxml; |
| use Getopt::Std; |
| use strict; |
| |
| our $debug = 0; # normal use is to set via the file being parsed. |
| # <debug set="on"/> or <debug set="off"/> or <debug/> |
| # if the set attribute is omitted, debug state is toggled |
| # Override with appDebug, but toggle won't do what you |
| # want. |
| my $appDebug = 0; # used after return from "new auditxml"; |
| |
| # Process command-line options |
| our ($opt_d, $opt_e, $opt_i, $opt_o); |
| $opt_e = ""; |
| $opt_i = ""; |
| $opt_o = ""; |
| if (!getopts('de:i:o:') || $#ARGV != 0) { |
| die $usage; |
| } |
| my $outdir = $opt_o || "."; |
| my $pfx_adt = lc($opt_i) || "adt"; |
| my $pfx_ADT = uc($pfx_adt); |
| my $pfx_AUE = uc($opt_e) || "AUE"; |
| |
| $appDebug = $opt_d; |
| |
| my $uniLabel = "adr"; |
| my $xlateUniLabelInc = 0; |
| |
| |
| # where everything comes from and where it goes: |
| |
| my $xlateFile = "$outdir/${pfx_adt}_xlate.c"; |
| my $headerFile = "$outdir/${pfx_adt}_event_N.h"; |
| |
| my $filename = $ARGV[0]; # input XML file |
| my $doc = new auditxml ($filename); |
| $filename =~ s|.*/||g; |
| |
| $debug = $appDebug; |
| |
| my $genNotice = " |
| DO NOT EDIT. This file is auto generated by the Solaris Audit |
| system from $filename. |
| |
| See http://opensolaris.org/os/project/audit/ |
| "; |
| |
| # trim leading/trailing newlines |
| $genNotice =~ s/^\n//s; |
| $genNotice =~ s/\n$//s; |
| |
| my %xlateEventTable = (); |
| my @xlateTypeList = (); |
| my %xlateTypeList = (); |
| my %eventAPI = (); |
| my %eventExtra = (); |
| my %headers = (); |
| my %externalIdNo = (); |
| my @outputState = (); |
| my %nameTranslation = (); |
| my @xlateDefaults = (); |
| my %xlateDefault = (); |
| my %msg_list = (); |
| |
| my $event; |
| while ($event = $doc->getNextEvent()) { |
| my $eventId = $event->getId(); |
| my $eventHeader = $event->getHeader(); |
| my $idNo = $event->getIdNo(); |
| $externalIdNo{$eventId} = $idNo; |
| addHeader($eventHeader) if defined ($eventHeader); |
| my $super; |
| my $omit = $event->getOmit(); |
| my $eventType = ''; |
| if ($super = $event->getSuperClass()) { |
| $event = $super; |
| $eventType = 'instance'; |
| } else { |
| $eventType = $event->getType(); |
| } |
| |
| # header file for API use |
| generateAPIFile($event, $eventId, $eventType, $eventHeader, $idNo) |
| unless $omit eq 'always'; |
| |
| # c file table for translation |
| generateTableC($event, $eventId, $eventType, $eventHeader, $omit); |
| } |
| |
| my $textList; |
| while ($textList = $doc->getNextMsgId()) { |
| generateMsgLists($textList); # enum -> text mappings |
| } |
| |
| printTableC($xlateFile); |
| printAPIFile($headerFile, $doc); |
| |
| exit 0; |
| |
| |
| sub printTableC { |
| my $file = shift; |
| |
| unless (open(Cfile, ">$file")) { |
| print STDERR "can't open output file ($file): $!\n"; |
| return; |
| } |
| |
| my $notice = $genNotice; |
| $notice =~ s/\n/\n * /gs; |
| $notice =~ s/\s+\n/\n/gs; |
| print Cfile <<EOF; |
| /* |
| * $notice |
| */ |
| |
| #include <bsm/libbsm.h> |
| #include <adt_xlate.h> |
| #include <libintl.h> |
| |
| EOF |
| print Cfile "#ifndef _PRAUDIT\n"; |
| print Cfile "/* Internal data type definitions */\n\n"; |
| my $extDef; |
| foreach $extDef (@xlateTypeList) { |
| print Cfile "static $extDef\n"; |
| } |
| @xlateTypeList = (); |
| |
| print Cfile "\n/* External event structure to internal event structure */\n\n"; |
| |
| my @pointers = (); |
| |
| foreach my $eventId (sort keys %xlateEventTable) { |
| if ($xlateEventTable{$eventId}) { |
| my ($ref1, $eventType, $firstToken, $eventHeader) = |
| @{$xlateEventTable{$eventId}}; |
| my @entries = @$ref1; |
| my $entry; |
| my $entries = $#entries; |
| my $count = $entries + 1; |
| my $externalName = $nameTranslation{$eventId}; |
| my $externalRoot = $externalName; |
| $externalRoot =~ s/${pfx_AUE}_//; |
| my $structName = "XX_$externalRoot"; |
| my $root = $eventId; |
| $root =~ s/${pfx_AUE}_//; |
| my $externalId = $eventId; |
| $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/; |
| |
| unless ($eventType eq 'generic') { |
| print Cfile "static struct entry $structName\[$count\] = {\n"; |
| foreach $entry (@entries) { |
| if ($entries--) { |
| $entry =~ s/EOL/,/; |
| } |
| else { |
| $entry =~ s/EOL//; |
| } |
| $entry =~ s/selfReference/$structName/; |
| print Cfile "\t$entry\n"; |
| } |
| print Cfile "};\n"; |
| |
| print Cfile "static struct translation X_$externalRoot = {\n"; |
| push (@pointers, "X_$externalRoot"); |
| |
| print Cfile "\t0,\n"; # tx_offsetsCalculated = 0 |
| print Cfile "\t$externalId,\n"; |
| print Cfile "\t$externalName,\n"; |
| |
| print Cfile "\t$count,\n"; |
| print Cfile "\t&XX_$externalRoot\[$firstToken\],\n"; |
| print Cfile "\t&XX_$externalRoot\[0\]\n};\n"; |
| } |
| } else { |
| print STDERR "expected entry for $eventId but none found\n"; |
| } |
| } |
| |
| my $count = $#pointers + 2; |
| print Cfile "adt_translation_t *${pfx_adt}_xlate_table[$count] = {\n"; |
| |
| my $firstEvent = 1; |
| foreach my $eventId (@pointers) { |
| if ($firstEvent) { |
| $firstEvent = 0; |
| } |
| else { |
| print Cfile ",\n"; |
| } |
| print Cfile "\t&$eventId"; |
| } |
| print Cfile ",\n\tNULL\n};\n"; |
| |
| # generate the Event preload() function |
| |
| print Cfile <<EOF; |
| |
| void |
| ${pfx_adt}_preload(au_event_t event_id, adt_event_data_t *event_data) |
| { |
| switch (event_id) { |
| EOF |
| |
| foreach my $id (@xlateDefaults) { |
| my $adtID = $id; |
| $adtID =~ s/${pfx_AUE}/${pfx_ADT}/; |
| |
| print Cfile <<EOF; |
| case $adtID: |
| EOF |
| my @preloads = @{$xlateDefault{$id}}; |
| while (@preloads) { |
| my $fieldName = shift @preloads; |
| my $default = shift @preloads; |
| $id =~ s/${pfx_AUE}_/${pfx_adt}_/; |
| |
| print Cfile <<EOF; |
| event_data->$id.$fieldName = $default; |
| EOF |
| } |
| |
| print Cfile <<EOF; |
| break; |
| EOF |
| } |
| |
| print Cfile <<EOF; |
| default: |
| break; |
| } |
| } |
| #endif |
| |
| EOF |
| |
| print Cfile "/* message lists */\n\n"; |
| my $listName; |
| my @listName; |
| foreach $listName (sort keys %msg_list) { |
| my ($listRef, $headref) = @{$msg_list{$listName}}; |
| my ($header, $start, $public, $deprecated) = @$headref; |
| |
| my @listValue = @$listRef; |
| my $listValue; |
| my $listLength = $#listValue + 1; |
| |
| $listName = 'NULL' if ($#listValue < 0); |
| |
| push (@listName, [$listName, $listLength - 1, $start, $public]); |
| |
| next if ($#listValue < 0); |
| |
| print Cfile "/* Deprecated message list */\n" if ($deprecated); |
| print Cfile "static char *msg_$listName\[$listLength] = {\n"; |
| |
| my $ffirst = 1; |
| foreach $listValue (@listValue) { |
| print Cfile ",\n" unless $ffirst; |
| $ffirst = 0; |
| my ($id, $text) = split(/\s*::\s*/, $listValue); |
| if ($text) { |
| print Cfile "\t\"$text\""; |
| } |
| else { |
| print Cfile "\tNULL"; |
| } |
| } |
| print Cfile "\n};\n"; |
| } |
| |
| if ($#listName >= 0) { |
| print Cfile "\nstruct msg_text ${pfx_adt}_msg_text[", $#listName + 1, |
| "] = {\n"; |
| my $ffirst = 1; |
| foreach $listName (@listName) { |
| my ($name, $max, $start) = @$listName; |
| $start = -$start if $start; |
| print Cfile ",\n" unless $ffirst; |
| $ffirst = 0; |
| $name = "msg_$name" if ($name ne 'NULL'); |
| print Cfile "\t{0, $max, $name, $start}"; |
| } |
| print Cfile "\n};\n"; |
| } |
| |
| close Cfile; |
| } |
| |
| sub printAPIFile { |
| my $file = shift; |
| my $xmlDoc = shift; |
| |
| my @Hfile; |
| @Hfile = openHeaderFiles($file); |
| |
| my $notice = $genNotice; |
| $notice =~ s/\n/\n * /gs; |
| $notice =~ s/\s+\n/\n/gs; |
| |
| foreach my $header (keys %headers) { |
| next unless $Hfile[$header]; |
| *Hfile = $Hfile[$header]; |
| my $include = "adt.h"; |
| my $adt_event_n = "_${pfx_ADT}_EVENT_H"; |
| if ($header > 0) { |
| $include = "${pfx_adt}_event.h"; |
| $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H"; |
| } |
| print Hfile <<EOF; |
| /* |
| * $notice |
| */ |
| |
| #ifndef $adt_event_n |
| #define $adt_event_n |
| |
| #include <bsm/$include> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* |
| * adt_put_event() status values. Positive values are for kernel-generated |
| * failure, -1 for user-space. For ADT_SUCCESS, the adt_put_event() return_val |
| * is not used; the convention is to set it to ADT_SUCCESS. |
| */ |
| #define ADT_SUCCESS 0 |
| #define ADT_FAILURE -1 |
| |
| EOF |
| } |
| |
| foreach my $listName (sort keys %msg_list) { |
| my $shortName = uc $listName; |
| $shortName =~ s/_TEXT//; |
| |
| my ($listRef, $headref) = @{$msg_list{$listName}}; |
| my ($header, $start, $public, $deprecated) = @$headref; |
| next unless $Hfile[$header]; |
| *Hfile = $Hfile[$header]; |
| |
| print Hfile "/* Deprecated message list */\n" if $deprecated; |
| print Hfile "#define\t${pfx_ADT}_$shortName\t$start\n" if $start; |
| |
| my @listValue = @$listRef; |
| next unless ($#listValue >= 0); |
| print Hfile "enum\t${pfx_adt}_$listName", " {\n"; |
| |
| my $listValue; |
| my $i = 0; |
| my $j = $#listValue; |
| my $comma = ','; |
| foreach $listValue (@listValue) { |
| my ($id, $text) = split(/\s*::\s*/, $listValue); |
| $comma = '' if $i++ == $j; |
| if ($start) { |
| $start = " = $start$comma"; |
| } else { |
| $start = "$comma\t"; |
| } |
| $text = "(no token will be generated)" unless $text; |
| my $line = "\t${pfx_ADT}_$shortName"."_$id$start\t/* "; |
| # ensure whole line does not exceed 80 chars |
| my $eline = $line.$text; |
| #expand tabs |
| 1 while $eline =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e; |
| if ((length($eline) > 77) && ($line =~ /\t\t/)) { |
| # 77 = 80 - length(" */") |
| # strip off double tab so that comment can be longer |
| $line =~ s/\t\t/\t/; |
| # shorten eline; don't mind where the spaces are removed, it is |
| # only $eline length which matters |
| $eline =~ s/ {8}//; |
| } |
| if (length($eline) > 77) { # 80 - length(" */") |
| # here we use negative length in substr to leave off from the |
| # right side; 74 = 77 - length("...") |
| $line .= substr($text, 0, 74 - length($eline)); |
| # strip off part of last word (already cut) |
| $line =~ s/\s(\S+)$/ /; |
| $line .= "..."; |
| } else { |
| $line .= $text; |
| } |
| print Hfile "$line */\n"; |
| $start = ''; |
| } |
| print Hfile "};\n"; |
| } |
| |
| # generate defines for external event names |
| |
| foreach my $eventId (sort keys %eventAPI) { |
| my ($header, $idNo) = @{$eventExtra{$eventId}}; |
| unless (defined ($header)) { |
| print STDERR "missing header selection for $eventId\n"; |
| next; |
| } |
| *Hfile = $Hfile[$header]; |
| next unless $Hfile[$header]; |
| |
| my $l = length($eventId) + 8; # label plus preceding #define\t |
| $l = 5 - int(($l + 8)/8); |
| $l = 1 if $l < 1; |
| my $tab = "\t" x $l; |
| |
| print STDERR "missing id number for $eventId\n" unless $idNo; |
| |
| $eventId =~ s/${pfx_AUE}_/${pfx_ADT}_/; |
| print Hfile "#define\t$eventId$tab$idNo\n"; |
| } |
| |
| |
| # generate per-event structures |
| |
| foreach my $eventId (sort keys %eventAPI) { |
| my ($header, $idNo) = @{$eventExtra{$eventId}}; |
| my $dataId = $eventId; |
| $dataId =~ s/^${pfx_AUE}_/${pfx_adt}_/; |
| unless(defined ($header)) { |
| print STDERR "$eventId is missing the header assignment\n"; |
| next; |
| } |
| *Hfile = $Hfile[$header]; |
| next unless $Hfile[$header]; |
| |
| my $externalId = $eventId; |
| $externalId =~ s/${pfx_AUE}_/${pfx_ADT}_/; |
| |
| print Hfile "\nstruct $dataId {\t/* $externalId */\n"; |
| |
| my @entries = @{$eventAPI{$eventId}}; |
| my $entry; |
| if ($#entries < 0) { |
| print Hfile "\tint\tdummy;\t/* not used */\n"; |
| } else { |
| foreach $entry (@entries) { |
| $entry =~ s/termid/adt_termid_t/; |
| print Hfile "\t$entry\n"; |
| } |
| } |
| print Hfile "};\n"; |
| $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/; |
| print Hfile "typedef struct $dataId $eventId","_t;\n"; |
| } |
| |
| foreach my $header (sort keys %headers) { |
| $outputState[$header] = 0; |
| } |
| |
| foreach my $eventId (sort keys %eventAPI) { |
| my ($header, $idNo) = @{$eventExtra{$eventId}}; |
| unless(defined ($header)) { |
| # don't print duplicate error message |
| next; |
| } |
| *Hfile = $Hfile[$header]; |
| next unless $Hfile[$header]; |
| if ($outputState[$header] == 0) { |
| $outputState[$header] = 1; |
| my $suffix = ''; |
| $suffix = "_$header" if $header; |
| print Hfile "\nunion adt_event_data$suffix {\n"; |
| } |
| my $elementName = $eventId; |
| $elementName =~ s/^${pfx_AUE}_/${pfx_adt}_/; |
| $eventId =~ s/^${pfx_AUE}_/${pfx_adt}_/; |
| $elementName =~ s/_t$//; |
| |
| print Hfile "\t\t$eventId","_t\t$elementName;\n"; |
| } |
| foreach my $header (sort keys %headers) { |
| if ($outputState[$header]) { |
| *Hfile = $Hfile[$header]; |
| next unless $Hfile[$header]; |
| print Hfile "};\n"; |
| } |
| } |
| foreach my $header (keys %headers) { |
| next unless $Hfile[$header]; |
| *Hfile = $Hfile[$header]; |
| my $adt_event_n = "_${pfx_ADT}_EVENT_H"; |
| if ($header > 0) { |
| $adt_event_n = "_${pfx_ADT}_EVENT_".$header."_H"; |
| } |
| print Hfile <<EOF; |
| |
| |
| #ifndef ${pfx_ADT}_PRIVATE |
| #define ${pfx_ADT}_PRIVATE |
| |
| /* |
| * These interfaces are project private and will change without |
| * notice as needed for the Solaris Audit project. |
| */ |
| |
| extern void adt_get_auid(const adt_session_data_t *, au_id_t *); |
| extern void adt_set_auid(const adt_session_data_t *, const au_id_t); |
| |
| extern void adt_get_mask(const adt_session_data_t *, au_mask_t *); |
| extern void adt_set_mask(const adt_session_data_t *, const au_mask_t *); |
| |
| extern void adt_get_termid(const adt_session_data_t *, au_tid_addr_t *); |
| extern void adt_set_termid(const adt_session_data_t *, |
| const au_tid_addr_t *); |
| |
| extern void adt_get_asid(const adt_session_data_t *, au_asid_t *); |
| extern void adt_set_asid(const adt_session_data_t *, const au_asid_t); |
| extern au_asid_t adt_get_unique_id(au_id_t); |
| extern void adt_load_table(const adt_session_data_t *, adt_translation_t **, |
| void (*preload)(au_event_t, adt_event_data_t *)); |
| |
| extern void ${pfx_adt}_preload(au_event_t, adt_event_data_t *); |
| |
| extern adt_translation_t *${pfx_adt}_xlate_table[]; |
| |
| #endif |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* $adt_event_n */ |
| EOF |
| } |
| closeHeaderFiles(@Hfile); |
| } |
| |
| sub generateTableC { |
| my $event = shift; |
| my $eventId = shift; |
| my $eventType = shift; |
| my $eventHeader = shift; |
| my $omit = shift; |
| |
| my %tokenType = ( |
| # |
| # tokenTypes are the ones that are actually defined |
| # for use in adt.xml audit records |
| # |
| |
| # 'acl' => 'AUT_ACL', # not defined |
| # 'arbitrary' => 'AUT_ARBITRARY', # not defined |
| # 'arg' => 'AUT_ARG', # not defined |
| # 'attr' => 'AUT_ATTR', |
| 'command' => 'AUT_CMD', |
| 'command_alt' => 'ADT_CMD_ALT', # dummy token id |
| # 'date' => 'AUT_TEXT', # not used |
| # 'exec_args' => 'AUT_EXEC_ARGS', # not defined |
| # 'exec_env' => 'AUT_EXEC_ENV', # not defined |
| # 'exit' => 'AUT_EXIT', # not defined |
| 'fmri' => 'AUT_FMRI', |
| # 'groups' => 'AUT_GROUPS', # not defined |
| # 'header' => 'AUT_HEADER', # not defined |
| 'in_peer' => 'ADT_IN_PEER', # dummy token id |
| 'in_remote' => 'ADT_IN_REMOTE', # dummy token id |
| # 'ipc' => 'AUT_IPC', # not defined |
| # 'ipc_perm' => 'AUT_IPC_PERM', # not defined |
| 'iport' => 'AUT_IPORT', |
| 'label' => 'AUT_LABEL', |
| 'newgroups' => 'AUT_NEWGROUPS', |
| # 'opaque' => 'AUT_OPAQUE', # not defined |
| 'path' => 'AUT_PATH', |
| 'path_list' => '-AUT_PATH', # dummy token id |
| 'process' => 'AUT_PROCESS', |
| 'priv_effective' => 'ADT_AUT_PRIV_E', # dummy token id |
| 'priv_limit' => 'ADT_AUT_PRIV_L', # dummy token id |
| 'priv_inherit' => 'ADT_AUT_PRIV_I', # dummy token id |
| 'return' => 'AUT_RETURN', |
| 'secflags' => 'AUT_SECFLAGS', |
| # 'seq' => 'AUT_SEQ', # not defined |
| # 'socket' => 'AUT_SOCKET', # not defined |
| # 'socket-inet' => 'AUT_SOCKET_INET', |
| 'subject' => 'AUT_SUBJECT', |
| 'text' => 'AUT_TEXT', |
| 'tid' => 'AUT_TID', |
| # 'trailer' => 'AUT_TRAILER', # not defined |
| 'uauth' => 'AUT_UAUTH', |
| 'user' => 'AUT_USER', |
| 'zonename' => 'AUT_ZONENAME' |
| ); |
| |
| my @xlateEntryList = (); |
| |
| my $external = $event->getExternal(); |
| my $internal = $event->getInternal(); |
| |
| unless ($external) { |
| print STDERR "No external object captured for event $eventId\n"; |
| return; |
| } |
| if ($eventType) { |
| $nameTranslation{$eventId} = $eventId; |
| } else { |
| $nameTranslation{$eventId} = $external->getInternalName(); |
| } |
| unless ($internal) { |
| print STDERR "No internal object captured for event $eventId\n"; |
| return; |
| } |
| my @entryRef = $internal->getEntries(); |
| my $entryRef; |
| my @tokenOrder = (); |
| my $firstTokenIndex = 0; # djdj not used yet, djdj BUG! |
| # needs to be used by translate table |
| |
| if ($internal->isReorder()) { # prescan the entry list to get the token order |
| my @inputOrder; |
| foreach $entryRef (@entryRef) { |
| my ($intEntry, $entry) = @$entryRef; |
| push (@inputOrder, $intEntry->getAttr('order')); |
| } |
| |
| my $i; # walk down the inputOrder list once |
| my $k = 1; # discover next in line |
| my $l = 0; # who should point to next in line |
| for ($i = 0; $i <= $#inputOrder; $i++) { |
| my $j; |
| for ($j = 0; $j <= $#inputOrder; $j++) { |
| if ($k == $inputOrder[$j]) { |
| if ($k == 1) { |
| $firstTokenIndex = $j; |
| } else { |
| $tokenOrder[$l] = "&(selfReference[$j])"; |
| } |
| $l = $j; |
| last; |
| } |
| } |
| $k++; |
| } |
| $tokenOrder[$l] = 'NULL'; |
| } |
| else { # default order -- input order same as output |
| my $i; |
| my $j; |
| for ($i = 0; $i < $#entryRef; $i++) { |
| my $j = $i + 1; |
| $tokenOrder[$i] = "&(selfReference[$j])"; |
| } |
| $tokenOrder[$#entryRef] = 'NULL'; |
| } |
| |
| my $sequence = 0; |
| foreach $entryRef (@entryRef) { |
| my ($intEntry, $entry) = @$entryRef; |
| my $entryId = $entry->getAttr('id'); |
| |
| my ($extEntry, $unusedEntry, $tokenId) = |
| $external->getEntry($entryId); |
| my $opt = $extEntry->getAttr('opt'); |
| |
| if ($opt eq 'none') { |
| if (defined ($doc->getToken($tokenId))) { |
| if (defined ($tokenType{$tokenId})) { |
| $tokenId = $tokenType{$tokenId}; |
| } |
| else { |
| print STDERR "token id $tokenId not implemented\n"; |
| } |
| } |
| else { |
| print STDERR "token = $tokenId is undefined\n"; |
| $tokenId = 'error'; |
| } |
| my ($xlate, $jni) = |
| formatTableEntry ('', $tokenId, $eventId, '', 0, 0, |
| $tokenOrder[$sequence], 'NULL', '', $omit); |
| push (@xlateEntryList, $xlate); |
| } |
| else { |
| my $dataType = $extEntry->getAttr('type'); |
| $dataType =~ s/\s+//g; # remove blanks (char * => char*) |
| |
| my $enumGroup = ''; |
| if ($dataType =~ /^msg/i) { |
| $enumGroup = $dataType; |
| $enumGroup =~ s/^msg\s*//i; |
| $enumGroup = "${pfx_adt}_" . $enumGroup; |
| } |
| my $required = ($opt eq 'required') ? 1 : 0; |
| my $tsol = 0; |
| my $tokenId = $intEntry->getAttr('token'); |
| my $token; |
| my $tokenName; |
| my $tokenFormat = $intEntry->getAttr('format'); |
| if (defined ($tokenFormat)) { |
| $tokenFormat = "\"$tokenFormat\""; |
| } |
| else { |
| $tokenFormat = 'NULL'; |
| } |
| |
| if (defined ($token = $doc->getToken($tokenId))) { |
| $tsol = (lc $token->getUsage() eq 'tsol') ? 1 : 0; |
| if (defined ($tokenType{$tokenId})) { |
| $tokenName = $tokenType{$tokenId}; |
| } |
| else { |
| print STDERR "token id $tokenId not implemented\n"; |
| } |
| } |
| else { |
| print STDERR |
| "$tokenId is an unimplemented token ($entryId in $eventId)\n"; |
| $tokenName = 'AUT_TEXT'; |
| } |
| my ($xlate, $jni) = |
| formatTableEntry($entryId, $tokenName, $eventId, $dataType, $required, |
| $tsol, $tokenOrder[$sequence], $tokenFormat, |
| $enumGroup, $omit); |
| push (@xlateEntryList, $xlate); |
| } |
| $sequence++; |
| } |
| $xlateEventTable{$eventId} = [\@xlateEntryList, $eventType, $firstTokenIndex, |
| $eventHeader]; |
| } |
| |
| sub formatTableEntry { |
| my ($id, $token, $eventId, $type, $required, $tsol, $sequence, $format, |
| $enumGroup, $omitEntry) = @_; |
| |
| |
| # does this map belong in the xml source? (at least the defaults?) |
| # fill in the default value only if it is other than zero. |
| # base type adt name, default value |
| my %entryDef = ( 'au_asid_t' => ['ADT_UINT32', ''], |
| 'uint_t' => ['ADT_UINT32', ''], |
| 'int' => ['ADT_INT', ''], |
| 'int32_t' => ['ADT_INT32', ''], |
| 'uid_t' => ['ADT_UID', 'AU_NOAUDITID'], |
| 'gid_t' => ['ADT_GID', 'AU_NOAUDITID'], |
| 'uid_t*' => ['ADT_UIDSTAR', ''], |
| 'gid_t*' => ['ADT_GIDSTAR', ''], |
| 'char' => ['ADT_CHAR', ''], |
| 'char*' => ['ADT_CHARSTAR', ''], |
| 'char**' => ['ADT_CHAR2STAR', ''], |
| 'long' => ['ADT_LONG', ''], |
| 'pid_t' => ['ADT_PID', ''], |
| 'priv_set_t*' => ['ADT_PRIVSTAR', ''], |
| 'ulong_t' => ['ADT_ULONG', ''], |
| 'uint16_t', => ['ADT_UINT16', ''], |
| 'uint32_t' => ['ADT_UINT32', ''], |
| 'uint32_t*' => ['ADT_UINT32STAR', ''], |
| 'uint32_t[]' => ['ADT_UINT32ARRAY', ''], |
| 'uint64_t' => ['ADT_UINT64', ''], |
| 'uint64_t*' => ['ADT_UINT64STAR', ''], |
| 'm_label_t*' => ['ADT_MLABELSTAR', ''], |
| 'fd_t' => ['ADT_FD', '-1'], |
| ); |
| my $xlateLabel = $uniLabel.$xlateUniLabelInc; |
| my $xlateLabelInc = 0; |
| my $xlateLine = ''; |
| my @jniLine = (); |
| |
| # the list handling should be a simple loop with a loop of one |
| # falling out naturally. |
| |
| unless ($type =~ /,/) { # if list, then generate sequence of entries |
| my $dataType; |
| my $dataSize; |
| my $xlateLabelRef = ''; |
| |
| my $arraySize = ''; |
| $arraySize = $1 if ($type =~ s/\[(\d+)\]/[]/); |
| |
| my $entryType = ${$entryDef{$type}}[0]; |
| |
| my @xlateType = (); # for adt_xlate.c |
| my $typeCount = 1; |
| |
| if ($entryType) { |
| $dataType = $entryType; |
| $type =~ s/([^*]+)\s*(\*+)/$1 $2/; |
| $type =~ s/\[\]//; |
| $dataSize = "sizeof ($type)"; |
| if ($arraySize) { |
| $dataSize = "$arraySize * " . $dataSize; |
| } |
| $xlateLine = "{{$dataType, $dataSize}}"; |
| push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); |
| } elsif ($type eq '') { |
| $xlateLabelRef = 'NULL'; |
| } elsif ($type =~ /^msg/i) { |
| $type =~ s/^msg//i; |
| $dataType = 'ADT_MSG'; |
| my $dataEnum = 'ADT_LIST_' . uc $type; |
| $xlateLine = "{{$dataType, $dataEnum}}"; |
| push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); |
| } elsif ($type =~ /time_t/i) { |
| $dataType = 'ADT_DATE'; |
| $dataSize = "sizeof (time_t)"; |
| $xlateLine = "{{$dataType, $dataSize}}"; |
| push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); |
| } elsif ($type =~ /termid/i) { |
| $dataType = 'ADT_TERMIDSTAR'; |
| $dataSize = "sizeof (au_tid_addr_t *)"; |
| $xlateLine = "{{$dataType, $dataSize}}"; |
| push (@jniLine, [$id, $dataType, $format, $enumGroup, $required]); |
| } elsif (uc $omitEntry eq 'JNI') { |
| $xlateLabelRef = 'NULL'; |
| } else { |
| print STDERR "$type is not an implemented data type\n"; |
| $xlateLabelRef = 'NULL'; |
| } |
| if ($xlateLine && !($xlateTypeList{$xlateLine})) { |
| $xlateTypeList{$xlateLine} = $xlateLabel; |
| push (@xlateTypeList, "datadef\t$xlateLabel\[1\] =\t$xlateLine;"); |
| $xlateLabelInc = 1; |
| } else { |
| $xlateLabel = $xlateTypeList{$xlateLine}; |
| } |
| $xlateLabelRef = '&' . $xlateLabel . '[0]' |
| unless $xlateLabelRef eq 'NULL'; |
| |
| # "EOL" is where a comma should go unless end of list |
| $xlateLine = "{$token,\t1,\t$xlateLabelRef,\t$sequence,\n" . |
| "\t\t0,\t$required,\t$tsol,\t$format}EOL"; |
| |
| if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$type}}[1]) { |
| my @list = (); |
| if ($xlateDefault{$eventId}) { |
| @list = @{$xlateDefault{$eventId}}; |
| } else { |
| push (@xlateDefaults, $eventId); |
| } |
| push (@list, $id, ${$entryDef{$type}}[1]); |
| $xlateDefault{$eventId} = \@list; |
| } |
| } else { # is a list |
| my @type = split(/,/, $type); |
| my @arraySize = (); |
| my @id = split(/,/, $id); |
| my @jniId = @id; |
| my $dataType; |
| my $typeCount = ($#type + 1); |
| my @xlateType = (); |
| my @default = (); |
| |
| foreach my $dtype (@type) { |
| my $jniId = shift @jniId; |
| my $id = shift @id; |
| my $arraySize = ''; |
| $arraySize = $1 if ($dtype =~ s/\[(\d+)\]/[]/); |
| |
| my $entryType = ${$entryDef{$dtype}}[0]; |
| if ($entryType) { |
| my $type = $dtype; |
| $type =~ s/([^*]+)\s*(\*+)/$1 $2/; |
| $type =~ s/\[\]//; |
| |
| my $sizeString = "sizeof"; |
| $sizeString = "$arraySize * " . $sizeString if $arraySize; |
| push (@xlateType, "\{$entryType, $sizeString ($type)\}"); |
| push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); |
| } elsif ($type =~ /^msg/i) { |
| $type =~ s/^msg//i; |
| $dataType = 'ADT_MSG'; |
| my $dataEnum = 'ADT_LIST_' . uc $type; |
| push (@xlateType, "\{$dataType, $dataEnum\}};"); |
| push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); |
| } elsif ($type =~ /time_t/i) { |
| $dataType = 'ADT_DATE'; |
| push (@xlateType, "\{$entryType, sizeof ($type)\}"); |
| push (@jniLine, [$jniId, $entryType, $format, $enumGroup, $required]); |
| } elsif ($type =~ /termid/i) { |
| $dataType = 'ADT_TERMIDSTAR'; |
| push (@xlateType, "\{$dataType, sizeof (au_tid_addr_t *)\}"); |
| push (@jniLine, [$jniId, $dataType, $format, $enumGroup, $required]); |
| } elsif (uc $omitEntry eq 'JNI') { |
| # nothing to do. |
| } else { |
| print STDERR "$dtype is not an implemented data type\n"; |
| } |
| if (uc $omitEntry ne 'ALWAYS' && ${$entryDef{$dtype}}[1]) { |
| push (@default, $id, ${$entryDef{$dtype}}[1]); |
| } |
| } |
| my $xlateArray = "\[$typeCount\] =\t{" . join(",\n\t\t\t\t", @xlateType) . "};"; |
| |
| unless ($xlateTypeList{$xlateArray}) { |
| $xlateTypeList{$xlateArray} = $xlateLabel; |
| $xlateArray = "datadef\t$xlateLabel" . $xlateArray; |
| push (@xlateTypeList, $xlateArray); |
| $xlateLabelInc = 1; |
| } else { |
| $xlateLabel = $xlateTypeList{$xlateArray}; |
| } |
| $xlateLine = |
| "{$token,\t$typeCount,\t&$xlateLabel\[0\],\t$sequence,\n" . |
| "\t\t0,\t$required,\t$tsol,\t$format}EOL"; |
| if (@default) { |
| my @list = (); |
| if ($xlateDefault{$eventId}) { |
| @list = @{$xlateDefault{$eventId}}; |
| } else { |
| push (@xlateDefaults, $eventId); |
| } |
| push (@list, @default); |
| $xlateDefault{$eventId} = \@list; |
| } |
| } |
| $xlateUniLabelInc++ if $xlateLabelInc; |
| return ($xlateLine, \@jniLine); |
| } |
| |
| sub generateAPIFile { |
| my $event = shift; |
| my $eventId = shift; |
| my $eventType = shift; |
| my $eventHeader = shift; |
| my $idNo = shift; |
| |
| my @entryList = (); |
| |
| my $external = $event->getExternal(); |
| |
| if ($eventType && $debug) { |
| print STDERR "event $eventId is of type $eventType\n"; |
| } |
| |
| return unless $external; |
| |
| my ($extEntry, $entry, $tokenId, $format); |
| while (($extEntry, $entry, $tokenId, $format) = $external->getNextEntry()) { |
| last unless $entry; |
| my $entryId = $entry->getAttr('id'); |
| |
| unless (defined $entryId) { |
| print STDERR "undefined entry id for external $eventId\n"; |
| next; |
| } |
| my $option = $extEntry->getAttr('opt'); |
| next if ($option eq 'none'); |
| |
| if (defined (my $token = $doc->getToken($tokenId))) { |
| $option = 'Trusted Solaris only' |
| if (lc $token->getUsage() eq 'tsol') ? 1 : 0; |
| } |
| $option .= " (format: $format)" if $format; |
| |
| my $dataType = $extEntry->getAttr('type'); |
| unless (defined $dataType) { |
| print STDERR "no type defined for external tag for $eventId\n"; |
| $dataType = "error"; |
| } |
| |
| my $comment = $entry->getContent(); |
| |
| if (($dataType =~ /,/) || ($entryId =~ /,/)) { |
| my @type = split(/\s*,\s*/, $dataType); |
| my @id = split(/\s*,\s*/, $entryId); |
| if ($#type != $#id) { |
| print STDERR |
| "number of data types ($dataType) does not match number of ids ($entryId)", |
| " for event $eventId\n"; |
| if ($#type < $#id) { |
| $#id = $#type; |
| } |
| else { |
| $#type = $#id; |
| } |
| } |
| |
| my $i; |
| my $line = ''; |
| $line = "/* $comment */\n\t" if defined $comment; |
| for ($i = 0; $i <= $#type; $i++) { |
| my ($primitive, $dereference) = |
| ($type[$i] =~ /([^\*]+)\s*(\**)/); |
| $id[$i] .= $1 if ($primitive =~ s/(\[\d+\])//); |
| $line .= "$primitive\t$dereference$id[$i];\t/* $option */"; |
| push (@entryList, $line); |
| $line = ''; |
| } |
| } |
| else { |
| my $line = ''; |
| $line = "/* $comment */\n\t" if defined $comment; |
| if ($dataType =~ /^msg/i) { |
| $dataType =~ s/^msg\s*//i; |
| $line .= "enum ${pfx_adt}_$dataType" . "\t$entryId;\t/* $option */"; |
| } |
| elsif ($dataType =~ /time_t/i) { |
| $line .= "time_t\t$entryId;\t/* $option */"; |
| } |
| else { |
| my ($primitive, $dereference) = |
| ($dataType =~ /([^\*]+)\s*(\**)/); |
| $entryId .= $1 if ($primitive =~ s/(\[\d+\])//); |
| $line .= "$primitive\t$dereference$entryId;\t/* $option */"; |
| } |
| push (@entryList, $line); |
| } |
| } |
| $eventExtra{$eventId} = [$eventHeader, $idNo]; |
| $eventAPI{$eventId} = \@entryList; |
| } |
| |
| sub generateMsgLists { |
| my $textList = shift; |
| |
| my $textName = $textList->getId(); |
| my $header = $textList->getHeader(); |
| my $start = $textList->getMsgStart(); |
| my $public = $textList->getMsgPublic(); |
| my $deprecated = $textList->getDeprecated(); |
| |
| addHeader($header); |
| print "$textName starts at $start\n" if $debug; |
| |
| my $entry; |
| my @entry; |
| while ($entry = $textList->getNextMsg()) { |
| if ($debug) { |
| my ($id, $text) = split(/\s*::\s*/, $entry); |
| print " $id = $text\n"; |
| } |
| unshift (@entry, $entry); |
| } |
| $msg_list{$textName} = |
| [\@entry, [$header, $start, $public, $deprecated]]; |
| } |
| |
| sub addHeader { |
| my $header_index = shift; |
| |
| die "invalid adt_event_N.h index: $header_index\n" |
| unless ($header_index =~ /^\d+$/); |
| |
| $headers{$header_index} = $header_index; |
| } |
| |
| # $header = 0 is a special case; it is for adt_event.h |
| # $header > 0 creates adt_event_N.h, where N = $header |
| |
| sub openHeaderFiles { |
| my $outfile = shift; # path to an adt_event_N.h file |
| |
| my $header; |
| my @Hfile = (); # potentially sparse array of file handles |
| my @HfileName = (); # parallel array to Hfile, file name (not path) |
| foreach $header (sort keys %headers) { |
| my $file = $outfile; |
| if ($header > 0) { |
| $file =~ s/_N/_$header/; |
| } else { |
| $file =~ s/_N//; |
| } |
| unless (open($Hfile[$header], ">$file")) { |
| print STDERR "can't open output ($file): $!\n"; |
| $HfileName[$header] = ''; |
| $Hfile[$header] = ''; |
| } else { |
| my @tmp = split(/\//, $file); |
| $HfileName[$header] = $tmp[$#tmp]; |
| } |
| } |
| return (@Hfile); |
| } |
| |
| sub closeHeaderFiles { |
| my @Hfile = @_; |
| |
| my $header; |
| foreach $header (sort keys %headers) { |
| close $Hfile[$header] if $Hfile[$header]; |
| } |
| } |