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