4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * The Secure SunOS audit reduction tool - auditreduce.
29 * Document SM0071 is the primary source of information on auditreduce.
31 * Composed of 4 source modules:
32 * main.c - main driver.
33 * option.c - command line option processing.
34 * process.c - record/file/process functions.
35 * time.c - date/time handling.
37 * Main(), write_header(), audit_stats(), and a_calloc()
38 * are the only functions visible outside this module.
47 #if !defined(TEXT_DOMAIN)
48 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
51 extern void derive_str(time_t, char *);
52 extern int process_options(int, char **);
53 extern int mproc(audit_pcb_t
*);
54 extern void init_tokens(void); /* shared with praudit */
56 static int a_pow(int, int);
57 static void calc_procs(void);
58 static void chld_handler(int);
59 static int close_outfile(void);
60 static void c_close(audit_pcb_t
*, int);
61 static void delete_infiles(void);
62 static void gather_pcb(audit_pcb_t
*, int, int);
63 static void init_options(void);
64 static int init_sig(void);
65 static void int_handler(int);
66 static int mfork(audit_pcb_t
*, int, int, int);
67 static void mcount(int, int);
68 static int open_outfile(void);
69 static void p_close(audit_pcb_t
*);
70 static int rename_outfile(void);
71 static void rm_mem(audit_pcb_t
*);
72 static void rm_outfile(void);
73 static void trim_mem(audit_pcb_t
*);
74 static int write_file_token(time_t);
75 static int write_trailer(void);
80 static int max_sproc
; /* maximum number of subprocesses per process */
81 static int total_procs
; /* number of processes in the process tree */
82 static int total_layers
; /* number of layers in the process tree */
86 * .desc The beginning. Main() calls each of the initialization routines
87 * and then allocates the root pcb. Then it calls mfork() to get
89 * .call main(argc, argv).
90 * .arg argc - number of arguments.
91 * .arg argv - array of pointers to arguments.
92 * .ret 0 - via exit() - no errors detected.
93 * .ret 1 - via exit() - errors detected (messages printed).
96 main(int argc
, char **argv
)
101 /* Internationalization */
102 (void) setlocale(LC_ALL
, "");
103 (void) textdomain(TEXT_DOMAIN
);
105 root_pid
= getpid(); /* know who is root process for error */
106 init_options(); /* initialize options */
107 init_tokens(); /* initialize token processing table */
108 if (init_sig()) /* initialize signals */
110 if (process_options(argc
, argv
))
111 exit(1); /* process command line options */
112 if (open_outfile()) /* setup root process output stream */
114 calc_procs(); /* see how many subprocesses we need */
116 * Allocate the root pcb and set it up.
118 pcb
= (audit_pcb_t
*)a_calloc(1, sizeof (audit_pcb_t
));
119 pcb
->pcb_procno
= root_pid
;
120 pcb
->pcb_flags
|= PF_ROOT
;
121 pcb
->pcb_fpw
= stdout
;
124 * Now start the whole thing rolling.
126 if (mfork(pcb
, pcbnum
, 0, pcbnum
- 1)) {
128 * Error in processing somewhere. A message is already printed.
129 * Display usage statistics and remove the outfile.
131 if (getpid() == root_pid
) {
133 (void) close_outfile();
139 * Clean up afterwards.
140 * Only do outfile cleanup if we are root process.
142 if (getpid() == root_pid
) {
143 if ((ret
= write_trailer()) == 0) { /* write trailer to file */
145 ret
= close_outfile(); /* close the outfile */
148 * If there was an error in cleanup then remove outfile.
155 * And lastly delete the infiles if the user so wishes.
166 * .func mfork - main fork routine.
167 * .desc Create a (sub-)tree of processses if needed, or just do the work
168 * if we have few enough groups to process. This is a recursive routine
169 * which stops recursing when the number of files to process is small
170 * enough. Each call to mfork() is responsible for a range of pcbs
171 * from audit_pcbs[]. This range is designated by the lo and hi
172 * arguments (inclusive). If the number of pcbs is small enough
173 * then we have hit a leaf of the tree and mproc() is called to
174 * do the processing. Otherwise we fork some processes and break
175 * the range of pcbs up amongst them.
176 * .call ret = mfork(pcb, nsp, lo, hi).
177 * .arg pcb - ptr to pcb that is root node of the to-be-created tree.
178 * .arg nsp - number of sub-processes this tree must process.
179 * .arg lo - lower-limit of process number range. Index into audit_pcbs.
180 * .arg hi - higher limit of pcb range. Index into audit_pcbs.
181 * .ret 0 - succesful completion.
182 * .ret -1 - error encountered in processing - message already printed.
185 mfork(audit_pcb_t
*pcb
, int nsp
, int lo
, int hi
)
187 int range
, procno
, i
, tofork
, nnsp
, nrem
;
192 (void) fprintf(stderr
, "mfork: nsp %d %d->%d\n", nsp
, lo
, hi
);
196 * The range of pcb's to process is small enough now. Do the work.
198 if (nsp
<= max_sproc
) {
199 pcb
->pcb_flags
|= PF_LEAF
; /* leaf in process tree */
200 pcb
->pcb_below
= audit_pcbs
; /* proc pcbs from audit_pcbs */
201 gather_pcb(pcb
, lo
, hi
);
202 trim_mem(pcb
); /* trim allocated memory */
203 return (mproc(pcb
)); /* do the work */
206 * Too many pcb's for one process - must fork.
207 * Try to balance the tree as it grows and make it short and fat.
208 * The thing to minimize is the number of times a record passes
213 * Fork less than the maximum number of processes.
215 if (nsp
<= max_sproc
* (max_sproc
- 1)) {
216 tofork
= nsp
/ max_sproc
;
218 tofork
++; /* how many to fork */
221 * Fork the maximum number of processes.
224 tofork
= max_sproc
; /* how many to fork */
227 * Allocate the nodes below us in the process tree.
229 pcb
->pcb_below
= (audit_pcb_t
*)
230 a_calloc(tofork
, sizeof (*pcb
));
231 nnsp
= nsp
/ tofork
; /* # of pcbs per forked process */
232 nrem
= nsp
% tofork
; /* remainder to spread around */
234 * Loop to fork all of the subs. Open a pipe for each.
235 * If there are any errors in pipes, forks, or getting streams
236 * for the pipes then quit altogether.
238 for (i
= 0; i
< tofork
; i
++) {
239 pcbn
= &pcb
->pcb_below
[i
];
243 "auditreduce: couldn't get a pipe"));
247 * Convert descriptors to streams.
249 if ((pcbn
->pcb_fpr
= fdopen(fildes
[0], "r")) == NULL
) {
250 perror(gettext("auditreduce: couldn't get read stream for pipe"));
253 if ((pcbn
->pcb_fpw
= fdopen(fildes
[1], "w")) == NULL
) {
254 perror(gettext("auditreduce: couldn't get write stream for pipe"));
257 if ((procno
= fork()) == -1) {
258 perror(gettext("auditreduce: fork failed"));
262 * Calculate the range of pcbs from audit_pcbs [] this
263 * branch of the tree will be responsible for.
265 range
= (nrem
> 0) ? nnsp
+ 1 : nnsp
;
270 pcbn
->pcb_procno
= getpid();
271 c_close(pcb
, i
); /* close unused streams */
273 * Continue resolving this branch.
275 return (mfork(pcbn
, range
, lo
, lo
+ range
- 1));
279 pcbn
->pcb_procno
= i
;
280 /* allocate buffer to hold record */
281 pcbn
->pcb_rec
= (char *)a_calloc(1,
283 pcbn
->pcb_size
= AUDITBUFSIZE
;
284 p_close(pcbn
); /* close unused streams */
291 * Done forking all of the subs.
293 gather_pcb(pcb
, 0, tofork
- 1);
294 trim_mem(pcb
); /* free unused memory */
301 * .func trim_mem - trim memory usage.
302 * .desc Free un-needed allocated memory.
303 * .call trim_mem(pcb).
304 * .arg pcb - ptr to pcb for current process.
308 trim_mem(audit_pcb_t
*pcb
)
314 * For the root don't free anything. We need to save audit_pcbs[]
315 * in case we are deleting the infiles at the end.
317 if (pcb
->pcb_flags
& PF_ROOT
)
320 * For a leaf save its part of audit_pcbs[] and then remove it all.
322 if (pcb
->pcb_flags
& PF_LEAF
) {
323 count
= pcb
->pcb_count
;
324 size
= sizeof (audit_pcb_t
);
325 /* allocate a new buffer to hold the pcbs */
326 pcb
->pcb_below
= (audit_pcb_t
*)a_calloc(count
, size
);
327 /* save this pcb's portion */
328 (void) memcpy((void *) pcb
->pcb_below
,
329 (void *) &audit_pcbs
[pcb
->pcb_lo
], count
* size
);
331 gather_pcb(pcb
, 0, count
- 1);
334 * If this is an intermediate node then just remove it all.
343 * .func rm_mem - remove memory.
344 * .desc Remove unused memory associated with audit_pcbs[]. For each
345 * pcb in audit_pcbs[] free the record buffer and all of
346 * the fcbs. Then free audit_pcbs[].
347 * .call rm_mem(pcbr).
348 * .arg pcbr - ptr to pcb of current process.
352 rm_mem(audit_pcb_t
*pcbr
)
356 audit_fcb_t
*fcb
, *fcbn
;
358 for (i
= 0; i
< pcbsize
; i
++) {
360 * Don't free the record buffer and fcbs for the pcbs this
363 if (pcbr
->pcb_flags
& PF_LEAF
) {
364 if (pcbr
->pcb_lo
<= i
|| i
<= pcbr
->pcb_hi
)
367 pcb
= &audit_pcbs
[i
];
369 for (fcb
= pcb
->pcb_first
; fcb
!= NULL
; /* */) {
370 fcbn
= fcb
->fcb_next
;
375 free((char *)audit_pcbs
);
380 * .func c_close - close unused streams.
381 * .desc This is called for each child process just after being born.
382 * The child closes the read stream for the pipe to its parent.
383 * It also closes the read streams for the other children that
384 * have been born before it. If any closes fail a warning message
385 * is printed, but processing continues.
386 * .call ret = c_close(pcb, i).
387 * .arg pcb - ptr to the child's parent pcb.
388 * .arg i - iteration # of child in forking loop.
392 c_close(audit_pcb_t
*pcb
, int i
)
398 * Do all pcbs in parent's group up to and including us
400 for (j
= 0; j
<= i
; j
++) {
401 pcbt
= &pcb
->pcb_below
[j
];
402 if (fclose(pcbt
->pcb_fpr
) == EOF
) {
404 perror(gettext("auditreduce: initial close on pipe failed"));
407 * Free the buffer allocated to hold incoming records.
417 * .func p_close - close unused streams for parent.
418 * .desc Called by the parent right after forking a child.
419 * Closes the write stream on the pipe to the child since
420 * we will never use it.
421 * .call p_close(pcbn),
422 * .arg pcbn - ptr to pcb.
426 p_close(audit_pcb_t
*pcbn
)
428 if (fclose(pcbn
->pcb_fpw
) == EOF
) {
430 perror(gettext("auditreduce: close for write pipe failed"));
436 * .func audit_stats - print statistics.
437 * .desc Print usage statistics for the user if the run fails.
438 * Tells them how many files they had and how many groups this
439 * totalled. Also tell them how many layers and processes the
441 * .call audit_stats().
450 if (getrlimit(RLIMIT_NOFILE
, &rl
) != -1)
451 (void) fprintf(stderr
,
452 gettext("%s The system allows %d files per process.\n"),
454 (void) fprintf(stderr
, gettext(
455 "%s There were %d file(s) %d file group(s) %d process(es) %d layer(s).\n"),
456 ar
, filenum
, pcbnum
, total_procs
, total_layers
);
461 * .func gather_pcb - gather pcbs.
462 * .desc Gather together the range of the sub-processes that we are
463 * responsible for. For a pcb that controls processes this is all
464 * of the sub-processes that it forks. For a pcb that controls
465 * files this is the the range of pcbs from audit_pcbs[].
466 * .call gather_pcb(pcb, lo, hi).
467 * .arg pcb - ptr to pcb.
468 * .arg lo - lo index into pcb_below.
469 * .arg hi - hi index into pcb_below.
473 gather_pcb(audit_pcb_t
*pcb
, int lo
, int hi
)
477 pcb
->pcb_count
= hi
- lo
+ 1;
482 * .func calc_procs - calculate process parameters.
483 * .desc Calculate the current run's paramters regarding how many
484 * processes will have to be forked (maybe none).
485 * 5 is subtracted from maxfiles_proc to allow for stdin, stdout,
486 * stderr, and the pipe to a parent process. The outfile
487 * in the root process is assigned to stdout. The unused half of each
488 * pipe is closed, to allow for more connections, but we still
489 * have to have the 5th spot because in order to get the pipe
490 * we need 2 descriptors up front.
491 * .call calc_procs().
502 if (getrlimit(RLIMIT_NOFILE
, &rl
) == -1) {
503 perror("auditreduce: getrlimit");
507 maxfiles_proc
= rl
.rlim_cur
;
509 max_sproc
= maxfiles_proc
- 5; /* max subprocesses per process */
512 * Calculate how many layers the process tree has.
515 for (/* */; /* */; /* */) {
516 val
= a_pow(max_sproc
, total_layers
);
522 * Count how many processes are in the process tree.
527 (void) fprintf(stderr
,
528 "pcbnum %d filenum %d mfp %d msp %d ly %d tot %d\n\n",
529 pcbnum
, filenum
, maxfiles_proc
, max_sproc
,
530 total_layers
, total_procs
);
536 a_pow(int base
, int exp
)
545 for (i
= 0; i
< (exp
- 1); i
++)
553 * .func mcount - main count.
554 * .desc Go through the motions of building the process tree just
555 * to count how many processes there are. Don't really
556 * build anything. Answer is in global var total_procs.
557 * .call mcount(nsp, lo).
558 * .arg nsp - number of subs for this tree branch.
559 * .arg lo - lo side of range of subs.
563 mcount(int nsp
, int lo
)
565 int range
, i
, tofork
, nnsp
, nrem
;
567 total_procs
++; /* count another process created */
569 if (nsp
> max_sproc
) {
570 if (nsp
<= max_sproc
* (max_sproc
- 1)) {
571 tofork
= nsp
/ max_sproc
;
579 for (i
= 0; i
< tofork
; i
++) {
580 range
= (nrem
> 0) ? nnsp
+ 1 : nnsp
;
590 * .func delete_infiles - delete the input files.
591 * .desc If the user asked us to (via 'D' flag) then unlink the input files.
592 * .call ret = delete_infiles().
603 for (i
= 0; i
< pcbsize
; i
++) {
604 pcb
= &audit_pcbs
[i
];
605 fcb
= pcb
->pcb_dfirst
;
606 while (fcb
!= NULL
) {
608 * Only delete a file if it was succesfully processed.
609 * If there were any read errors or bad records
610 * then don't delete it.
611 * There may still be unprocessed records in it.
613 if (fcb
->fcb_flags
& FF_DELETE
) {
614 if (unlink(fcb
->fcb_file
)) {
616 (void) sprintf(errbuf
, gettext(
617 "%s delete on %s failed"),
630 * .func rm_outfile - remove the outfile.
631 * .desc Remove the file we are writing the records to. We do this if
632 * processing failed and we are quitting before finishing.
633 * Update - don't actually remove the outfile, but generate
634 * a warning about its possible heathen nature.
635 * .call ret = rm_outfile().
644 if (unlink(f_outtemp
) == -1) {
645 (void) sprintf(errbuf
,
646 gettext("%s delete on %s failed"),
652 (void) fprintf(stderr
,
653 gettext("%s Warning: Incomplete audit file may have been generated - %s\n"),
655 (f_outfile
== NULL
) ? gettext("standard output") : f_outfile
);
661 * .func close_outfile - close the outfile.
662 * .desc Close the file we are writing records to.
663 * .call ret = close_outfile().
665 * .ret 0 - close was succesful.
666 * .ret -1 - close failed.
671 if (fclose(stdout
) == EOF
) {
672 (void) sprintf(errbuf
, gettext("%s close on %s failed"),
673 ar
, f_outfile
? f_outfile
: "standard output");
677 (void) fsync(fileno(stdout
));
678 return (rename_outfile());
683 * .func write_header - write audit file header.
684 * .desc Write an audit file header to the output stream. The time in the
685 * header is the time of the first record written to the stream. This
686 * routine is called by the process handling the root node of the
687 * process tree just before it writes the first record to the output
689 * .ret 0 - succesful write.
690 * .ret -1 - failed write - message printed.
695 return (write_file_token(f_start
));
700 write_file_token(time_t when
)
702 adr_t adr
; /* adr ptr */
703 struct timeval tv
; /* time now */
704 char for_adr
[16]; /* plenty of room */
706 char token_id
= AUT_OTHER_FILE64
;
708 char token_id
= AUT_OTHER_FILE32
;
715 adr_start(&adr
, for_adr
);
716 adr_char(&adr
, &token_id
, 1);
718 adr_int64(&adr
, (int64_t *)&tv
, 2);
720 adr_int32(&adr
, (int32_t *)&tv
, 2);
722 adr_short(&adr
, &i
, 1);
723 adr_char(&adr
, &c
, 1);
725 if (fwrite(for_adr
, sizeof (char), adr_count(&adr
), stdout
) !=
727 if (when
== f_start
) {
728 (void) sprintf(errbuf
,
729 gettext("%s error writing header to %s. "),
731 f_outfile
? f_outfile
:
732 gettext("standard output"));
734 (void) sprintf(errbuf
,
735 gettext("%s error writing trailer to %s. "),
737 f_outfile
? f_outfile
:
738 gettext("standard output"));
748 * .func write_trailer - write audit file trailer.
749 * .desc Write an audit file trailer to the output stream. The finish
750 * time for the trailer is the time of the last record written
752 * .ret 0 - succesful write.
753 * .ret -1 - failed write - message printed.
758 return (write_file_token(f_end
));
763 * .func rename_outfile - rename the outfile.
764 * .desc If the user used the -O flag they only gave us the suffix name
765 * for the outfile. We have to add the time stamps to put the filename
766 * in the proper audit file name format. The start time will be the time
767 * of the first record in the file and the end time will be the time of
768 * the last record in the file.
769 * .ret 0 - rename succesful.
770 * .ret -1 - rename failed - message printed.
775 char f_newfile
[MAXFILELEN
];
776 char buf1
[15], buf2
[15];
777 char *f_file
, *f_nfile
, *f_time
, *f_name
;
779 if (f_outfile
!= NULL
) {
781 * Get string representations of start and end times.
783 derive_str(f_start
, buf1
);
784 derive_str(f_end
, buf2
);
786 f_nfile
= f_time
= f_newfile
; /* working copy */
787 f_file
= f_name
= f_outfile
; /* their version */
789 if (*f_file
== '/') { /* look for filename */
790 f_time
= f_nfile
+ 1;
793 *f_nfile
++ = *f_file
++; /* make copy of their version */
796 /* start time goes first */
797 (void) strcat(f_newfile
, buf1
);
798 (void) strcat(f_newfile
, ".");
799 /* then the finish time */
800 (void) strcat(f_newfile
, buf2
);
801 (void) strcat(f_newfile
, ".");
802 /* and the name they gave us */
803 (void) strcat(f_newfile
, f_name
);
806 (void) fprintf(stderr
, "rename_outfile: <%s> --> <%s>\n",
807 f_outfile
, f_newfile
);
811 if (rename(f_outtemp
, f_newfile
) == -1) {
812 (void) fprintf(stderr
,
813 "%s rename of %s to %s failed.\n",
814 ar
, f_outtemp
, f_newfile
);
817 f_outfile
= f_newfile
;
819 if (rename(f_outtemp
, f_outfile
) == -1) {
820 (void) fprintf(stderr
,
821 gettext("%s rename of %s to %s failed.\n"),
822 ar
, f_outtemp
, f_outfile
);
832 * .func open_outfile - open the outfile.
833 * .desc Open the outfile specified by the -O option. Assign it to the
834 * the standard output. Get a unique temporary name to use so we
835 * don't clobber an existing file.
836 * .ret 0 - no errors detected.
837 * .ret -1 - errors in processing (message already printed).
844 if (f_outfile
!= NULL
) {
845 f_outtemp
= (char *)a_calloc(1, strlen(f_outfile
) + 8);
846 (void) strcpy(f_outtemp
, f_outfile
);
847 (void) strcat(f_outtemp
, "XXXXXX");
848 if ((tmpfd
= mkstemp(f_outtemp
)) == -1) {
849 (void) sprintf(errbuf
,
850 gettext("%s couldn't create temporary file"), ar
);
854 (void) fflush(stdout
);
855 if (tmpfd
!= fileno(stdout
)) {
856 if ((dup2(tmpfd
, fileno(stdout
))) == -1) {
857 (void) sprintf(errbuf
,
858 gettext("%s can't assign %s to the "
859 "standard output"), ar
, f_outfile
);
871 * .func init_options - initialize the options.
872 * .desc Give initial and/or default values to some options.
873 * .call init_options();
884 * Get current time for general use.
886 if (gettimeofday(&tp
, &tpz
) == -1)
887 perror(gettext("auditreduce: initial getttimeofday failed"));
889 time_now
= tp
.tv_sec
; /* save for general use */
890 f_start
= 0; /* first record time default */
891 f_end
= time_now
; /* last record time default */
892 m_after
= 0; /* Jan 1, 1970 00:00:00 */
895 * Setup initial size of audit_pcbs[].
897 pcbsize
= PCB_INITSIZE
; /* initial size of file-holding pcb's */
899 audit_pcbs
= (audit_pcb_t
*)a_calloc(pcbsize
, sizeof (audit_pcb_t
));
901 /* description of 'current' error */
902 error_str
= gettext("initial error");
908 * .func a_calloc - audit calloc.
909 * .desc Calloc with check for failure. This is called by all of the
910 * places that want memory.
911 * .call ptr = a_calloc(nelem, size).
912 * .arg nelem - number of elements to allocate.
913 * .arg size - size of each element.
914 * .ret ptr - ptr to allocated and zeroed memory.
915 * .ret never - if calloc fails then we never return.
918 a_calloc(int nelem
, size_t size
)
922 if ((ptr
= calloc((unsigned)nelem
, size
)) == NULL
) {
923 perror(gettext("auditreduce: memory allocation failed"));
931 * .func init_sig - initial signal catching.
934 * Setup the signal catcher to catch the SIGCHLD signal plus
935 * "environmental" signals -- keyboard plus other externally
936 * generated signals such as out of file space or cpu time. If a
937 * child exits with either a non-zero exit code or was killed by
938 * a signal to it then we will also exit with a non-zero exit
939 * code. In this way abnormal conditions can be passed up to the
940 * root process and the entire run be halted. Also catch the int
941 * and quit signals. Remove the output file since it is in an
942 * inconsistent state.
943 * .call ret = init_sig().
945 * .ret 0 - no errors detected.
946 * .ret -1 - signal failed (message printed).
951 if (signal(SIGCHLD
, chld_handler
) == SIG_ERR
) {
952 perror(gettext("auditreduce: SIGCHLD signal failed"));
956 if (signal(SIGHUP
, int_handler
) == SIG_ERR
) {
957 perror(gettext("auditreduce: SIGHUP signal failed"));
960 if (signal(SIGINT
, int_handler
) == SIG_ERR
) {
961 perror(gettext("auditreduce: SIGINT signal failed"));
964 if (signal(SIGQUIT
, int_handler
) == SIG_ERR
) {
965 perror(gettext("auditreduce: SIGQUIT signal failed"));
968 if (signal(SIGABRT
, int_handler
) == SIG_ERR
) {
969 perror(gettext("auditreduce: SIGABRT signal failed"));
972 if (signal(SIGTERM
, int_handler
) == SIG_ERR
) {
973 perror(gettext("auditreduce: SIGTERM signal failed"));
976 if (signal(SIGPWR
, int_handler
) == SIG_ERR
) {
977 perror(gettext("auditreduce: SIGPWR signal failed"));
980 if (signal(SIGXCPU
, int_handler
) == SIG_ERR
) {
981 perror(gettext("auditreduce: SIGXCPU signal failed"));
984 if (signal(SIGXFSZ
, int_handler
) == SIG_ERR
) {
985 perror(gettext("auditreduce: SIGXFSZ signal failed"));
988 if (signal(SIGSEGV
, int_handler
) == SIG_ERR
) {
989 perror(gettext("auditreduce: SIGSEGV signal failed"));
998 * .func chld_handler - handle child signals.
999 * .desc Catch the SIGCHLD signals. Remove the root process
1000 * output file because it is in an inconsistent state.
1001 * Print a message giving the signal number and/or return code
1002 * of the child who caused the signal.
1007 chld_handler(int sig
)
1013 * Get pid and reasons for cause of event.
1015 pid
= wait(&status
);
1019 * If child received a signal or exited with a non-zero
1020 * exit status then print message and exit
1022 if ((WHIBYTE(status
) == 0 && WLOBYTE(status
) != 0) ||
1023 (WHIBYTE(status
) != 0 && WLOBYTE(status
) == 0)) {
1024 (void) fprintf(stderr
,
1025 gettext("%s abnormal child termination - "), ar
);
1027 if (WHIBYTE(status
) == 0 && WLOBYTE(status
) != 0) {
1028 psignal(WLOBYTE(status
), "signal");
1029 if (WCOREDUMP(status
))
1030 (void) fprintf(stderr
,
1031 gettext("core dumped\n"));
1034 if (WHIBYTE(status
) != 0 && WLOBYTE(status
) == 0)
1035 (void) fprintf(stderr
, gettext(
1036 "return code %d\n"),
1040 * Get rid of outfile - it is suspect.
1042 if (f_outfile
!= NULL
) {
1043 (void) close_outfile();
1047 * Give statistical info that may be useful.
1058 * .func int_handler - handle quit/int signals.
1059 * .desc Catch the keyboard and other environmental signals.
1060 * Remove the root process output file because it is in
1061 * an inconsistent state.
1066 int_handler(int sig
)
1068 if (getpid() == root_pid
) {
1069 (void) close_outfile();
1074 * For a child process don't give an error exit or the
1075 * parent process will catch it with the chld_handler and
1076 * try to erase the outfile again.