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