10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*8889STon.Nguyen@Sun.COM * Common Development and Distribution License (the "License").
6*8889STon.Nguyen@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*8889STon.Nguyen@Sun.COM
220Sstevel@tonic-gate /*
23*8889STon.Nguyen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * The Secure SunOS audit reduction tool - auditreduce.
290Sstevel@tonic-gate * Document SM0071 is the primary source of information on auditreduce.
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * Composed of 4 source modules:
320Sstevel@tonic-gate * main.c - main driver.
330Sstevel@tonic-gate * option.c - command line option processing.
340Sstevel@tonic-gate * process.c - record/file/process functions.
350Sstevel@tonic-gate * time.c - date/time handling.
360Sstevel@tonic-gate *
370Sstevel@tonic-gate * Main(), write_header(), audit_stats(), and a_calloc()
380Sstevel@tonic-gate * are the only functions visible outside this module.
390Sstevel@tonic-gate */
400Sstevel@tonic-gate
410Sstevel@tonic-gate #include <siginfo.h>
420Sstevel@tonic-gate #include <locale.h>
430Sstevel@tonic-gate #include <libintl.h>
440Sstevel@tonic-gate #include "auditr.h"
450Sstevel@tonic-gate #include "auditrd.h"
460Sstevel@tonic-gate
470Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
480Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD"
490Sstevel@tonic-gate #endif
500Sstevel@tonic-gate
510Sstevel@tonic-gate extern void derive_str(time_t, char *);
520Sstevel@tonic-gate extern int process_options(int, char **);
530Sstevel@tonic-gate extern int mproc(audit_pcb_t *);
540Sstevel@tonic-gate extern void init_tokens(void); /* shared with praudit */
550Sstevel@tonic-gate
560Sstevel@tonic-gate static int a_pow(int, int);
570Sstevel@tonic-gate static void calc_procs(void);
580Sstevel@tonic-gate static void chld_handler(int);
590Sstevel@tonic-gate static int close_outfile(void);
600Sstevel@tonic-gate static void c_close(audit_pcb_t *, int);
610Sstevel@tonic-gate static void delete_infiles(void);
620Sstevel@tonic-gate static void gather_pcb(audit_pcb_t *, int, int);
630Sstevel@tonic-gate static void init_options(void);
640Sstevel@tonic-gate static int init_sig(void);
650Sstevel@tonic-gate static void int_handler(int);
660Sstevel@tonic-gate static int mfork(audit_pcb_t *, int, int, int);
670Sstevel@tonic-gate static void mcount(int, int);
680Sstevel@tonic-gate static int open_outfile(void);
690Sstevel@tonic-gate static void p_close(audit_pcb_t *);
700Sstevel@tonic-gate static int rename_outfile(void);
710Sstevel@tonic-gate static void rm_mem(audit_pcb_t *);
720Sstevel@tonic-gate static void rm_outfile(void);
730Sstevel@tonic-gate static void trim_mem(audit_pcb_t *);
740Sstevel@tonic-gate static int write_file_token(time_t);
750Sstevel@tonic-gate static int write_trailer(void);
760Sstevel@tonic-gate
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate * File globals.
790Sstevel@tonic-gate */
800Sstevel@tonic-gate static int max_sproc; /* maximum number of subprocesses per process */
810Sstevel@tonic-gate static int total_procs; /* number of processes in the process tree */
820Sstevel@tonic-gate static int total_layers; /* number of layers in the process tree */
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * .func main - main.
860Sstevel@tonic-gate * .desc The beginning. Main() calls each of the initialization routines
870Sstevel@tonic-gate * and then allocates the root pcb. Then it calls mfork() to get
880Sstevel@tonic-gate * the work done.
890Sstevel@tonic-gate * .call main(argc, argv).
900Sstevel@tonic-gate * .arg argc - number of arguments.
910Sstevel@tonic-gate * .arg argv - array of pointers to arguments.
920Sstevel@tonic-gate * .ret 0 - via exit() - no errors detected.
930Sstevel@tonic-gate * .ret 1 - via exit() - errors detected (messages printed).
940Sstevel@tonic-gate */
950Sstevel@tonic-gate int
main(int argc,char ** argv)960Sstevel@tonic-gate main(int argc, char **argv)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate int ret;
990Sstevel@tonic-gate audit_pcb_t *pcb;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /* Internationalization */
1020Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1030Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate root_pid = getpid(); /* know who is root process for error */
1060Sstevel@tonic-gate init_options(); /* initialize options */
1070Sstevel@tonic-gate init_tokens(); /* initialize token processing table */
1080Sstevel@tonic-gate if (init_sig()) /* initialize signals */
1090Sstevel@tonic-gate exit(1);
1100Sstevel@tonic-gate if (process_options(argc, argv))
1110Sstevel@tonic-gate exit(1); /* process command line options */
1120Sstevel@tonic-gate if (open_outfile()) /* setup root process output stream */
1130Sstevel@tonic-gate exit(1);
1140Sstevel@tonic-gate calc_procs(); /* see how many subprocesses we need */
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * Allocate the root pcb and set it up.
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate pcb = (audit_pcb_t *)a_calloc(1, sizeof (audit_pcb_t));
1190Sstevel@tonic-gate pcb->pcb_procno = root_pid;
1200Sstevel@tonic-gate pcb->pcb_flags |= PF_ROOT;
1210Sstevel@tonic-gate pcb->pcb_fpw = stdout;
1220Sstevel@tonic-gate pcb->pcb_time = -1;
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * Now start the whole thing rolling.
1250Sstevel@tonic-gate */
1260Sstevel@tonic-gate if (mfork(pcb, pcbnum, 0, pcbnum - 1)) {
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate * Error in processing somewhere. A message is already printed.
1290Sstevel@tonic-gate * Display usage statistics and remove the outfile.
1300Sstevel@tonic-gate */
1310Sstevel@tonic-gate if (getpid() == root_pid) {
1320Sstevel@tonic-gate audit_stats();
1330Sstevel@tonic-gate (void) close_outfile();
1340Sstevel@tonic-gate rm_outfile();
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate exit(1);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * Clean up afterwards.
1400Sstevel@tonic-gate * Only do outfile cleanup if we are root process.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate if (getpid() == root_pid) {
1430Sstevel@tonic-gate if ((ret = write_trailer()) == 0) { /* write trailer to file */
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate ret = close_outfile(); /* close the outfile */
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * If there was an error in cleanup then remove outfile.
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate if (ret) {
1510Sstevel@tonic-gate rm_outfile();
1520Sstevel@tonic-gate exit(1);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * And lastly delete the infiles if the user so wishes.
1560Sstevel@tonic-gate */
1570Sstevel@tonic-gate if (f_delete)
1580Sstevel@tonic-gate delete_infiles();
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate return (0);
1610Sstevel@tonic-gate /*NOTREACHED*/
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * .func mfork - main fork routine.
1670Sstevel@tonic-gate * .desc Create a (sub-)tree of processses if needed, or just do the work
1680Sstevel@tonic-gate * if we have few enough groups to process. This is a recursive routine
1690Sstevel@tonic-gate * which stops recursing when the number of files to process is small
1700Sstevel@tonic-gate * enough. Each call to mfork() is responsible for a range of pcbs
1710Sstevel@tonic-gate * from audit_pcbs[]. This range is designated by the lo and hi
1720Sstevel@tonic-gate * arguments (inclusive). If the number of pcbs is small enough
1730Sstevel@tonic-gate * then we have hit a leaf of the tree and mproc() is called to
1740Sstevel@tonic-gate * do the processing. Otherwise we fork some processes and break
1750Sstevel@tonic-gate * the range of pcbs up amongst them.
1760Sstevel@tonic-gate * .call ret = mfork(pcb, nsp, lo, hi).
1770Sstevel@tonic-gate * .arg pcb - ptr to pcb that is root node of the to-be-created tree.
1780Sstevel@tonic-gate * .arg nsp - number of sub-processes this tree must process.
1790Sstevel@tonic-gate * .arg lo - lower-limit of process number range. Index into audit_pcbs.
1800Sstevel@tonic-gate * .arg hi - higher limit of pcb range. Index into audit_pcbs.
1810Sstevel@tonic-gate * .ret 0 - succesful completion.
1820Sstevel@tonic-gate * .ret -1 - error encountered in processing - message already printed.
1830Sstevel@tonic-gate */
1840Sstevel@tonic-gate static int
mfork(audit_pcb_t * pcb,int nsp,int lo,int hi)1850Sstevel@tonic-gate mfork(audit_pcb_t *pcb, int nsp, int lo, int hi)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate int range, procno, i, tofork, nnsp, nrem;
1880Sstevel@tonic-gate int fildes[2];
1890Sstevel@tonic-gate audit_pcb_t *pcbn;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate #if AUDIT_PROC_TRACE
1920Sstevel@tonic-gate (void) fprintf(stderr, "mfork: nsp %d %d->%d\n", nsp, lo, hi);
1930Sstevel@tonic-gate #endif
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * The range of pcb's to process is small enough now. Do the work.
1970Sstevel@tonic-gate */
1980Sstevel@tonic-gate if (nsp <= max_sproc) {
1990Sstevel@tonic-gate pcb->pcb_flags |= PF_LEAF; /* leaf in process tree */
2000Sstevel@tonic-gate pcb->pcb_below = audit_pcbs; /* proc pcbs from audit_pcbs */
2010Sstevel@tonic-gate gather_pcb(pcb, lo, hi);
2020Sstevel@tonic-gate trim_mem(pcb); /* trim allocated memory */
2030Sstevel@tonic-gate return (mproc(pcb)); /* do the work */
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Too many pcb's for one process - must fork.
2070Sstevel@tonic-gate * Try to balance the tree as it grows and make it short and fat.
2080Sstevel@tonic-gate * The thing to minimize is the number of times a record passes
2090Sstevel@tonic-gate * through a pipe.
2100Sstevel@tonic-gate */
2110Sstevel@tonic-gate else {
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate * Fork less than the maximum number of processes.
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate if (nsp <= max_sproc * (max_sproc - 1)) {
2160Sstevel@tonic-gate tofork = nsp / max_sproc;
2170Sstevel@tonic-gate if (nsp % max_sproc)
2180Sstevel@tonic-gate tofork++; /* how many to fork */
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate * Fork the maximum number of processes.
2220Sstevel@tonic-gate */
2230Sstevel@tonic-gate else {
2240Sstevel@tonic-gate tofork = max_sproc; /* how many to fork */
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate * Allocate the nodes below us in the process tree.
2280Sstevel@tonic-gate */
2290Sstevel@tonic-gate pcb->pcb_below = (audit_pcb_t *)
2300Sstevel@tonic-gate a_calloc(tofork, sizeof (*pcb));
2310Sstevel@tonic-gate nnsp = nsp / tofork; /* # of pcbs per forked process */
2320Sstevel@tonic-gate nrem = nsp % tofork; /* remainder to spread around */
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate * Loop to fork all of the subs. Open a pipe for each.
2350Sstevel@tonic-gate * If there are any errors in pipes, forks, or getting streams
2360Sstevel@tonic-gate * for the pipes then quit altogether.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate for (i = 0; i < tofork; i++) {
2390Sstevel@tonic-gate pcbn = &pcb->pcb_below[i];
2400Sstevel@tonic-gate pcbn->pcb_time = -1;
2410Sstevel@tonic-gate if (pipe(fildes)) {
2420Sstevel@tonic-gate perror(gettext(
2430Sstevel@tonic-gate "auditreduce: couldn't get a pipe"));
2440Sstevel@tonic-gate return (-1);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * Convert descriptors to streams.
2480Sstevel@tonic-gate */
2490Sstevel@tonic-gate if ((pcbn->pcb_fpr = fdopen(fildes[0], "r")) == NULL) {
2500Sstevel@tonic-gate perror(gettext("auditreduce: couldn't get read stream for pipe"));
2510Sstevel@tonic-gate return (-1);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate if ((pcbn->pcb_fpw = fdopen(fildes[1], "w")) == NULL) {
2540Sstevel@tonic-gate perror(gettext("auditreduce: couldn't get write stream for pipe"));
2550Sstevel@tonic-gate return (-1);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate if ((procno = fork()) == -1) {
2580Sstevel@tonic-gate perror(gettext("auditreduce: fork failed"));
2590Sstevel@tonic-gate return (-1);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate /*
2620Sstevel@tonic-gate * Calculate the range of pcbs from audit_pcbs [] this
2630Sstevel@tonic-gate * branch of the tree will be responsible for.
2640Sstevel@tonic-gate */
2650Sstevel@tonic-gate range = (nrem > 0) ? nnsp + 1 : nnsp;
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * Child route.
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate if (procno == 0) {
2700Sstevel@tonic-gate pcbn->pcb_procno = getpid();
2710Sstevel@tonic-gate c_close(pcb, i); /* close unused streams */
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Continue resolving this branch.
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate return (mfork(pcbn, range, lo, lo + range - 1));
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate /* Parent route. */
2780Sstevel@tonic-gate else {
2790Sstevel@tonic-gate pcbn->pcb_procno = i;
2800Sstevel@tonic-gate /* allocate buffer to hold record */
2810Sstevel@tonic-gate pcbn->pcb_rec = (char *)a_calloc(1,
2820Sstevel@tonic-gate AUDITBUFSIZE);
2830Sstevel@tonic-gate pcbn->pcb_size = AUDITBUFSIZE;
2840Sstevel@tonic-gate p_close(pcbn); /* close unused streams */
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate nrem--;
2870Sstevel@tonic-gate lo += range;
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate * Done forking all of the subs.
2920Sstevel@tonic-gate */
2930Sstevel@tonic-gate gather_pcb(pcb, 0, tofork - 1);
2940Sstevel@tonic-gate trim_mem(pcb); /* free unused memory */
2950Sstevel@tonic-gate return (mproc(pcb));
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate /*
3010Sstevel@tonic-gate * .func trim_mem - trim memory usage.
3020Sstevel@tonic-gate * .desc Free un-needed allocated memory.
3030Sstevel@tonic-gate * .call trim_mem(pcb).
3040Sstevel@tonic-gate * .arg pcb - ptr to pcb for current process.
3050Sstevel@tonic-gate * .ret void.
3060Sstevel@tonic-gate */
3070Sstevel@tonic-gate static void
trim_mem(audit_pcb_t * pcb)3080Sstevel@tonic-gate trim_mem(audit_pcb_t *pcb)
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate int count;
3110Sstevel@tonic-gate size_t size;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate * For the root don't free anything. We need to save audit_pcbs[]
3150Sstevel@tonic-gate * in case we are deleting the infiles at the end.
3160Sstevel@tonic-gate */
3170Sstevel@tonic-gate if (pcb->pcb_flags & PF_ROOT)
3180Sstevel@tonic-gate return;
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate * For a leaf save its part of audit_pcbs[] and then remove it all.
3210Sstevel@tonic-gate */
3220Sstevel@tonic-gate if (pcb->pcb_flags & PF_LEAF) {
3230Sstevel@tonic-gate count = pcb->pcb_count;
3240Sstevel@tonic-gate size = sizeof (audit_pcb_t);
3250Sstevel@tonic-gate /* allocate a new buffer to hold the pcbs */
3260Sstevel@tonic-gate pcb->pcb_below = (audit_pcb_t *)a_calloc(count, size);
3270Sstevel@tonic-gate /* save this pcb's portion */
3280Sstevel@tonic-gate (void) memcpy((void *) pcb->pcb_below,
3290Sstevel@tonic-gate (void *) &audit_pcbs[pcb->pcb_lo], count * size);
3300Sstevel@tonic-gate rm_mem(pcb);
3310Sstevel@tonic-gate gather_pcb(pcb, 0, count - 1);
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * If this is an intermediate node then just remove it all.
3350Sstevel@tonic-gate */
3360Sstevel@tonic-gate else {
3370Sstevel@tonic-gate rm_mem(pcb);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate /*
3430Sstevel@tonic-gate * .func rm_mem - remove memory.
3440Sstevel@tonic-gate * .desc Remove unused memory associated with audit_pcbs[]. For each
3450Sstevel@tonic-gate * pcb in audit_pcbs[] free the record buffer and all of
3460Sstevel@tonic-gate * the fcbs. Then free audit_pcbs[].
3470Sstevel@tonic-gate * .call rm_mem(pcbr).
3480Sstevel@tonic-gate * .arg pcbr - ptr to pcb of current process.
3490Sstevel@tonic-gate * .ret void.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate static void
rm_mem(audit_pcb_t * pcbr)3520Sstevel@tonic-gate rm_mem(audit_pcb_t *pcbr)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate int i;
3550Sstevel@tonic-gate audit_pcb_t *pcb;
3560Sstevel@tonic-gate audit_fcb_t *fcb, *fcbn;
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate for (i = 0; i < pcbsize; i++) {
3590Sstevel@tonic-gate /*
3600Sstevel@tonic-gate * Don't free the record buffer and fcbs for the pcbs this
3610Sstevel@tonic-gate * process is using.
3620Sstevel@tonic-gate */
3630Sstevel@tonic-gate if (pcbr->pcb_flags & PF_LEAF) {
3640Sstevel@tonic-gate if (pcbr->pcb_lo <= i || i <= pcbr->pcb_hi)
3650Sstevel@tonic-gate continue;
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate pcb = &audit_pcbs[i];
3680Sstevel@tonic-gate free(pcb->pcb_rec);
3690Sstevel@tonic-gate for (fcb = pcb->pcb_first; fcb != NULL; /* */) {
3700Sstevel@tonic-gate fcbn = fcb->fcb_next;
3710Sstevel@tonic-gate free((char *)fcb);
3720Sstevel@tonic-gate fcb = fcbn;
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate free((char *)audit_pcbs);
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate * .func c_close - close unused streams.
3810Sstevel@tonic-gate * .desc This is called for each child process just after being born.
3820Sstevel@tonic-gate * The child closes the read stream for the pipe to its parent.
3830Sstevel@tonic-gate * It also closes the read streams for the other children that
3840Sstevel@tonic-gate * have been born before it. If any closes fail a warning message
3850Sstevel@tonic-gate * is printed, but processing continues.
3860Sstevel@tonic-gate * .call ret = c_close(pcb, i).
3870Sstevel@tonic-gate * .arg pcb - ptr to the child's parent pcb.
3880Sstevel@tonic-gate * .arg i - iteration # of child in forking loop.
3890Sstevel@tonic-gate * .ret void.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate static void
c_close(audit_pcb_t * pcb,int i)3920Sstevel@tonic-gate c_close(audit_pcb_t *pcb, int i)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate int j;
3950Sstevel@tonic-gate audit_pcb_t *pcbt;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * Do all pcbs in parent's group up to and including us
3990Sstevel@tonic-gate */
4000Sstevel@tonic-gate for (j = 0; j <= i; j++) {
4010Sstevel@tonic-gate pcbt = &pcb->pcb_below[j];
4020Sstevel@tonic-gate if (fclose(pcbt->pcb_fpr) == EOF) {
4030Sstevel@tonic-gate if (!f_quiet)
4040Sstevel@tonic-gate perror(gettext("auditreduce: initial close on pipe failed"));
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate * Free the buffer allocated to hold incoming records.
4080Sstevel@tonic-gate */
4090Sstevel@tonic-gate if (i != j) {
4100Sstevel@tonic-gate free(pcbt->pcb_rec);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate * .func p_close - close unused streams for parent.
4180Sstevel@tonic-gate * .desc Called by the parent right after forking a child.
4190Sstevel@tonic-gate * Closes the write stream on the pipe to the child since
4200Sstevel@tonic-gate * we will never use it.
4210Sstevel@tonic-gate * .call p_close(pcbn),
4220Sstevel@tonic-gate * .arg pcbn - ptr to pcb.
4230Sstevel@tonic-gate * .ret void.
4240Sstevel@tonic-gate */
4250Sstevel@tonic-gate static void
p_close(audit_pcb_t * pcbn)4260Sstevel@tonic-gate p_close(audit_pcb_t *pcbn)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate if (fclose(pcbn->pcb_fpw) == EOF) {
4290Sstevel@tonic-gate if (!f_quiet)
4300Sstevel@tonic-gate perror(gettext("auditreduce: close for write pipe failed"));
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * .func audit_stats - print statistics.
4370Sstevel@tonic-gate * .desc Print usage statistics for the user if the run fails.
4380Sstevel@tonic-gate * Tells them how many files they had and how many groups this
4390Sstevel@tonic-gate * totalled. Also tell them how many layers and processes the
4400Sstevel@tonic-gate * process tree had.
4410Sstevel@tonic-gate * .call audit_stats().
4420Sstevel@tonic-gate * .arg none.
4430Sstevel@tonic-gate * .ret void.
4440Sstevel@tonic-gate */
4450Sstevel@tonic-gate void
audit_stats(void)4460Sstevel@tonic-gate audit_stats(void)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate struct rlimit rl;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) != -1)
4510Sstevel@tonic-gate (void) fprintf(stderr,
4520Sstevel@tonic-gate gettext("%s The system allows %d files per process.\n"),
4530Sstevel@tonic-gate ar, rl.rlim_cur);
4540Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4550Sstevel@tonic-gate "%s There were %d file(s) %d file group(s) %d process(es) %d layer(s).\n"),
4560Sstevel@tonic-gate ar, filenum, pcbnum, total_procs, total_layers);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate * .func gather_pcb - gather pcbs.
4620Sstevel@tonic-gate * .desc Gather together the range of the sub-processes that we are
4630Sstevel@tonic-gate * responsible for. For a pcb that controls processes this is all
4640Sstevel@tonic-gate * of the sub-processes that it forks. For a pcb that controls
4650Sstevel@tonic-gate * files this is the the range of pcbs from audit_pcbs[].
4660Sstevel@tonic-gate * .call gather_pcb(pcb, lo, hi).
4670Sstevel@tonic-gate * .arg pcb - ptr to pcb.
4680Sstevel@tonic-gate * .arg lo - lo index into pcb_below.
4690Sstevel@tonic-gate * .arg hi - hi index into pcb_below.
4700Sstevel@tonic-gate * .ret void.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate static void
gather_pcb(audit_pcb_t * pcb,int lo,int hi)4730Sstevel@tonic-gate gather_pcb(audit_pcb_t *pcb, int lo, int hi)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate pcb->pcb_lo = lo;
4760Sstevel@tonic-gate pcb->pcb_hi = hi;
4770Sstevel@tonic-gate pcb->pcb_count = hi - lo + 1;
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate * .func calc_procs - calculate process parameters.
4830Sstevel@tonic-gate * .desc Calculate the current run's paramters regarding how many
4840Sstevel@tonic-gate * processes will have to be forked (maybe none).
4850Sstevel@tonic-gate * 5 is subtracted from maxfiles_proc to allow for stdin, stdout,
4860Sstevel@tonic-gate * stderr, and the pipe to a parent process. The outfile
4870Sstevel@tonic-gate * in the root process is assigned to stdout. The unused half of each
4880Sstevel@tonic-gate * pipe is closed, to allow for more connections, but we still
4890Sstevel@tonic-gate * have to have the 5th spot because in order to get the pipe
4900Sstevel@tonic-gate * we need 2 descriptors up front.
4910Sstevel@tonic-gate * .call calc_procs().
4920Sstevel@tonic-gate * .arg none.
4930Sstevel@tonic-gate * .ret void.
4940Sstevel@tonic-gate */
4950Sstevel@tonic-gate static void
calc_procs(void)4960Sstevel@tonic-gate calc_procs(void)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate int val;
4990Sstevel@tonic-gate int maxfiles_proc;
5000Sstevel@tonic-gate struct rlimit rl;
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
5030Sstevel@tonic-gate perror("auditreduce: getrlimit");
5040Sstevel@tonic-gate exit(1);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate maxfiles_proc = rl.rlim_cur;
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate max_sproc = maxfiles_proc - 5; /* max subprocesses per process */
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate * Calculate how many layers the process tree has.
5130Sstevel@tonic-gate */
5140Sstevel@tonic-gate total_layers = 1;
5150Sstevel@tonic-gate for (/* */; /* */; /* */) {
5160Sstevel@tonic-gate val = a_pow(max_sproc, total_layers);
5170Sstevel@tonic-gate if (val > pcbnum)
5180Sstevel@tonic-gate break;
5190Sstevel@tonic-gate total_layers++;
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate * Count how many processes are in the process tree.
5230Sstevel@tonic-gate */
5240Sstevel@tonic-gate mcount(pcbnum, 0);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate #if AUDIT_PROC_TRACE
5270Sstevel@tonic-gate (void) fprintf(stderr,
5280Sstevel@tonic-gate "pcbnum %d filenum %d mfp %d msp %d ly %d tot %d\n\n",
5290Sstevel@tonic-gate pcbnum, filenum, maxfiles_proc, max_sproc,
5300Sstevel@tonic-gate total_layers, total_procs);
5310Sstevel@tonic-gate #endif
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate static int
a_pow(int base,int exp)5360Sstevel@tonic-gate a_pow(int base, int exp)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate int i;
5390Sstevel@tonic-gate int answer;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate if (exp == 0) {
5420Sstevel@tonic-gate answer = 1;
5430Sstevel@tonic-gate } else {
5440Sstevel@tonic-gate answer = base;
5450Sstevel@tonic-gate for (i = 0; i < (exp - 1); i++)
5460Sstevel@tonic-gate answer *= base;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate return (answer);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate * .func mcount - main count.
5540Sstevel@tonic-gate * .desc Go through the motions of building the process tree just
5550Sstevel@tonic-gate * to count how many processes there are. Don't really
5560Sstevel@tonic-gate * build anything. Answer is in global var total_procs.
5570Sstevel@tonic-gate * .call mcount(nsp, lo).
5580Sstevel@tonic-gate * .arg nsp - number of subs for this tree branch.
5590Sstevel@tonic-gate * .arg lo - lo side of range of subs.
5600Sstevel@tonic-gate * .ret void.
5610Sstevel@tonic-gate */
5620Sstevel@tonic-gate static void
mcount(int nsp,int lo)5630Sstevel@tonic-gate mcount(int nsp, int lo)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate int range, i, tofork, nnsp, nrem;
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate total_procs++; /* count another process created */
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate if (nsp > max_sproc) {
5700Sstevel@tonic-gate if (nsp <= max_sproc * (max_sproc - 1)) {
5710Sstevel@tonic-gate tofork = nsp / max_sproc;
5720Sstevel@tonic-gate if (nsp % max_sproc)
5730Sstevel@tonic-gate tofork++;
5740Sstevel@tonic-gate } else {
5750Sstevel@tonic-gate tofork = max_sproc;
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate nnsp = nsp / tofork;
5780Sstevel@tonic-gate nrem = nsp % tofork;
5790Sstevel@tonic-gate for (i = 0; i < tofork; i++) {
5800Sstevel@tonic-gate range = (nrem > 0) ? nnsp + 1 : nnsp;
5810Sstevel@tonic-gate mcount(range, lo);
5820Sstevel@tonic-gate nrem--;
5830Sstevel@tonic-gate lo += range;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate * .func delete_infiles - delete the input files.
5910Sstevel@tonic-gate * .desc If the user asked us to (via 'D' flag) then unlink the input files.
5920Sstevel@tonic-gate * .call ret = delete_infiles().
5930Sstevel@tonic-gate * .arg none.
5940Sstevel@tonic-gate * .ret void.
5950Sstevel@tonic-gate */
5960Sstevel@tonic-gate static void
delete_infiles(void)5970Sstevel@tonic-gate delete_infiles(void)
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate int i;
6000Sstevel@tonic-gate audit_pcb_t *pcb;
6010Sstevel@tonic-gate audit_fcb_t *fcb;
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate for (i = 0; i < pcbsize; i++) {
6040Sstevel@tonic-gate pcb = &audit_pcbs[i];
6050Sstevel@tonic-gate fcb = pcb->pcb_dfirst;
6060Sstevel@tonic-gate while (fcb != NULL) {
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate * Only delete a file if it was succesfully processed.
6090Sstevel@tonic-gate * If there were any read errors or bad records
6100Sstevel@tonic-gate * then don't delete it.
6110Sstevel@tonic-gate * There may still be unprocessed records in it.
6120Sstevel@tonic-gate */
6130Sstevel@tonic-gate if (fcb->fcb_flags & FF_DELETE) {
6140Sstevel@tonic-gate if (unlink(fcb->fcb_file)) {
6150Sstevel@tonic-gate if (f_verbose) {
6160Sstevel@tonic-gate (void) sprintf(errbuf, gettext(
6170Sstevel@tonic-gate "%s delete on %s failed"),
6180Sstevel@tonic-gate ar, fcb->fcb_file);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate perror(errbuf);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate fcb = fcb->fcb_next;
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate * .func rm_outfile - remove the outfile.
6310Sstevel@tonic-gate * .desc Remove the file we are writing the records to. We do this if
6320Sstevel@tonic-gate * processing failed and we are quitting before finishing.
6330Sstevel@tonic-gate * Update - don't actually remove the outfile, but generate
6340Sstevel@tonic-gate * a warning about its possible heathen nature.
6350Sstevel@tonic-gate * .call ret = rm_outfile().
6360Sstevel@tonic-gate * .arg none.
6370Sstevel@tonic-gate * .ret void.
6380Sstevel@tonic-gate */
6390Sstevel@tonic-gate static void
rm_outfile(void)6400Sstevel@tonic-gate rm_outfile(void)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate #if 0
6430Sstevel@tonic-gate if (f_outfile) {
6440Sstevel@tonic-gate if (unlink(f_outtemp) == -1) {
6450Sstevel@tonic-gate (void) sprintf(errbuf,
6460Sstevel@tonic-gate gettext("%s delete on %s failed"),
6470Sstevel@tonic-gate ar, f_outtemp);
6480Sstevel@tonic-gate perror(errbuf);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate #else
6520Sstevel@tonic-gate (void) fprintf(stderr,
6530Sstevel@tonic-gate gettext("%s Warning: Incomplete audit file may have been generated - %s\n"),
6540Sstevel@tonic-gate ar,
6550Sstevel@tonic-gate (f_outfile == NULL) ? gettext("standard output") : f_outfile);
6560Sstevel@tonic-gate #endif
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * .func close_outfile - close the outfile.
6620Sstevel@tonic-gate * .desc Close the file we are writing records to.
6630Sstevel@tonic-gate * .call ret = close_outfile().
6640Sstevel@tonic-gate * .arg none.
6650Sstevel@tonic-gate * .ret 0 - close was succesful.
6660Sstevel@tonic-gate * .ret -1 - close failed.
6670Sstevel@tonic-gate */
6680Sstevel@tonic-gate static int
close_outfile(void)6690Sstevel@tonic-gate close_outfile(void)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate if (fclose(stdout) == EOF) {
6720Sstevel@tonic-gate (void) sprintf(errbuf, gettext("%s close on %s failed"),
6730Sstevel@tonic-gate ar, f_outfile ? f_outfile : "standard output");
6740Sstevel@tonic-gate perror(errbuf);
6750Sstevel@tonic-gate return (-1);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate (void) fsync(fileno(stdout));
6780Sstevel@tonic-gate return (rename_outfile());
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate /*
6830Sstevel@tonic-gate * .func write_header - write audit file header.
6840Sstevel@tonic-gate * .desc Write an audit file header to the output stream. The time in the
6850Sstevel@tonic-gate * header is the time of the first record written to the stream. This
6860Sstevel@tonic-gate * routine is called by the process handling the root node of the
6870Sstevel@tonic-gate * process tree just before it writes the first record to the output
6880Sstevel@tonic-gate * stream.
6890Sstevel@tonic-gate * .ret 0 - succesful write.
6900Sstevel@tonic-gate * .ret -1 - failed write - message printed.
6910Sstevel@tonic-gate */
6920Sstevel@tonic-gate int
write_header(void)6930Sstevel@tonic-gate write_header(void)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate return (write_file_token(f_start));
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate static int
write_file_token(time_t when)7000Sstevel@tonic-gate write_file_token(time_t when)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate adr_t adr; /* adr ptr */
7030Sstevel@tonic-gate struct timeval tv; /* time now */
7040Sstevel@tonic-gate char for_adr[16]; /* plenty of room */
7050Sstevel@tonic-gate #ifdef _LP64
7060Sstevel@tonic-gate char token_id = AUT_OTHER_FILE64;
7070Sstevel@tonic-gate #else
7080Sstevel@tonic-gate char token_id = AUT_OTHER_FILE32;
7090Sstevel@tonic-gate #endif
7100Sstevel@tonic-gate short i = 1;
7110Sstevel@tonic-gate char c = '\0';
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate tv.tv_sec = when;
7140Sstevel@tonic-gate tv.tv_usec = 0;
7150Sstevel@tonic-gate adr_start(&adr, for_adr);
7160Sstevel@tonic-gate adr_char(&adr, &token_id, 1);
7170Sstevel@tonic-gate #ifdef _LP64
7180Sstevel@tonic-gate adr_int64(&adr, (int64_t *)&tv, 2);
7190Sstevel@tonic-gate #else
7200Sstevel@tonic-gate adr_int32(&adr, (int32_t *)&tv, 2);
7210Sstevel@tonic-gate #endif
7220Sstevel@tonic-gate adr_short(&adr, &i, 1);
7230Sstevel@tonic-gate adr_char(&adr, &c, 1);
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate if (fwrite(for_adr, sizeof (char), adr_count(&adr), stdout) !=
7260Sstevel@tonic-gate adr_count(&adr)) {
7270Sstevel@tonic-gate if (when == f_start) {
7280Sstevel@tonic-gate (void) sprintf(errbuf,
7290Sstevel@tonic-gate gettext("%s error writing header to %s. "),
7300Sstevel@tonic-gate ar,
7310Sstevel@tonic-gate f_outfile ? f_outfile :
7320Sstevel@tonic-gate gettext("standard output"));
7330Sstevel@tonic-gate } else {
7340Sstevel@tonic-gate (void) sprintf(errbuf,
7350Sstevel@tonic-gate gettext("%s error writing trailer to %s. "),
7360Sstevel@tonic-gate ar,
7370Sstevel@tonic-gate f_outfile ? f_outfile :
7380Sstevel@tonic-gate gettext("standard output"));
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate perror(errbuf);
7410Sstevel@tonic-gate return (-1);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate return (0);
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate * .func write_trailer - write audit file trailer.
7490Sstevel@tonic-gate * .desc Write an audit file trailer to the output stream. The finish
7500Sstevel@tonic-gate * time for the trailer is the time of the last record written
7510Sstevel@tonic-gate * to the stream.
7520Sstevel@tonic-gate * .ret 0 - succesful write.
7530Sstevel@tonic-gate * .ret -1 - failed write - message printed.
7540Sstevel@tonic-gate */
7550Sstevel@tonic-gate static int
write_trailer(void)7560Sstevel@tonic-gate write_trailer(void)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate return (write_file_token(f_end));
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate * .func rename_outfile - rename the outfile.
7640Sstevel@tonic-gate * .desc If the user used the -O flag they only gave us the suffix name
7650Sstevel@tonic-gate * for the outfile. We have to add the time stamps to put the filename
7660Sstevel@tonic-gate * in the proper audit file name format. The start time will be the time
7670Sstevel@tonic-gate * of the first record in the file and the end time will be the time of
7680Sstevel@tonic-gate * the last record in the file.
7690Sstevel@tonic-gate * .ret 0 - rename succesful.
7700Sstevel@tonic-gate * .ret -1 - rename failed - message printed.
7710Sstevel@tonic-gate */
7720Sstevel@tonic-gate static int
rename_outfile(void)7730Sstevel@tonic-gate rename_outfile(void)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate char f_newfile[MAXFILELEN];
7760Sstevel@tonic-gate char buf1[15], buf2[15];
7770Sstevel@tonic-gate char *f_file, *f_nfile, *f_time, *f_name;
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate if (f_outfile != NULL) {
7800Sstevel@tonic-gate /*
7810Sstevel@tonic-gate * Get string representations of start and end times.
7820Sstevel@tonic-gate */
7830Sstevel@tonic-gate derive_str(f_start, buf1);
7840Sstevel@tonic-gate derive_str(f_end, buf2);
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate f_nfile = f_time = f_newfile; /* working copy */
7870Sstevel@tonic-gate f_file = f_name = f_outfile; /* their version */
7880Sstevel@tonic-gate while (*f_file) {
7890Sstevel@tonic-gate if (*f_file == '/') { /* look for filename */
7900Sstevel@tonic-gate f_time = f_nfile + 1;
7910Sstevel@tonic-gate f_name = f_file + 1;
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate *f_nfile++ = *f_file++; /* make copy of their version */
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate *f_time = '\0';
7960Sstevel@tonic-gate /* start time goes first */
7970Sstevel@tonic-gate (void) strcat(f_newfile, buf1);
7980Sstevel@tonic-gate (void) strcat(f_newfile, ".");
7990Sstevel@tonic-gate /* then the finish time */
8000Sstevel@tonic-gate (void) strcat(f_newfile, buf2);
8010Sstevel@tonic-gate (void) strcat(f_newfile, ".");
8020Sstevel@tonic-gate /* and the name they gave us */
8030Sstevel@tonic-gate (void) strcat(f_newfile, f_name);
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate #if AUDIT_FILE
8060Sstevel@tonic-gate (void) fprintf(stderr, "rename_outfile: <%s> --> <%s>\n",
8070Sstevel@tonic-gate f_outfile, f_newfile);
8080Sstevel@tonic-gate #endif
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate #if AUDIT_RENAME
8110Sstevel@tonic-gate if (rename(f_outtemp, f_newfile) == -1) {
8120Sstevel@tonic-gate (void) fprintf(stderr,
8130Sstevel@tonic-gate "%s rename of %s to %s failed.\n",
8140Sstevel@tonic-gate ar, f_outtemp, f_newfile);
8150Sstevel@tonic-gate return (-1);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate f_outfile = f_newfile;
8180Sstevel@tonic-gate #else
8190Sstevel@tonic-gate if (rename(f_outtemp, f_outfile) == -1) {
8200Sstevel@tonic-gate (void) fprintf(stderr,
8210Sstevel@tonic-gate gettext("%s rename of %s to %s failed.\n"),
8220Sstevel@tonic-gate ar, f_outtemp, f_outfile);
8230Sstevel@tonic-gate return (-1);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate #endif
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate return (0);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate /*
8320Sstevel@tonic-gate * .func open_outfile - open the outfile.
8330Sstevel@tonic-gate * .desc Open the outfile specified by the -O option. Assign it to the
8340Sstevel@tonic-gate * the standard output. Get a unique temporary name to use so we
8350Sstevel@tonic-gate * don't clobber an existing file.
8360Sstevel@tonic-gate * .ret 0 - no errors detected.
8370Sstevel@tonic-gate * .ret -1 - errors in processing (message already printed).
8380Sstevel@tonic-gate */
8390Sstevel@tonic-gate static int
open_outfile(void)8400Sstevel@tonic-gate open_outfile(void)
8410Sstevel@tonic-gate {
8420Sstevel@tonic-gate int tmpfd = -1;
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate if (f_outfile != NULL) {
8450Sstevel@tonic-gate f_outtemp = (char *)a_calloc(1, strlen(f_outfile) + 8);
8460Sstevel@tonic-gate (void) strcpy(f_outtemp, f_outfile);
8470Sstevel@tonic-gate (void) strcat(f_outtemp, "XXXXXX");
8480Sstevel@tonic-gate if ((tmpfd = mkstemp(f_outtemp)) == -1) {
8490Sstevel@tonic-gate (void) sprintf(errbuf,
8500Sstevel@tonic-gate gettext("%s couldn't create temporary file"), ar);
8510Sstevel@tonic-gate perror(errbuf);
8520Sstevel@tonic-gate return (-1);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate (void) fflush(stdout);
8550Sstevel@tonic-gate if (tmpfd != fileno(stdout)) {
8560Sstevel@tonic-gate if ((dup2(tmpfd, fileno(stdout))) == -1) {
8570Sstevel@tonic-gate (void) sprintf(errbuf,
8580Sstevel@tonic-gate gettext("%s can't assign %s to the "
8590Sstevel@tonic-gate "standard output"), ar, f_outfile);
8600Sstevel@tonic-gate perror(errbuf);
8610Sstevel@tonic-gate return (-1);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate (void) close(tmpfd);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate return (0);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate /*
8710Sstevel@tonic-gate * .func init_options - initialize the options.
8720Sstevel@tonic-gate * .desc Give initial and/or default values to some options.
8730Sstevel@tonic-gate * .call init_options();
8740Sstevel@tonic-gate * .arg none.
8750Sstevel@tonic-gate * .ret void.
8760Sstevel@tonic-gate */
8770Sstevel@tonic-gate static void
init_options(void)8780Sstevel@tonic-gate init_options(void)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate struct timeval tp;
8810Sstevel@tonic-gate struct timezone tpz;
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate /*
8840Sstevel@tonic-gate * Get current time for general use.
8850Sstevel@tonic-gate */
8860Sstevel@tonic-gate if (gettimeofday(&tp, &tpz) == -1)
8870Sstevel@tonic-gate perror(gettext("auditreduce: initial getttimeofday failed"));
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate time_now = tp.tv_sec; /* save for general use */
8900Sstevel@tonic-gate f_start = 0; /* first record time default */
8910Sstevel@tonic-gate f_end = time_now; /* last record time default */
8920Sstevel@tonic-gate m_after = 0; /* Jan 1, 1970 00:00:00 */
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate * Setup initial size of audit_pcbs[].
8960Sstevel@tonic-gate */
8970Sstevel@tonic-gate pcbsize = PCB_INITSIZE; /* initial size of file-holding pcb's */
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate audit_pcbs = (audit_pcb_t *)a_calloc(pcbsize, sizeof (audit_pcb_t));
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate /* description of 'current' error */
9020Sstevel@tonic-gate error_str = gettext("initial error");
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate * .func a_calloc - audit calloc.
9090Sstevel@tonic-gate * .desc Calloc with check for failure. This is called by all of the
9100Sstevel@tonic-gate * places that want memory.
9110Sstevel@tonic-gate * .call ptr = a_calloc(nelem, size).
9120Sstevel@tonic-gate * .arg nelem - number of elements to allocate.
9130Sstevel@tonic-gate * .arg size - size of each element.
9140Sstevel@tonic-gate * .ret ptr - ptr to allocated and zeroed memory.
9150Sstevel@tonic-gate * .ret never - if calloc fails then we never return.
9160Sstevel@tonic-gate */
9170Sstevel@tonic-gate void *
a_calloc(int nelem,size_t size)9180Sstevel@tonic-gate a_calloc(int nelem, size_t size)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate void *ptr;
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate if ((ptr = calloc((unsigned)nelem, size)) == NULL) {
9230Sstevel@tonic-gate perror(gettext("auditreduce: memory allocation failed"));
9240Sstevel@tonic-gate exit(1);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate return (ptr);
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate * .func init_sig - initial signal catching.
9320Sstevel@tonic-gate *
9330Sstevel@tonic-gate * .desc
9340Sstevel@tonic-gate * Setup the signal catcher to catch the SIGCHLD signal plus
9350Sstevel@tonic-gate * "environmental" signals -- keyboard plus other externally
9360Sstevel@tonic-gate * generated signals such as out of file space or cpu time. If a
9370Sstevel@tonic-gate * child exits with either a non-zero exit code or was killed by
9380Sstevel@tonic-gate * a signal to it then we will also exit with a non-zero exit
9390Sstevel@tonic-gate * code. In this way abnormal conditions can be passed up to the
9400Sstevel@tonic-gate * root process and the entire run be halted. Also catch the int
9410Sstevel@tonic-gate * and quit signals. Remove the output file since it is in an
9420Sstevel@tonic-gate * inconsistent state.
9430Sstevel@tonic-gate * .call ret = init_sig().
9440Sstevel@tonic-gate * .arg none.
9450Sstevel@tonic-gate * .ret 0 - no errors detected.
9460Sstevel@tonic-gate * .ret -1 - signal failed (message printed).
9470Sstevel@tonic-gate */
9480Sstevel@tonic-gate static int
init_sig(void)9490Sstevel@tonic-gate init_sig(void)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate if (signal(SIGCHLD, chld_handler) == SIG_ERR) {
9520Sstevel@tonic-gate perror(gettext("auditreduce: SIGCHLD signal failed"));
9530Sstevel@tonic-gate return (-1);
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate if (signal(SIGHUP, int_handler) == SIG_ERR) {
9570Sstevel@tonic-gate perror(gettext("auditreduce: SIGHUP signal failed"));
9580Sstevel@tonic-gate return (-1);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate if (signal(SIGINT, int_handler) == SIG_ERR) {
9610Sstevel@tonic-gate perror(gettext("auditreduce: SIGINT signal failed"));
9620Sstevel@tonic-gate return (-1);
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate if (signal(SIGQUIT, int_handler) == SIG_ERR) {
9650Sstevel@tonic-gate perror(gettext("auditreduce: SIGQUIT signal failed"));
9660Sstevel@tonic-gate return (-1);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate if (signal(SIGABRT, int_handler) == SIG_ERR) {
9690Sstevel@tonic-gate perror(gettext("auditreduce: SIGABRT signal failed"));
9700Sstevel@tonic-gate return (-1);
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate if (signal(SIGTERM, int_handler) == SIG_ERR) {
9730Sstevel@tonic-gate perror(gettext("auditreduce: SIGTERM signal failed"));
9740Sstevel@tonic-gate return (-1);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate if (signal(SIGPWR, int_handler) == SIG_ERR) {
9770Sstevel@tonic-gate perror(gettext("auditreduce: SIGPWR signal failed"));
9780Sstevel@tonic-gate return (-1);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate if (signal(SIGXCPU, int_handler) == SIG_ERR) {
9810Sstevel@tonic-gate perror(gettext("auditreduce: SIGXCPU signal failed"));
9820Sstevel@tonic-gate return (-1);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate if (signal(SIGXFSZ, int_handler) == SIG_ERR) {
9850Sstevel@tonic-gate perror(gettext("auditreduce: SIGXFSZ signal failed"));
9860Sstevel@tonic-gate return (-1);
9870Sstevel@tonic-gate }
988*8889STon.Nguyen@Sun.COM if (signal(SIGSEGV, int_handler) == SIG_ERR) {
989*8889STon.Nguyen@Sun.COM perror(gettext("auditreduce: SIGSEGV signal failed"));
990*8889STon.Nguyen@Sun.COM return (-1);
991*8889STon.Nguyen@Sun.COM }
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate return (0);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate /*
9980Sstevel@tonic-gate * .func chld_handler - handle child signals.
9990Sstevel@tonic-gate * .desc Catch the SIGCHLD signals. Remove the root process
10000Sstevel@tonic-gate * output file because it is in an inconsistent state.
10010Sstevel@tonic-gate * Print a message giving the signal number and/or return code
10020Sstevel@tonic-gate * of the child who caused the signal.
10030Sstevel@tonic-gate * .ret void.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate /* ARGSUSED */
10060Sstevel@tonic-gate void
chld_handler(int sig)10070Sstevel@tonic-gate chld_handler(int sig)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate int pid;
10100Sstevel@tonic-gate int status;
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate * Get pid and reasons for cause of event.
10140Sstevel@tonic-gate */
10150Sstevel@tonic-gate pid = wait(&status);
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate if (pid > 0) {
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate * If child received a signal or exited with a non-zero
10200Sstevel@tonic-gate * exit status then print message and exit
10210Sstevel@tonic-gate */
10220Sstevel@tonic-gate if ((WHIBYTE(status) == 0 && WLOBYTE(status) != 0) ||
10230Sstevel@tonic-gate (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)) {
10240Sstevel@tonic-gate (void) fprintf(stderr,
10250Sstevel@tonic-gate gettext("%s abnormal child termination - "), ar);
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate if (WHIBYTE(status) == 0 && WLOBYTE(status) != 0) {
10280Sstevel@tonic-gate psignal(WLOBYTE(status), "signal");
10290Sstevel@tonic-gate if (WCOREDUMP(status))
10300Sstevel@tonic-gate (void) fprintf(stderr,
10310Sstevel@tonic-gate gettext("core dumped\n"));
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate if (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)
10350Sstevel@tonic-gate (void) fprintf(stderr, gettext(
10360Sstevel@tonic-gate "return code %d\n"),
10370Sstevel@tonic-gate WHIBYTE(status));
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate /*
10400Sstevel@tonic-gate * Get rid of outfile - it is suspect.
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate if (f_outfile != NULL) {
10430Sstevel@tonic-gate (void) close_outfile();
10440Sstevel@tonic-gate rm_outfile();
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * Give statistical info that may be useful.
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate audit_stats();
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate exit(1);
10520Sstevel@tonic-gate }
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate * .func int_handler - handle quit/int signals.
10590Sstevel@tonic-gate * .desc Catch the keyboard and other environmental signals.
10600Sstevel@tonic-gate * Remove the root process output file because it is in
10610Sstevel@tonic-gate * an inconsistent state.
10620Sstevel@tonic-gate * .ret void.
10630Sstevel@tonic-gate */
10640Sstevel@tonic-gate /* ARGSUSED */
10650Sstevel@tonic-gate void
int_handler(int sig)10660Sstevel@tonic-gate int_handler(int sig)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate if (getpid() == root_pid) {
10690Sstevel@tonic-gate (void) close_outfile();
10700Sstevel@tonic-gate rm_outfile();
10710Sstevel@tonic-gate exit(1);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * For a child process don't give an error exit or the
10750Sstevel@tonic-gate * parent process will catch it with the chld_handler and
10760Sstevel@tonic-gate * try to erase the outfile again.
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate exit(0);
10790Sstevel@tonic-gate }
1080