#!/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 (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
#
# 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";
our $errExit = 0; # Exit code set for fatal errors
# set to 3 for all errors.
# Process command-line options
our ($opt_d, $opt_e, $opt_i, $opt_o);
if (!getopts('de:i:o:') || $#ARGV != 0) {
die $usage;
}
my $outdir = defined ($opt_o) ? $opt_o : ".";
my $pfx_adt = defined ($opt_i) ? lc($opt_i) : "adt";
my $pfx_ADT = uc($pfx_adt);
my $pfx_AUE = defined ($opt_e) ? 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;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $cYear = 1900 + $year;
$debug = $appDebug;
my $genNotice = "
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 (c) 2007, $cYear, Oracle and/or its affiliates. All rights reserved.
DO NOT EDIT. This file is auto generated by the Solaris Audit
system from $filename.
";
# 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 $errExit;
sub printTableC {
my $file = shift;
unless (open(Cfile, ">$file")) {
print STDERR "can't open output file ($file): $!\n";
$errExit = 3;
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";
$errExit = 3;
}
}
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";
$errExit = 3;
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;
unless ($idNo) {
print STDERR "missing id number for $eventId\n";
$errExit = 3;
}
$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";
$errExit = 3;
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',
# 'atom' => 'AUT_XATOM', # not defined
'attr' => 'AUT_ATTR64',
# 'colormap' => 'AUT_XCOLORMAP', # not defined
'command' => 'AUT_CMD',
'command_alt' => 'ADT_CMD_ALT', # dummy token id
# 'cursor' => 'AUT_XCURSOR', # not defined
# 'date' => 'AUT_TEXT', # not used
# 'exec_args' => 'AUT_EXEC_ARGS', # not defined
# 'exec_env' => 'AUT_EXEC_ENV', # not defined
# 'exit' => 'AUT_EXIT', # not defined
# 'font' => 'AUT_XFONT', # not defined
'fmri' => 'AUT_FMRI',
# 'gc' => 'AUT_XGC', # not defined
# '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
# 'pixmap' => 'AUT_XPIXMAP', # not defined
'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',
# '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',
'xclient' => 'AUT_XCLIENT',
# 'xobj' => 'AUT_XOBJ', # not defined
# 'xproto' => 'AUT_XPROTO', # not defined
'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";
$errExit = 3;
return;
}
if ($eventType) {
$nameTranslation{$eventId} = $eventId;
} else {
$nameTranslation{$eventId} = $external->getInternalName();
}
unless ($internal) {
print STDERR "No internal object captured for event $eventId\n";
$errExit = 3;
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";
$errExit = 3;
}
}
else {
print STDERR "token = $tokenId is undefined\n";
$tokenId = 'error';
$errExit = 3;
}
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";
$errExit = 3;
}
}
else {
print STDERR
"$tokenId is an unimplemented token ($entryId in $eventId)\n";
$tokenName = 'AUT_TEXT';
$errExit = 3;
}
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) = @_;
$omitEntry = defined ($omitEntry) ? $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'],
'adt_stat_t*' => ['ADT_STATSTAR', ''],
);
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';
$errExit = 3;
}
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";
$errExit = 3;
}
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";
$errExit = 3;
}
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";
$errExit = 3;
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";
$errExit = 3;
}
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";
$errExit = 3;
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] = '';
$errExit = 3;
} 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];
}
}