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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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