xref: /titanic_54/usr/src/cmd/auditreduce/main.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1987-2000, 2002 Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * The Secure SunOS audit reduction tool - auditreduce.
32*7c478bd9Sstevel@tonic-gate  * Document SM0071 is the primary source of information on auditreduce.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * Composed of 4 source modules:
35*7c478bd9Sstevel@tonic-gate  * main.c - main driver.
36*7c478bd9Sstevel@tonic-gate  * option.c - command line option processing.
37*7c478bd9Sstevel@tonic-gate  * process.c - record/file/process functions.
38*7c478bd9Sstevel@tonic-gate  * time.c - date/time handling.
39*7c478bd9Sstevel@tonic-gate  *
40*7c478bd9Sstevel@tonic-gate  * Main(), write_header(), audit_stats(), and a_calloc()
41*7c478bd9Sstevel@tonic-gate  * are the only functions visible outside this module.
42*7c478bd9Sstevel@tonic-gate  */
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <siginfo.h>
45*7c478bd9Sstevel@tonic-gate #include <locale.h>
46*7c478bd9Sstevel@tonic-gate #include <libintl.h>
47*7c478bd9Sstevel@tonic-gate #include "auditr.h"
48*7c478bd9Sstevel@tonic-gate #include "auditrd.h"
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
51*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SUNW_OST_OSCMD"
52*7c478bd9Sstevel@tonic-gate #endif
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate extern void	derive_str(time_t, char *);
55*7c478bd9Sstevel@tonic-gate extern int	process_options(int, char **);
56*7c478bd9Sstevel@tonic-gate extern int	mproc(audit_pcb_t *);
57*7c478bd9Sstevel@tonic-gate extern void	init_tokens(void);	/* shared with praudit */
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static int	a_pow(int, int);
60*7c478bd9Sstevel@tonic-gate static void	calc_procs(void);
61*7c478bd9Sstevel@tonic-gate static void	chld_handler(int);
62*7c478bd9Sstevel@tonic-gate static int	close_outfile(void);
63*7c478bd9Sstevel@tonic-gate static void	c_close(audit_pcb_t *, int);
64*7c478bd9Sstevel@tonic-gate static void	delete_infiles(void);
65*7c478bd9Sstevel@tonic-gate static void	gather_pcb(audit_pcb_t *, int, int);
66*7c478bd9Sstevel@tonic-gate static void	init_options(void);
67*7c478bd9Sstevel@tonic-gate static int	init_sig(void);
68*7c478bd9Sstevel@tonic-gate static void	int_handler(int);
69*7c478bd9Sstevel@tonic-gate static int	mfork(audit_pcb_t *, int, int, int);
70*7c478bd9Sstevel@tonic-gate static void	mcount(int, int);
71*7c478bd9Sstevel@tonic-gate static int	open_outfile(void);
72*7c478bd9Sstevel@tonic-gate static void	p_close(audit_pcb_t *);
73*7c478bd9Sstevel@tonic-gate static int	rename_outfile(void);
74*7c478bd9Sstevel@tonic-gate static void	rm_mem(audit_pcb_t *);
75*7c478bd9Sstevel@tonic-gate static void	rm_outfile(void);
76*7c478bd9Sstevel@tonic-gate static void	trim_mem(audit_pcb_t *);
77*7c478bd9Sstevel@tonic-gate static int	write_file_token(time_t);
78*7c478bd9Sstevel@tonic-gate static int	write_trailer(void);
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * File globals.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate static int	max_sproc;	/* maximum number of subprocesses per process */
84*7c478bd9Sstevel@tonic-gate static int	total_procs;	/* number of processes in the process tree */
85*7c478bd9Sstevel@tonic-gate static int	total_layers;	/* number of layers in the process tree */
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * .func main - main.
89*7c478bd9Sstevel@tonic-gate  * .desc The beginning. Main() calls each of the initialization routines
90*7c478bd9Sstevel@tonic-gate  *	and then allocates the root pcb. Then it calls mfork() to get
91*7c478bd9Sstevel@tonic-gate  *	the work done.
92*7c478bd9Sstevel@tonic-gate  * .call	main(argc, argv).
93*7c478bd9Sstevel@tonic-gate  * .arg	argc	- number of arguments.
94*7c478bd9Sstevel@tonic-gate  * .arg	argv	- array of pointers to arguments.
95*7c478bd9Sstevel@tonic-gate  * .ret	0	- via exit() - no errors detected.
96*7c478bd9Sstevel@tonic-gate  * .ret	1	- via exit() - errors detected (messages printed).
97*7c478bd9Sstevel@tonic-gate  */
98*7c478bd9Sstevel@tonic-gate int
99*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	int	ret;
102*7c478bd9Sstevel@tonic-gate 	audit_pcb_t *pcb;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	/* Internationalization */
105*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
106*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	root_pid = getpid();	/* know who is root process for error */
109*7c478bd9Sstevel@tonic-gate 	init_options();		/* initialize options */
110*7c478bd9Sstevel@tonic-gate 	init_tokens();		/* initialize token processing table */
111*7c478bd9Sstevel@tonic-gate 	if (init_sig())		/* initialize signals */
112*7c478bd9Sstevel@tonic-gate 		exit(1);
113*7c478bd9Sstevel@tonic-gate 	if (process_options(argc, argv))
114*7c478bd9Sstevel@tonic-gate 		exit(1);	/* process command line options */
115*7c478bd9Sstevel@tonic-gate 	if (open_outfile())	/* setup root process output stream */
116*7c478bd9Sstevel@tonic-gate 		exit(1);
117*7c478bd9Sstevel@tonic-gate 	calc_procs();		/* see how many subprocesses we need */
118*7c478bd9Sstevel@tonic-gate 	/*
119*7c478bd9Sstevel@tonic-gate 	 * Allocate the root pcb and set it up.
120*7c478bd9Sstevel@tonic-gate 	 */
121*7c478bd9Sstevel@tonic-gate 	pcb = (audit_pcb_t *)a_calloc(1, sizeof (audit_pcb_t));
122*7c478bd9Sstevel@tonic-gate 	pcb->pcb_procno = root_pid;
123*7c478bd9Sstevel@tonic-gate 	pcb->pcb_flags |= PF_ROOT;
124*7c478bd9Sstevel@tonic-gate 	pcb->pcb_fpw = stdout;
125*7c478bd9Sstevel@tonic-gate 	pcb->pcb_time = -1;
126*7c478bd9Sstevel@tonic-gate 	/*
127*7c478bd9Sstevel@tonic-gate 	 * Now start the whole thing rolling.
128*7c478bd9Sstevel@tonic-gate 	 */
129*7c478bd9Sstevel@tonic-gate 	if (mfork(pcb, pcbnum, 0, pcbnum - 1)) {
130*7c478bd9Sstevel@tonic-gate 		/*
131*7c478bd9Sstevel@tonic-gate 		 * Error in processing somewhere. A message is already printed.
132*7c478bd9Sstevel@tonic-gate 		 * Display usage statistics and remove the outfile.
133*7c478bd9Sstevel@tonic-gate 		 */
134*7c478bd9Sstevel@tonic-gate 		if (getpid() == root_pid) {
135*7c478bd9Sstevel@tonic-gate 			audit_stats();
136*7c478bd9Sstevel@tonic-gate 			(void) close_outfile();
137*7c478bd9Sstevel@tonic-gate 			rm_outfile();
138*7c478bd9Sstevel@tonic-gate 		}
139*7c478bd9Sstevel@tonic-gate 		exit(1);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 	/*
142*7c478bd9Sstevel@tonic-gate 	 * Clean up afterwards.
143*7c478bd9Sstevel@tonic-gate 	 * Only do outfile cleanup if we are root process.
144*7c478bd9Sstevel@tonic-gate 	 */
145*7c478bd9Sstevel@tonic-gate 	if (getpid() == root_pid) {
146*7c478bd9Sstevel@tonic-gate 		if ((ret = write_trailer()) == 0) { /* write trailer to file */
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 			ret = close_outfile();	/* close the outfile */
149*7c478bd9Sstevel@tonic-gate 		}
150*7c478bd9Sstevel@tonic-gate 		/*
151*7c478bd9Sstevel@tonic-gate 		 * If there was an error in cleanup then remove outfile.
152*7c478bd9Sstevel@tonic-gate 		 */
153*7c478bd9Sstevel@tonic-gate 		if (ret) {
154*7c478bd9Sstevel@tonic-gate 			rm_outfile();
155*7c478bd9Sstevel@tonic-gate 			exit(1);
156*7c478bd9Sstevel@tonic-gate 		}
157*7c478bd9Sstevel@tonic-gate 		/*
158*7c478bd9Sstevel@tonic-gate 		 * And lastly delete the infiles if the user so wishes.
159*7c478bd9Sstevel@tonic-gate 		 */
160*7c478bd9Sstevel@tonic-gate 		if (f_delete)
161*7c478bd9Sstevel@tonic-gate 			delete_infiles();
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 	return (0);
164*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate /*
169*7c478bd9Sstevel@tonic-gate  * .func mfork - main fork routine.
170*7c478bd9Sstevel@tonic-gate  * .desc Create a (sub-)tree of processses if needed, or just do the work
171*7c478bd9Sstevel@tonic-gate  *	if we have few enough groups to process. This is a recursive routine
172*7c478bd9Sstevel@tonic-gate  *	which stops recursing when the number of files to process is small
173*7c478bd9Sstevel@tonic-gate  *	enough. Each call to mfork() is responsible for a range of pcbs
174*7c478bd9Sstevel@tonic-gate  *	from audit_pcbs[]. This range is designated by the lo and hi
175*7c478bd9Sstevel@tonic-gate  *	arguments (inclusive). If the number of pcbs is small enough
176*7c478bd9Sstevel@tonic-gate  *	then we have hit a leaf of the tree and mproc() is called to
177*7c478bd9Sstevel@tonic-gate  *	do the processing. Otherwise we fork some processes and break
178*7c478bd9Sstevel@tonic-gate  *	the range of pcbs up amongst them.
179*7c478bd9Sstevel@tonic-gate  * .call	ret = mfork(pcb, nsp, lo, hi).
180*7c478bd9Sstevel@tonic-gate  * .arg	pcb	- ptr to pcb that is root node of the to-be-created tree.
181*7c478bd9Sstevel@tonic-gate  * .arg	nsp	- number of sub-processes this tree must process.
182*7c478bd9Sstevel@tonic-gate  * .arg	lo	- lower-limit of process number range. Index into audit_pcbs.
183*7c478bd9Sstevel@tonic-gate  * .arg	hi	- higher limit of pcb range. Index into audit_pcbs.
184*7c478bd9Sstevel@tonic-gate  * .ret	0	- succesful completion.
185*7c478bd9Sstevel@tonic-gate  * .ret	-1	- error encountered in processing - message already printed.
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate static int
188*7c478bd9Sstevel@tonic-gate mfork(audit_pcb_t *pcb, int nsp, int lo, int hi)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	int	range, procno, i, tofork, nnsp, nrem;
191*7c478bd9Sstevel@tonic-gate 	int	fildes[2];
192*7c478bd9Sstevel@tonic-gate 	audit_pcb_t *pcbn;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate #if AUDIT_PROC_TRACE
195*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "mfork: nsp %d %d->%d\n", nsp, lo, hi);
196*7c478bd9Sstevel@tonic-gate #endif
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	/*
199*7c478bd9Sstevel@tonic-gate 	 * The range of pcb's to process is small enough now. Do the work.
200*7c478bd9Sstevel@tonic-gate 	 */
201*7c478bd9Sstevel@tonic-gate 	if (nsp <= max_sproc) {
202*7c478bd9Sstevel@tonic-gate 		pcb->pcb_flags |= PF_LEAF;	/* leaf in process tree */
203*7c478bd9Sstevel@tonic-gate 		pcb->pcb_below = audit_pcbs;	/* proc pcbs from audit_pcbs */
204*7c478bd9Sstevel@tonic-gate 		gather_pcb(pcb, lo, hi);
205*7c478bd9Sstevel@tonic-gate 		trim_mem(pcb);			/* trim allocated memory */
206*7c478bd9Sstevel@tonic-gate 		return (mproc(pcb));		/* do the work */
207*7c478bd9Sstevel@tonic-gate 	}
208*7c478bd9Sstevel@tonic-gate 	/*
209*7c478bd9Sstevel@tonic-gate 	 * Too many pcb's for one process - must fork.
210*7c478bd9Sstevel@tonic-gate 	 * Try to balance the tree as it grows and make it short and fat.
211*7c478bd9Sstevel@tonic-gate 	 * The thing to minimize is the number of times a record passes
212*7c478bd9Sstevel@tonic-gate 	 * through a pipe.
213*7c478bd9Sstevel@tonic-gate 	 */
214*7c478bd9Sstevel@tonic-gate 	else {
215*7c478bd9Sstevel@tonic-gate 		/*
216*7c478bd9Sstevel@tonic-gate 		 * Fork less than the maximum number of processes.
217*7c478bd9Sstevel@tonic-gate 		 */
218*7c478bd9Sstevel@tonic-gate 		if (nsp <= max_sproc * (max_sproc - 1)) {
219*7c478bd9Sstevel@tonic-gate 			tofork = nsp / max_sproc;
220*7c478bd9Sstevel@tonic-gate 			if (nsp % max_sproc)
221*7c478bd9Sstevel@tonic-gate 				tofork++;	/* how many to fork */
222*7c478bd9Sstevel@tonic-gate 		}
223*7c478bd9Sstevel@tonic-gate 		/*
224*7c478bd9Sstevel@tonic-gate 		 * Fork the maximum number of processes.
225*7c478bd9Sstevel@tonic-gate 		 */
226*7c478bd9Sstevel@tonic-gate 		else {
227*7c478bd9Sstevel@tonic-gate 			tofork = max_sproc;	/* how many to fork */
228*7c478bd9Sstevel@tonic-gate 		}
229*7c478bd9Sstevel@tonic-gate 		/*
230*7c478bd9Sstevel@tonic-gate 		 * Allocate the nodes below us in the process tree.
231*7c478bd9Sstevel@tonic-gate 		 */
232*7c478bd9Sstevel@tonic-gate 		pcb->pcb_below = (audit_pcb_t *)
233*7c478bd9Sstevel@tonic-gate 			a_calloc(tofork, sizeof (*pcb));
234*7c478bd9Sstevel@tonic-gate 		nnsp = nsp / tofork;	/* # of pcbs per forked process */
235*7c478bd9Sstevel@tonic-gate 		nrem = nsp % tofork;	/* remainder to spread around */
236*7c478bd9Sstevel@tonic-gate 		/*
237*7c478bd9Sstevel@tonic-gate 		 * Loop to fork all of the subs. Open a pipe for each.
238*7c478bd9Sstevel@tonic-gate 		 * If there are any errors in pipes, forks, or getting streams
239*7c478bd9Sstevel@tonic-gate 		 * for the pipes then quit altogether.
240*7c478bd9Sstevel@tonic-gate 		 */
241*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < tofork; i++) {
242*7c478bd9Sstevel@tonic-gate 			pcbn = &pcb->pcb_below[i];
243*7c478bd9Sstevel@tonic-gate 			pcbn->pcb_time = -1;
244*7c478bd9Sstevel@tonic-gate 			if (pipe(fildes)) {
245*7c478bd9Sstevel@tonic-gate 				perror(gettext(
246*7c478bd9Sstevel@tonic-gate 					"auditreduce: couldn't get a pipe"));
247*7c478bd9Sstevel@tonic-gate 				return (-1);
248*7c478bd9Sstevel@tonic-gate 			}
249*7c478bd9Sstevel@tonic-gate 			/*
250*7c478bd9Sstevel@tonic-gate 			 * Convert descriptors to streams.
251*7c478bd9Sstevel@tonic-gate 			 */
252*7c478bd9Sstevel@tonic-gate 			if ((pcbn->pcb_fpr = fdopen(fildes[0], "r")) == NULL) {
253*7c478bd9Sstevel@tonic-gate 	perror(gettext("auditreduce: couldn't get read stream for pipe"));
254*7c478bd9Sstevel@tonic-gate 				return (-1);
255*7c478bd9Sstevel@tonic-gate 			}
256*7c478bd9Sstevel@tonic-gate 			if ((pcbn->pcb_fpw = fdopen(fildes[1], "w")) == NULL) {
257*7c478bd9Sstevel@tonic-gate 	perror(gettext("auditreduce: couldn't get write stream for pipe"));
258*7c478bd9Sstevel@tonic-gate 				return (-1);
259*7c478bd9Sstevel@tonic-gate 			}
260*7c478bd9Sstevel@tonic-gate 			if ((procno = fork()) == -1) {
261*7c478bd9Sstevel@tonic-gate 				perror(gettext("auditreduce: fork failed"));
262*7c478bd9Sstevel@tonic-gate 				return (-1);
263*7c478bd9Sstevel@tonic-gate 			}
264*7c478bd9Sstevel@tonic-gate 			/*
265*7c478bd9Sstevel@tonic-gate 			 * Calculate the range of pcbs from audit_pcbs [] this
266*7c478bd9Sstevel@tonic-gate 			 * branch of the tree will be responsible for.
267*7c478bd9Sstevel@tonic-gate 			 */
268*7c478bd9Sstevel@tonic-gate 			range = (nrem > 0) ? nnsp + 1 : nnsp;
269*7c478bd9Sstevel@tonic-gate 			/*
270*7c478bd9Sstevel@tonic-gate 			 * Child route.
271*7c478bd9Sstevel@tonic-gate 			 */
272*7c478bd9Sstevel@tonic-gate 			if (procno == 0) {
273*7c478bd9Sstevel@tonic-gate 				pcbn->pcb_procno = getpid();
274*7c478bd9Sstevel@tonic-gate 				c_close(pcb, i); /* close unused streams */
275*7c478bd9Sstevel@tonic-gate 				/*
276*7c478bd9Sstevel@tonic-gate 				 * Continue resolving this branch.
277*7c478bd9Sstevel@tonic-gate 				 */
278*7c478bd9Sstevel@tonic-gate 				return (mfork(pcbn, range, lo, lo + range - 1));
279*7c478bd9Sstevel@tonic-gate 			}
280*7c478bd9Sstevel@tonic-gate 			/* Parent route. */
281*7c478bd9Sstevel@tonic-gate 			else {
282*7c478bd9Sstevel@tonic-gate 				pcbn->pcb_procno = i;
283*7c478bd9Sstevel@tonic-gate 				/* allocate buffer to hold record */
284*7c478bd9Sstevel@tonic-gate 				pcbn->pcb_rec = (char *)a_calloc(1,
285*7c478bd9Sstevel@tonic-gate 				    AUDITBUFSIZE);
286*7c478bd9Sstevel@tonic-gate 				pcbn->pcb_size = AUDITBUFSIZE;
287*7c478bd9Sstevel@tonic-gate 				p_close(pcbn);	/* close unused streams */
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 				nrem--;
290*7c478bd9Sstevel@tonic-gate 				lo += range;
291*7c478bd9Sstevel@tonic-gate 			}
292*7c478bd9Sstevel@tonic-gate 		}
293*7c478bd9Sstevel@tonic-gate 		/*
294*7c478bd9Sstevel@tonic-gate 		 * Done forking all of the subs.
295*7c478bd9Sstevel@tonic-gate 		 */
296*7c478bd9Sstevel@tonic-gate 		gather_pcb(pcb, 0, tofork - 1);
297*7c478bd9Sstevel@tonic-gate 		trim_mem(pcb);			/* free unused memory */
298*7c478bd9Sstevel@tonic-gate 		return (mproc(pcb));
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate /*
304*7c478bd9Sstevel@tonic-gate  * .func	trim_mem - trim memory usage.
305*7c478bd9Sstevel@tonic-gate  * .desc	Free un-needed allocated memory.
306*7c478bd9Sstevel@tonic-gate  * .call	trim_mem(pcb).
307*7c478bd9Sstevel@tonic-gate  * .arg	pcb	- ptr to pcb for current process.
308*7c478bd9Sstevel@tonic-gate  * .ret	void.
309*7c478bd9Sstevel@tonic-gate  */
310*7c478bd9Sstevel@tonic-gate static void
311*7c478bd9Sstevel@tonic-gate trim_mem(audit_pcb_t *pcb)
312*7c478bd9Sstevel@tonic-gate {
313*7c478bd9Sstevel@tonic-gate 	int	count;
314*7c478bd9Sstevel@tonic-gate 	size_t	size;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/*
317*7c478bd9Sstevel@tonic-gate 	 * For the root don't free anything. We need to save audit_pcbs[]
318*7c478bd9Sstevel@tonic-gate 	 * in case we are deleting the infiles at the end.
319*7c478bd9Sstevel@tonic-gate 	 */
320*7c478bd9Sstevel@tonic-gate 	if (pcb->pcb_flags & PF_ROOT)
321*7c478bd9Sstevel@tonic-gate 		return;
322*7c478bd9Sstevel@tonic-gate 	/*
323*7c478bd9Sstevel@tonic-gate 	 * For a leaf save its part of audit_pcbs[] and then remove it all.
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	if (pcb->pcb_flags & PF_LEAF) {
326*7c478bd9Sstevel@tonic-gate 		count = pcb->pcb_count;
327*7c478bd9Sstevel@tonic-gate 		size = sizeof (audit_pcb_t);
328*7c478bd9Sstevel@tonic-gate 		/* allocate a new buffer to hold the pcbs */
329*7c478bd9Sstevel@tonic-gate 		pcb->pcb_below = (audit_pcb_t *)a_calloc(count, size);
330*7c478bd9Sstevel@tonic-gate 		/* save this pcb's portion */
331*7c478bd9Sstevel@tonic-gate 		(void) memcpy((void *) pcb->pcb_below,
332*7c478bd9Sstevel@tonic-gate 		    (void *) &audit_pcbs[pcb->pcb_lo], count * size);
333*7c478bd9Sstevel@tonic-gate 		rm_mem(pcb);
334*7c478bd9Sstevel@tonic-gate 		gather_pcb(pcb, 0, count - 1);
335*7c478bd9Sstevel@tonic-gate 	}
336*7c478bd9Sstevel@tonic-gate 		/*
337*7c478bd9Sstevel@tonic-gate 		 * If this is an intermediate node then just remove it all.
338*7c478bd9Sstevel@tonic-gate 		 */
339*7c478bd9Sstevel@tonic-gate 	else {
340*7c478bd9Sstevel@tonic-gate 		rm_mem(pcb);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate /*
346*7c478bd9Sstevel@tonic-gate  * .func	rm_mem - remove memory.
347*7c478bd9Sstevel@tonic-gate  * .desc	Remove unused memory associated with audit_pcbs[]. For each
348*7c478bd9Sstevel@tonic-gate  *	pcb in audit_pcbs[] free the record buffer and all of
349*7c478bd9Sstevel@tonic-gate  *	the fcbs. Then free audit_pcbs[].
350*7c478bd9Sstevel@tonic-gate  * .call	rm_mem(pcbr).
351*7c478bd9Sstevel@tonic-gate  * .arg	pcbr	- ptr to pcb of current process.
352*7c478bd9Sstevel@tonic-gate  * .ret	void.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static void
355*7c478bd9Sstevel@tonic-gate rm_mem(audit_pcb_t *pcbr)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	int	i;
358*7c478bd9Sstevel@tonic-gate 	audit_pcb_t *pcb;
359*7c478bd9Sstevel@tonic-gate 	audit_fcb_t *fcb, *fcbn;
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcbsize; i++) {
362*7c478bd9Sstevel@tonic-gate 		/*
363*7c478bd9Sstevel@tonic-gate 		 * Don't free the record buffer and fcbs for the pcbs this
364*7c478bd9Sstevel@tonic-gate 		 * process is using.
365*7c478bd9Sstevel@tonic-gate 		 */
366*7c478bd9Sstevel@tonic-gate 		if (pcbr->pcb_flags & PF_LEAF) {
367*7c478bd9Sstevel@tonic-gate 			if (pcbr->pcb_lo <= i || i <= pcbr->pcb_hi)
368*7c478bd9Sstevel@tonic-gate 				continue;
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		pcb = &audit_pcbs[i];
371*7c478bd9Sstevel@tonic-gate 		free(pcb->pcb_rec);
372*7c478bd9Sstevel@tonic-gate 		for (fcb = pcb->pcb_first; fcb != NULL; /* */) {
373*7c478bd9Sstevel@tonic-gate 			fcbn = fcb->fcb_next;
374*7c478bd9Sstevel@tonic-gate 			free((char *)fcb);
375*7c478bd9Sstevel@tonic-gate 			fcb = fcbn;
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 	free((char *)audit_pcbs);
379*7c478bd9Sstevel@tonic-gate }
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate /*
383*7c478bd9Sstevel@tonic-gate  * .func	c_close - close unused streams.
384*7c478bd9Sstevel@tonic-gate  * .desc	This is called for each child process just after being born.
385*7c478bd9Sstevel@tonic-gate  *	The child closes the read stream for the pipe to its parent.
386*7c478bd9Sstevel@tonic-gate  *	It also closes the read streams for the other children that
387*7c478bd9Sstevel@tonic-gate  *	have been born before it. If any closes fail a warning message
388*7c478bd9Sstevel@tonic-gate  *	is printed, but processing continues.
389*7c478bd9Sstevel@tonic-gate  * .call	ret = c_close(pcb, i).
390*7c478bd9Sstevel@tonic-gate  * .arg	pcb	- ptr to the child's parent pcb.
391*7c478bd9Sstevel@tonic-gate  * .arg	i	- iteration # of child in forking loop.
392*7c478bd9Sstevel@tonic-gate  * .ret	void.
393*7c478bd9Sstevel@tonic-gate  */
394*7c478bd9Sstevel@tonic-gate static void
395*7c478bd9Sstevel@tonic-gate c_close(audit_pcb_t *pcb, int	i)
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate 	int	j;
398*7c478bd9Sstevel@tonic-gate 	audit_pcb_t *pcbt;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/*
401*7c478bd9Sstevel@tonic-gate 	 * Do all pcbs in parent's group up to and including us
402*7c478bd9Sstevel@tonic-gate 	 */
403*7c478bd9Sstevel@tonic-gate 	for (j = 0; j <= i; j++) {
404*7c478bd9Sstevel@tonic-gate 		pcbt = &pcb->pcb_below[j];
405*7c478bd9Sstevel@tonic-gate 		if (fclose(pcbt->pcb_fpr) == EOF) {
406*7c478bd9Sstevel@tonic-gate 			if (!f_quiet)
407*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: initial close on pipe failed"));
408*7c478bd9Sstevel@tonic-gate 		}
409*7c478bd9Sstevel@tonic-gate 		/*
410*7c478bd9Sstevel@tonic-gate 		 * Free the buffer allocated to hold incoming records.
411*7c478bd9Sstevel@tonic-gate 		 */
412*7c478bd9Sstevel@tonic-gate 		if (i != j) {
413*7c478bd9Sstevel@tonic-gate 			free(pcbt->pcb_rec);
414*7c478bd9Sstevel@tonic-gate 		}
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate /*
420*7c478bd9Sstevel@tonic-gate  * .func	p_close - close unused streams for parent.
421*7c478bd9Sstevel@tonic-gate  * .desc	Called by the parent right after forking a child.
422*7c478bd9Sstevel@tonic-gate  *	Closes the write stream on the pipe to the child since
423*7c478bd9Sstevel@tonic-gate  *	we will never use it.
424*7c478bd9Sstevel@tonic-gate  * .call	p_close(pcbn),
425*7c478bd9Sstevel@tonic-gate  * .arg	pcbn	- ptr to pcb.
426*7c478bd9Sstevel@tonic-gate  * .ret	void.
427*7c478bd9Sstevel@tonic-gate  */
428*7c478bd9Sstevel@tonic-gate static void
429*7c478bd9Sstevel@tonic-gate p_close(audit_pcb_t *pcbn)
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate 	if (fclose(pcbn->pcb_fpw) == EOF) {
432*7c478bd9Sstevel@tonic-gate 		if (!f_quiet)
433*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: close for write pipe failed"));
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate /*
439*7c478bd9Sstevel@tonic-gate  * .func	audit_stats - print statistics.
440*7c478bd9Sstevel@tonic-gate  * .desc	Print usage statistics for the user if the run fails.
441*7c478bd9Sstevel@tonic-gate  *	Tells them how many files they had and how many groups this
442*7c478bd9Sstevel@tonic-gate  *	totalled. Also tell them how many layers and processes the
443*7c478bd9Sstevel@tonic-gate  *	process tree had.
444*7c478bd9Sstevel@tonic-gate  * .call	audit_stats().
445*7c478bd9Sstevel@tonic-gate  * .arg	none.
446*7c478bd9Sstevel@tonic-gate  * .ret	void.
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate void
449*7c478bd9Sstevel@tonic-gate audit_stats(void)
450*7c478bd9Sstevel@tonic-gate {
451*7c478bd9Sstevel@tonic-gate 	struct rlimit rl;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) != -1)
454*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
455*7c478bd9Sstevel@tonic-gate 		    gettext("%s The system allows %d files per process.\n"),
456*7c478bd9Sstevel@tonic-gate 		    ar, rl.rlim_cur);
457*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
458*7c478bd9Sstevel@tonic-gate "%s There were %d file(s) %d file group(s) %d process(es) %d layer(s).\n"),
459*7c478bd9Sstevel@tonic-gate 		ar, filenum, pcbnum, total_procs, total_layers);
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate /*
464*7c478bd9Sstevel@tonic-gate  * .func gather_pcb - gather pcbs.
465*7c478bd9Sstevel@tonic-gate  * .desc Gather together the range of the sub-processes that we are
466*7c478bd9Sstevel@tonic-gate  *	responsible for. For a pcb that controls processes this is all
467*7c478bd9Sstevel@tonic-gate  *	of the sub-processes that it forks. For a pcb that controls
468*7c478bd9Sstevel@tonic-gate  *	files this is the the range of pcbs from audit_pcbs[].
469*7c478bd9Sstevel@tonic-gate  * .call gather_pcb(pcb, lo, hi).
470*7c478bd9Sstevel@tonic-gate  * .arg	pcb	- ptr to pcb.
471*7c478bd9Sstevel@tonic-gate  * .arg	lo	- lo index into pcb_below.
472*7c478bd9Sstevel@tonic-gate  * .arg	hi	- hi index into pcb_below.
473*7c478bd9Sstevel@tonic-gate  * .ret	void.
474*7c478bd9Sstevel@tonic-gate  */
475*7c478bd9Sstevel@tonic-gate static void
476*7c478bd9Sstevel@tonic-gate gather_pcb(audit_pcb_t *pcb, int lo, int hi)
477*7c478bd9Sstevel@tonic-gate {
478*7c478bd9Sstevel@tonic-gate 	pcb->pcb_lo = lo;
479*7c478bd9Sstevel@tonic-gate 	pcb->pcb_hi = hi;
480*7c478bd9Sstevel@tonic-gate 	pcb->pcb_count = hi - lo + 1;
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate /*
485*7c478bd9Sstevel@tonic-gate  * .func calc_procs - calculate process parameters.
486*7c478bd9Sstevel@tonic-gate  * .desc Calculate the current run's paramters regarding how many
487*7c478bd9Sstevel@tonic-gate  *	processes will have to be forked (maybe none).
488*7c478bd9Sstevel@tonic-gate  *	5 is subtracted from maxfiles_proc to allow for stdin, stdout,
489*7c478bd9Sstevel@tonic-gate  *	stderr, and the pipe to a parent process. The outfile
490*7c478bd9Sstevel@tonic-gate  *	in the root process is assigned to stdout. The unused half of each
491*7c478bd9Sstevel@tonic-gate  *	pipe is closed, to allow for more connections, but we still
492*7c478bd9Sstevel@tonic-gate  *	have to have the 5th spot because in order to get the pipe
493*7c478bd9Sstevel@tonic-gate  *	we need 2 descriptors up front.
494*7c478bd9Sstevel@tonic-gate  * .call calc_procs().
495*7c478bd9Sstevel@tonic-gate  * .arg	none.
496*7c478bd9Sstevel@tonic-gate  * .ret	void.
497*7c478bd9Sstevel@tonic-gate  */
498*7c478bd9Sstevel@tonic-gate static void
499*7c478bd9Sstevel@tonic-gate calc_procs(void)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 	int	val;
502*7c478bd9Sstevel@tonic-gate 	int	maxfiles_proc;
503*7c478bd9Sstevel@tonic-gate 	struct rlimit rl;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
506*7c478bd9Sstevel@tonic-gate 		perror("auditreduce: getrlimit");
507*7c478bd9Sstevel@tonic-gate 		exit(1);
508*7c478bd9Sstevel@tonic-gate 	}
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	maxfiles_proc = rl.rlim_cur;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	max_sproc = maxfiles_proc - 5;	/* max subprocesses per process */
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	/*
515*7c478bd9Sstevel@tonic-gate 	 * Calculate how many layers the process tree has.
516*7c478bd9Sstevel@tonic-gate 	 */
517*7c478bd9Sstevel@tonic-gate 	total_layers = 1;
518*7c478bd9Sstevel@tonic-gate 	for (/* */; /* */; /* */) {
519*7c478bd9Sstevel@tonic-gate 		val = a_pow(max_sproc, total_layers);
520*7c478bd9Sstevel@tonic-gate 		if (val > pcbnum)
521*7c478bd9Sstevel@tonic-gate 			break;
522*7c478bd9Sstevel@tonic-gate 		total_layers++;
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 	/*
525*7c478bd9Sstevel@tonic-gate 	 * Count how many processes are in the process tree.
526*7c478bd9Sstevel@tonic-gate 	 */
527*7c478bd9Sstevel@tonic-gate 	mcount(pcbnum, 0);
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate #if AUDIT_PROC_TRACE
530*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
531*7c478bd9Sstevel@tonic-gate 	    "pcbnum %d filenum %d mfp %d msp %d ly %d tot %d\n\n",
532*7c478bd9Sstevel@tonic-gate 	    pcbnum, filenum, maxfiles_proc, max_sproc,
533*7c478bd9Sstevel@tonic-gate 	    total_layers, total_procs);
534*7c478bd9Sstevel@tonic-gate #endif
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate static int
539*7c478bd9Sstevel@tonic-gate a_pow(int base, int exp)
540*7c478bd9Sstevel@tonic-gate {
541*7c478bd9Sstevel@tonic-gate 	int	i;
542*7c478bd9Sstevel@tonic-gate 	int	answer;
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	if (exp == 0) {
545*7c478bd9Sstevel@tonic-gate 		answer = 1;
546*7c478bd9Sstevel@tonic-gate 	} else {
547*7c478bd9Sstevel@tonic-gate 		answer = base;
548*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (exp - 1); i++)
549*7c478bd9Sstevel@tonic-gate 			answer *= base;
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 	return (answer);
552*7c478bd9Sstevel@tonic-gate }
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate /*
556*7c478bd9Sstevel@tonic-gate  * .func mcount - main count.
557*7c478bd9Sstevel@tonic-gate  * .desc Go through the motions of building the process tree just
558*7c478bd9Sstevel@tonic-gate  *	to count how many processes there are. Don't really
559*7c478bd9Sstevel@tonic-gate  *	build anything. Answer is in global var total_procs.
560*7c478bd9Sstevel@tonic-gate  * .call mcount(nsp, lo).
561*7c478bd9Sstevel@tonic-gate  * .arg	nsp	- number of subs for this tree branch.
562*7c478bd9Sstevel@tonic-gate  * .arg	lo	- lo side of range of subs.
563*7c478bd9Sstevel@tonic-gate  * .ret	void.
564*7c478bd9Sstevel@tonic-gate  */
565*7c478bd9Sstevel@tonic-gate static void
566*7c478bd9Sstevel@tonic-gate mcount(int nsp, int lo)
567*7c478bd9Sstevel@tonic-gate {
568*7c478bd9Sstevel@tonic-gate 	int	range, i, tofork, nnsp, nrem;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	total_procs++;		/* count another process created */
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	if (nsp > max_sproc) {
573*7c478bd9Sstevel@tonic-gate 		if (nsp <= max_sproc * (max_sproc - 1)) {
574*7c478bd9Sstevel@tonic-gate 			tofork = nsp / max_sproc;
575*7c478bd9Sstevel@tonic-gate 			if (nsp % max_sproc)
576*7c478bd9Sstevel@tonic-gate 				tofork++;
577*7c478bd9Sstevel@tonic-gate 		} else {
578*7c478bd9Sstevel@tonic-gate 			tofork = max_sproc;
579*7c478bd9Sstevel@tonic-gate 		}
580*7c478bd9Sstevel@tonic-gate 		nnsp = nsp / tofork;
581*7c478bd9Sstevel@tonic-gate 		nrem = nsp % tofork;
582*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < tofork; i++) {
583*7c478bd9Sstevel@tonic-gate 			range = (nrem > 0) ? nnsp + 1 : nnsp;
584*7c478bd9Sstevel@tonic-gate 			mcount(range, lo);
585*7c478bd9Sstevel@tonic-gate 			nrem--;
586*7c478bd9Sstevel@tonic-gate 			lo += range;
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 	}
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate /*
593*7c478bd9Sstevel@tonic-gate  * .func delete_infiles - delete the input files.
594*7c478bd9Sstevel@tonic-gate  * .desc If the user asked us to (via 'D' flag) then unlink the input files.
595*7c478bd9Sstevel@tonic-gate  * .call ret = delete_infiles().
596*7c478bd9Sstevel@tonic-gate  * .arg none.
597*7c478bd9Sstevel@tonic-gate  * .ret void.
598*7c478bd9Sstevel@tonic-gate  */
599*7c478bd9Sstevel@tonic-gate static void
600*7c478bd9Sstevel@tonic-gate delete_infiles(void)
601*7c478bd9Sstevel@tonic-gate {
602*7c478bd9Sstevel@tonic-gate 	int	i;
603*7c478bd9Sstevel@tonic-gate 	audit_pcb_t *pcb;
604*7c478bd9Sstevel@tonic-gate 	audit_fcb_t *fcb;
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < pcbsize; i++) {
607*7c478bd9Sstevel@tonic-gate 		pcb = &audit_pcbs[i];
608*7c478bd9Sstevel@tonic-gate 		fcb = pcb->pcb_dfirst;
609*7c478bd9Sstevel@tonic-gate 		while (fcb != NULL) {
610*7c478bd9Sstevel@tonic-gate 			/*
611*7c478bd9Sstevel@tonic-gate 			 * Only delete a file if it was succesfully processed.
612*7c478bd9Sstevel@tonic-gate 			 * If there were any read errors or bad records
613*7c478bd9Sstevel@tonic-gate 			 * then don't delete it.
614*7c478bd9Sstevel@tonic-gate 			 * There may still be unprocessed records in it.
615*7c478bd9Sstevel@tonic-gate 			 */
616*7c478bd9Sstevel@tonic-gate 			if (fcb->fcb_flags & FF_DELETE) {
617*7c478bd9Sstevel@tonic-gate 				if (unlink(fcb->fcb_file)) {
618*7c478bd9Sstevel@tonic-gate 					if (f_verbose) {
619*7c478bd9Sstevel@tonic-gate 						(void) sprintf(errbuf, gettext(
620*7c478bd9Sstevel@tonic-gate 						"%s delete on %s failed"),
621*7c478bd9Sstevel@tonic-gate 						ar, fcb->fcb_file);
622*7c478bd9Sstevel@tonic-gate 					}
623*7c478bd9Sstevel@tonic-gate 					perror(errbuf);
624*7c478bd9Sstevel@tonic-gate 				}
625*7c478bd9Sstevel@tonic-gate 			}
626*7c478bd9Sstevel@tonic-gate 			fcb = fcb->fcb_next;
627*7c478bd9Sstevel@tonic-gate 		}
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate }
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate /*
633*7c478bd9Sstevel@tonic-gate  * .func rm_outfile - remove the outfile.
634*7c478bd9Sstevel@tonic-gate  * .desc Remove the file we are writing the records to. We do this if
635*7c478bd9Sstevel@tonic-gate  *	processing failed and we are quitting before finishing.
636*7c478bd9Sstevel@tonic-gate  *	Update - don't actually remove the outfile, but generate
637*7c478bd9Sstevel@tonic-gate  *	a warning about its possible heathen nature.
638*7c478bd9Sstevel@tonic-gate  * .call ret = rm_outfile().
639*7c478bd9Sstevel@tonic-gate  * .arg	none.
640*7c478bd9Sstevel@tonic-gate  * .ret	void.
641*7c478bd9Sstevel@tonic-gate  */
642*7c478bd9Sstevel@tonic-gate static void
643*7c478bd9Sstevel@tonic-gate rm_outfile(void)
644*7c478bd9Sstevel@tonic-gate {
645*7c478bd9Sstevel@tonic-gate #if 0
646*7c478bd9Sstevel@tonic-gate 	if (f_outfile) {
647*7c478bd9Sstevel@tonic-gate 		if (unlink(f_outtemp) == -1) {
648*7c478bd9Sstevel@tonic-gate 			(void) sprintf(errbuf,
649*7c478bd9Sstevel@tonic-gate 				gettext("%s delete on %s failed"),
650*7c478bd9Sstevel@tonic-gate 				ar, f_outtemp);
651*7c478bd9Sstevel@tonic-gate 			perror(errbuf);
652*7c478bd9Sstevel@tonic-gate 		}
653*7c478bd9Sstevel@tonic-gate 	}
654*7c478bd9Sstevel@tonic-gate #else
655*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
656*7c478bd9Sstevel@tonic-gate gettext("%s Warning: Incomplete audit file may have been generated - %s\n"),
657*7c478bd9Sstevel@tonic-gate 		ar,
658*7c478bd9Sstevel@tonic-gate 		(f_outfile == NULL) ? gettext("standard output") : f_outfile);
659*7c478bd9Sstevel@tonic-gate #endif
660*7c478bd9Sstevel@tonic-gate }
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate /*
664*7c478bd9Sstevel@tonic-gate  * .func	close_outfile - close the outfile.
665*7c478bd9Sstevel@tonic-gate  * .desc	Close the file we are writing records to.
666*7c478bd9Sstevel@tonic-gate  * .call	ret = close_outfile().
667*7c478bd9Sstevel@tonic-gate  * .arg	none.
668*7c478bd9Sstevel@tonic-gate  * .ret	0	- close was succesful.
669*7c478bd9Sstevel@tonic-gate  * .ret	-1	- close failed.
670*7c478bd9Sstevel@tonic-gate  */
671*7c478bd9Sstevel@tonic-gate static int
672*7c478bd9Sstevel@tonic-gate close_outfile(void)
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	if (fclose(stdout) == EOF) {
675*7c478bd9Sstevel@tonic-gate 		(void) sprintf(errbuf, gettext("%s close on %s failed"),
676*7c478bd9Sstevel@tonic-gate 		    ar, f_outfile ? f_outfile : "standard output");
677*7c478bd9Sstevel@tonic-gate 		perror(errbuf);
678*7c478bd9Sstevel@tonic-gate 		return (-1);
679*7c478bd9Sstevel@tonic-gate 	}
680*7c478bd9Sstevel@tonic-gate 	(void) fsync(fileno(stdout));
681*7c478bd9Sstevel@tonic-gate 	return (rename_outfile());
682*7c478bd9Sstevel@tonic-gate }
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate /*
686*7c478bd9Sstevel@tonic-gate  * .func write_header - write audit file header.
687*7c478bd9Sstevel@tonic-gate  * .desc Write an audit file header to the output stream. The time in the
688*7c478bd9Sstevel@tonic-gate  *	header is the time of the first record written to the stream. This
689*7c478bd9Sstevel@tonic-gate  *	routine is called by the process handling the root node of the
690*7c478bd9Sstevel@tonic-gate  *	process tree just before it writes the first record to the output
691*7c478bd9Sstevel@tonic-gate  *	stream.
692*7c478bd9Sstevel@tonic-gate  * .ret	0 - succesful write.
693*7c478bd9Sstevel@tonic-gate  * .ret -1 - failed write - message printed.
694*7c478bd9Sstevel@tonic-gate  */
695*7c478bd9Sstevel@tonic-gate int
696*7c478bd9Sstevel@tonic-gate write_header(void)
697*7c478bd9Sstevel@tonic-gate {
698*7c478bd9Sstevel@tonic-gate 	return (write_file_token(f_start));
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate static int
703*7c478bd9Sstevel@tonic-gate write_file_token(time_t when)
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	adr_t adr;			/* adr ptr */
706*7c478bd9Sstevel@tonic-gate 	struct timeval tv;		/* time now */
707*7c478bd9Sstevel@tonic-gate 	char	for_adr[16];		/* plenty of room */
708*7c478bd9Sstevel@tonic-gate #ifdef _LP64
709*7c478bd9Sstevel@tonic-gate 	char	token_id = AUT_OTHER_FILE64;
710*7c478bd9Sstevel@tonic-gate #else
711*7c478bd9Sstevel@tonic-gate 	char	token_id = AUT_OTHER_FILE32;
712*7c478bd9Sstevel@tonic-gate #endif
713*7c478bd9Sstevel@tonic-gate 	short	i = 1;
714*7c478bd9Sstevel@tonic-gate 	char	c = '\0';
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	tv.tv_sec = when;
717*7c478bd9Sstevel@tonic-gate 	tv.tv_usec = 0;
718*7c478bd9Sstevel@tonic-gate 	adr_start(&adr, for_adr);
719*7c478bd9Sstevel@tonic-gate 	adr_char(&adr, &token_id, 1);
720*7c478bd9Sstevel@tonic-gate #ifdef _LP64
721*7c478bd9Sstevel@tonic-gate 	adr_int64(&adr, (int64_t *)&tv, 2);
722*7c478bd9Sstevel@tonic-gate #else
723*7c478bd9Sstevel@tonic-gate 	adr_int32(&adr, (int32_t *)&tv, 2);
724*7c478bd9Sstevel@tonic-gate #endif
725*7c478bd9Sstevel@tonic-gate 	adr_short(&adr, &i, 1);
726*7c478bd9Sstevel@tonic-gate 	adr_char(&adr, &c, 1);
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	if (fwrite(for_adr, sizeof (char), adr_count(&adr), stdout) !=
729*7c478bd9Sstevel@tonic-gate 	    adr_count(&adr)) {
730*7c478bd9Sstevel@tonic-gate 		if (when == f_start) {
731*7c478bd9Sstevel@tonic-gate 			(void) sprintf(errbuf,
732*7c478bd9Sstevel@tonic-gate 				gettext("%s error writing header to %s. "),
733*7c478bd9Sstevel@tonic-gate 				ar,
734*7c478bd9Sstevel@tonic-gate 				f_outfile ? f_outfile :
735*7c478bd9Sstevel@tonic-gate 					gettext("standard output"));
736*7c478bd9Sstevel@tonic-gate 		} else {
737*7c478bd9Sstevel@tonic-gate 			(void) sprintf(errbuf,
738*7c478bd9Sstevel@tonic-gate 				gettext("%s error writing trailer to %s. "),
739*7c478bd9Sstevel@tonic-gate 				ar,
740*7c478bd9Sstevel@tonic-gate 				f_outfile ? f_outfile :
741*7c478bd9Sstevel@tonic-gate 					gettext("standard output"));
742*7c478bd9Sstevel@tonic-gate 		}
743*7c478bd9Sstevel@tonic-gate 		perror(errbuf);
744*7c478bd9Sstevel@tonic-gate 		return (-1);
745*7c478bd9Sstevel@tonic-gate 	}
746*7c478bd9Sstevel@tonic-gate 	return (0);
747*7c478bd9Sstevel@tonic-gate }
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate /*
751*7c478bd9Sstevel@tonic-gate  * .func  write_trailer - write audit file trailer.
752*7c478bd9Sstevel@tonic-gate  * .desc  Write an audit file trailer to the output stream. The finish
753*7c478bd9Sstevel@tonic-gate  *	time for the trailer is the time of the last record written
754*7c478bd9Sstevel@tonic-gate  *	to the stream.
755*7c478bd9Sstevel@tonic-gate  * .ret	0 - succesful write.
756*7c478bd9Sstevel@tonic-gate  * .ret	-1 - failed write - message printed.
757*7c478bd9Sstevel@tonic-gate  */
758*7c478bd9Sstevel@tonic-gate static int
759*7c478bd9Sstevel@tonic-gate write_trailer(void)
760*7c478bd9Sstevel@tonic-gate {
761*7c478bd9Sstevel@tonic-gate 	return (write_file_token(f_end));
762*7c478bd9Sstevel@tonic-gate }
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate /*
766*7c478bd9Sstevel@tonic-gate  * .func rename_outfile - rename the outfile.
767*7c478bd9Sstevel@tonic-gate  * .desc If the user used the -O flag they only gave us the suffix name
768*7c478bd9Sstevel@tonic-gate  *	for the outfile. We have to add the time stamps to put the filename
769*7c478bd9Sstevel@tonic-gate  *	in the proper audit file name format. The start time will be the time
770*7c478bd9Sstevel@tonic-gate  *	of the first record in the file and the end time will be the time of
771*7c478bd9Sstevel@tonic-gate  *	the last record in the file.
772*7c478bd9Sstevel@tonic-gate  * .ret	0 - rename succesful.
773*7c478bd9Sstevel@tonic-gate  * .ret	-1 - rename failed - message printed.
774*7c478bd9Sstevel@tonic-gate  */
775*7c478bd9Sstevel@tonic-gate static int
776*7c478bd9Sstevel@tonic-gate rename_outfile(void)
777*7c478bd9Sstevel@tonic-gate {
778*7c478bd9Sstevel@tonic-gate 	char	f_newfile[MAXFILELEN];
779*7c478bd9Sstevel@tonic-gate 	char	buf1[15], buf2[15];
780*7c478bd9Sstevel@tonic-gate 	char	*f_file, *f_nfile, *f_time, *f_name;
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	if (f_outfile != NULL) {
783*7c478bd9Sstevel@tonic-gate 		/*
784*7c478bd9Sstevel@tonic-gate 		 * Get string representations of start and end times.
785*7c478bd9Sstevel@tonic-gate 		 */
786*7c478bd9Sstevel@tonic-gate 		derive_str(f_start, buf1);
787*7c478bd9Sstevel@tonic-gate 		derive_str(f_end, buf2);
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 		f_nfile = f_time = f_newfile;	/* working copy */
790*7c478bd9Sstevel@tonic-gate 		f_file = f_name = f_outfile;	/* their version */
791*7c478bd9Sstevel@tonic-gate 		while (*f_file) {
792*7c478bd9Sstevel@tonic-gate 			if (*f_file == '/') {	/* look for filename */
793*7c478bd9Sstevel@tonic-gate 				f_time = f_nfile + 1;
794*7c478bd9Sstevel@tonic-gate 				f_name = f_file + 1;
795*7c478bd9Sstevel@tonic-gate 			}
796*7c478bd9Sstevel@tonic-gate 			*f_nfile++ = *f_file++;	/* make copy of their version */
797*7c478bd9Sstevel@tonic-gate 		}
798*7c478bd9Sstevel@tonic-gate 		*f_time = '\0';
799*7c478bd9Sstevel@tonic-gate 		/* start time goes first */
800*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_newfile, buf1);
801*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_newfile, ".");
802*7c478bd9Sstevel@tonic-gate 		/* then the finish time */
803*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_newfile, buf2);
804*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_newfile, ".");
805*7c478bd9Sstevel@tonic-gate 		/* and the name they gave us */
806*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_newfile, f_name);
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate #if AUDIT_FILE
809*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "rename_outfile: <%s> --> <%s>\n",
810*7c478bd9Sstevel@tonic-gate 			f_outfile, f_newfile);
811*7c478bd9Sstevel@tonic-gate #endif
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate #if AUDIT_RENAME
814*7c478bd9Sstevel@tonic-gate 		if (rename(f_outtemp, f_newfile) == -1) {
815*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
816*7c478bd9Sstevel@tonic-gate 			    "%s rename of %s to %s failed.\n",
817*7c478bd9Sstevel@tonic-gate 			    ar, f_outtemp, f_newfile);
818*7c478bd9Sstevel@tonic-gate 			return (-1);
819*7c478bd9Sstevel@tonic-gate 		}
820*7c478bd9Sstevel@tonic-gate 		f_outfile = f_newfile;
821*7c478bd9Sstevel@tonic-gate #else
822*7c478bd9Sstevel@tonic-gate 		if (rename(f_outtemp, f_outfile) == -1) {
823*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
824*7c478bd9Sstevel@tonic-gate 			    gettext("%s rename of %s to %s failed.\n"),
825*7c478bd9Sstevel@tonic-gate 			    ar, f_outtemp, f_outfile);
826*7c478bd9Sstevel@tonic-gate 			return (-1);
827*7c478bd9Sstevel@tonic-gate 		}
828*7c478bd9Sstevel@tonic-gate #endif
829*7c478bd9Sstevel@tonic-gate 	}
830*7c478bd9Sstevel@tonic-gate 	return (0);
831*7c478bd9Sstevel@tonic-gate }
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate /*
835*7c478bd9Sstevel@tonic-gate  * .func open_outfile - open the outfile.
836*7c478bd9Sstevel@tonic-gate  * .desc Open the outfile specified by the -O option. Assign it to the
837*7c478bd9Sstevel@tonic-gate  *	the standard output. Get a unique temporary name to use so we
838*7c478bd9Sstevel@tonic-gate  *	don't clobber an existing file.
839*7c478bd9Sstevel@tonic-gate  * .ret	0 - no errors detected.
840*7c478bd9Sstevel@tonic-gate  * .ret	-1 - errors in processing (message already printed).
841*7c478bd9Sstevel@tonic-gate  */
842*7c478bd9Sstevel@tonic-gate static int
843*7c478bd9Sstevel@tonic-gate open_outfile(void)
844*7c478bd9Sstevel@tonic-gate {
845*7c478bd9Sstevel@tonic-gate 	int	tmpfd = -1;
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	if (f_outfile != NULL) {
848*7c478bd9Sstevel@tonic-gate 		f_outtemp = (char *)a_calloc(1, strlen(f_outfile) + 8);
849*7c478bd9Sstevel@tonic-gate 		(void) strcpy(f_outtemp, f_outfile);
850*7c478bd9Sstevel@tonic-gate 		(void) strcat(f_outtemp, "XXXXXX");
851*7c478bd9Sstevel@tonic-gate 		if ((tmpfd = mkstemp(f_outtemp)) == -1) {
852*7c478bd9Sstevel@tonic-gate 			(void) sprintf(errbuf,
853*7c478bd9Sstevel@tonic-gate 			    gettext("%s couldn't create temporary file"), ar);
854*7c478bd9Sstevel@tonic-gate 			perror(errbuf);
855*7c478bd9Sstevel@tonic-gate 			return (-1);
856*7c478bd9Sstevel@tonic-gate 		}
857*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
858*7c478bd9Sstevel@tonic-gate 		if (tmpfd != fileno(stdout)) {
859*7c478bd9Sstevel@tonic-gate 			if ((dup2(tmpfd, fileno(stdout))) == -1) {
860*7c478bd9Sstevel@tonic-gate 				(void) sprintf(errbuf,
861*7c478bd9Sstevel@tonic-gate 				    gettext("%s can't assign %s to the "
862*7c478bd9Sstevel@tonic-gate 				    "standard output"), ar, f_outfile);
863*7c478bd9Sstevel@tonic-gate 				perror(errbuf);
864*7c478bd9Sstevel@tonic-gate 				return (-1);
865*7c478bd9Sstevel@tonic-gate 			}
866*7c478bd9Sstevel@tonic-gate 			(void) close(tmpfd);
867*7c478bd9Sstevel@tonic-gate 		}
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate 	return (0);
870*7c478bd9Sstevel@tonic-gate }
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate /*
874*7c478bd9Sstevel@tonic-gate  * .func init_options - initialize the options.
875*7c478bd9Sstevel@tonic-gate  * .desc Give initial and/or default values to some options.
876*7c478bd9Sstevel@tonic-gate  * .call init_options();
877*7c478bd9Sstevel@tonic-gate  * .arg	none.
878*7c478bd9Sstevel@tonic-gate  * .ret	void.
879*7c478bd9Sstevel@tonic-gate  */
880*7c478bd9Sstevel@tonic-gate static void
881*7c478bd9Sstevel@tonic-gate init_options(void)
882*7c478bd9Sstevel@tonic-gate {
883*7c478bd9Sstevel@tonic-gate 	struct timeval tp;
884*7c478bd9Sstevel@tonic-gate 	struct timezone tpz;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/*
887*7c478bd9Sstevel@tonic-gate 	 * Get current time for general use.
888*7c478bd9Sstevel@tonic-gate 	 */
889*7c478bd9Sstevel@tonic-gate 	if (gettimeofday(&tp, &tpz) == -1)
890*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: initial getttimeofday failed"));
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	time_now = tp.tv_sec;		/* save for general use */
893*7c478bd9Sstevel@tonic-gate 	f_start = 0;			/* first record time default */
894*7c478bd9Sstevel@tonic-gate 	f_end = time_now;		/* last record time default */
895*7c478bd9Sstevel@tonic-gate 	m_after = 0;			/* Jan 1, 1970 00:00:00 */
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	/*
898*7c478bd9Sstevel@tonic-gate 	 * Setup initial size of audit_pcbs[].
899*7c478bd9Sstevel@tonic-gate 	 */
900*7c478bd9Sstevel@tonic-gate 	pcbsize = PCB_INITSIZE;		/* initial size of file-holding pcb's */
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	audit_pcbs = (audit_pcb_t *)a_calloc(pcbsize, sizeof (audit_pcb_t));
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	/* description of 'current' error */
905*7c478bd9Sstevel@tonic-gate 	error_str = gettext("initial error");
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate }
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate /*
911*7c478bd9Sstevel@tonic-gate  * .func a_calloc - audit calloc.
912*7c478bd9Sstevel@tonic-gate  * .desc Calloc with check for failure. This is called by all of the
913*7c478bd9Sstevel@tonic-gate  *	places that want memory.
914*7c478bd9Sstevel@tonic-gate  * .call ptr = a_calloc(nelem, size).
915*7c478bd9Sstevel@tonic-gate  * .arg	nelem - number of elements to allocate.
916*7c478bd9Sstevel@tonic-gate  * .arg	size - size of each element.
917*7c478bd9Sstevel@tonic-gate  * .ret	ptr - ptr to allocated and zeroed memory.
918*7c478bd9Sstevel@tonic-gate  * .ret	never - if calloc fails then we never return.
919*7c478bd9Sstevel@tonic-gate  */
920*7c478bd9Sstevel@tonic-gate void	*
921*7c478bd9Sstevel@tonic-gate a_calloc(int nelem, size_t size)
922*7c478bd9Sstevel@tonic-gate {
923*7c478bd9Sstevel@tonic-gate 	void	*ptr;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	if ((ptr = calloc((unsigned)nelem, size)) == NULL) {
926*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: memory allocation failed"));
927*7c478bd9Sstevel@tonic-gate 		exit(1);
928*7c478bd9Sstevel@tonic-gate 	}
929*7c478bd9Sstevel@tonic-gate 	return (ptr);
930*7c478bd9Sstevel@tonic-gate }
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate /*
934*7c478bd9Sstevel@tonic-gate  * .func init_sig - initial signal catching.
935*7c478bd9Sstevel@tonic-gate  *
936*7c478bd9Sstevel@tonic-gate  * .desc
937*7c478bd9Sstevel@tonic-gate  *	Setup the signal catcher to catch the SIGCHLD signal plus
938*7c478bd9Sstevel@tonic-gate  *	"environmental" signals -- keyboard plus other externally
939*7c478bd9Sstevel@tonic-gate  *	generated signals such as out of file space or cpu time.  If a
940*7c478bd9Sstevel@tonic-gate  *	child exits with either a non-zero exit code or was killed by
941*7c478bd9Sstevel@tonic-gate  *	a signal to it then we will also exit with a non-zero exit
942*7c478bd9Sstevel@tonic-gate  *	code. In this way abnormal conditions can be passed up to the
943*7c478bd9Sstevel@tonic-gate  *	root process and the entire run be halted. Also catch the int
944*7c478bd9Sstevel@tonic-gate  *	and quit signals. Remove the output file since it is in an
945*7c478bd9Sstevel@tonic-gate  *	inconsistent state.
946*7c478bd9Sstevel@tonic-gate  * .call ret = init_sig().
947*7c478bd9Sstevel@tonic-gate  * .arg none.
948*7c478bd9Sstevel@tonic-gate  * .ret 0 - no errors detected.
949*7c478bd9Sstevel@tonic-gate  * .ret -1 - signal failed (message printed).
950*7c478bd9Sstevel@tonic-gate  */
951*7c478bd9Sstevel@tonic-gate static int
952*7c478bd9Sstevel@tonic-gate init_sig(void)
953*7c478bd9Sstevel@tonic-gate {
954*7c478bd9Sstevel@tonic-gate 	if (signal(SIGCHLD, chld_handler) == SIG_ERR) {
955*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGCHLD signal failed"));
956*7c478bd9Sstevel@tonic-gate 		return (-1);
957*7c478bd9Sstevel@tonic-gate 	}
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 	if (signal(SIGHUP, int_handler) == SIG_ERR) {
960*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGHUP signal failed"));
961*7c478bd9Sstevel@tonic-gate 		return (-1);
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 	if (signal(SIGINT, int_handler) == SIG_ERR) {
964*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGINT signal failed"));
965*7c478bd9Sstevel@tonic-gate 		return (-1);
966*7c478bd9Sstevel@tonic-gate 	}
967*7c478bd9Sstevel@tonic-gate 	if (signal(SIGQUIT, int_handler) == SIG_ERR) {
968*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGQUIT signal failed"));
969*7c478bd9Sstevel@tonic-gate 		return (-1);
970*7c478bd9Sstevel@tonic-gate 	}
971*7c478bd9Sstevel@tonic-gate 	if (signal(SIGABRT, int_handler) == SIG_ERR) {
972*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGABRT signal failed"));
973*7c478bd9Sstevel@tonic-gate 		return (-1);
974*7c478bd9Sstevel@tonic-gate 	}
975*7c478bd9Sstevel@tonic-gate 	if (signal(SIGTERM, int_handler) == SIG_ERR) {
976*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGTERM signal failed"));
977*7c478bd9Sstevel@tonic-gate 		return (-1);
978*7c478bd9Sstevel@tonic-gate 	}
979*7c478bd9Sstevel@tonic-gate 	if (signal(SIGPWR, int_handler) == SIG_ERR) {
980*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGPWR signal failed"));
981*7c478bd9Sstevel@tonic-gate 		return (-1);
982*7c478bd9Sstevel@tonic-gate 	}
983*7c478bd9Sstevel@tonic-gate 	if (signal(SIGXCPU, int_handler) == SIG_ERR) {
984*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGXCPU signal failed"));
985*7c478bd9Sstevel@tonic-gate 		return (-1);
986*7c478bd9Sstevel@tonic-gate 	}
987*7c478bd9Sstevel@tonic-gate 	if (signal(SIGXFSZ, int_handler) == SIG_ERR) {
988*7c478bd9Sstevel@tonic-gate 		perror(gettext("auditreduce: SIGXFSZ signal failed"));
989*7c478bd9Sstevel@tonic-gate 		return (-1);
990*7c478bd9Sstevel@tonic-gate 	}
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	return (0);
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate /*
997*7c478bd9Sstevel@tonic-gate  * .func chld_handler - handle child signals.
998*7c478bd9Sstevel@tonic-gate  * .desc Catch the SIGCHLD signals. Remove the root process
999*7c478bd9Sstevel@tonic-gate  *	output file because it is in an inconsistent state.
1000*7c478bd9Sstevel@tonic-gate  *	Print a message giving the signal number and/or return code
1001*7c478bd9Sstevel@tonic-gate  *	of the child who caused the signal.
1002*7c478bd9Sstevel@tonic-gate  * .ret	void.
1003*7c478bd9Sstevel@tonic-gate  */
1004*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1005*7c478bd9Sstevel@tonic-gate void
1006*7c478bd9Sstevel@tonic-gate chld_handler(int sig)
1007*7c478bd9Sstevel@tonic-gate {
1008*7c478bd9Sstevel@tonic-gate 	int	pid;
1009*7c478bd9Sstevel@tonic-gate 	int	status;
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	/*
1012*7c478bd9Sstevel@tonic-gate 	 * Get pid and reasons for cause of event.
1013*7c478bd9Sstevel@tonic-gate 	 */
1014*7c478bd9Sstevel@tonic-gate 	pid = wait(&status);
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	if (pid > 0) {
1017*7c478bd9Sstevel@tonic-gate 		/*
1018*7c478bd9Sstevel@tonic-gate 		 * If child received a signal or exited with a non-zero
1019*7c478bd9Sstevel@tonic-gate 		 * exit status then print message and exit
1020*7c478bd9Sstevel@tonic-gate 		 */
1021*7c478bd9Sstevel@tonic-gate 		if ((WHIBYTE(status) == 0 && WLOBYTE(status) != 0) ||
1022*7c478bd9Sstevel@tonic-gate 		    (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)) {
1023*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1024*7c478bd9Sstevel@tonic-gate 			    gettext("%s abnormal child termination - "), ar);
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 			if (WHIBYTE(status) == 0 && WLOBYTE(status) != 0) {
1027*7c478bd9Sstevel@tonic-gate 				psignal(WLOBYTE(status), "signal");
1028*7c478bd9Sstevel@tonic-gate 				if (WCOREDUMP(status))
1029*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
1030*7c478bd9Sstevel@tonic-gate 					    gettext("core dumped\n"));
1031*7c478bd9Sstevel@tonic-gate 			}
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 			if (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)
1034*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1035*7c478bd9Sstevel@tonic-gate 					"return code %d\n"),
1036*7c478bd9Sstevel@tonic-gate 					WHIBYTE(status));
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 			/*
1039*7c478bd9Sstevel@tonic-gate 			 * Get rid of outfile - it is suspect.
1040*7c478bd9Sstevel@tonic-gate 			 */
1041*7c478bd9Sstevel@tonic-gate 			if (f_outfile != NULL) {
1042*7c478bd9Sstevel@tonic-gate 				(void) close_outfile();
1043*7c478bd9Sstevel@tonic-gate 				rm_outfile();
1044*7c478bd9Sstevel@tonic-gate 			}
1045*7c478bd9Sstevel@tonic-gate 			/*
1046*7c478bd9Sstevel@tonic-gate 			 * Give statistical info that may be useful.
1047*7c478bd9Sstevel@tonic-gate 			 */
1048*7c478bd9Sstevel@tonic-gate 			audit_stats();
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 			exit(1);
1051*7c478bd9Sstevel@tonic-gate 		}
1052*7c478bd9Sstevel@tonic-gate 	}
1053*7c478bd9Sstevel@tonic-gate }
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate /*
1057*7c478bd9Sstevel@tonic-gate  * .func	int_handler - handle quit/int signals.
1058*7c478bd9Sstevel@tonic-gate  * .desc	Catch the keyboard and other environmental signals.
1059*7c478bd9Sstevel@tonic-gate  *		Remove the root process output file because it is in
1060*7c478bd9Sstevel@tonic-gate  *		an inconsistent state.
1061*7c478bd9Sstevel@tonic-gate  * .ret	void.
1062*7c478bd9Sstevel@tonic-gate  */
1063*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1064*7c478bd9Sstevel@tonic-gate void
1065*7c478bd9Sstevel@tonic-gate int_handler(int sig)
1066*7c478bd9Sstevel@tonic-gate {
1067*7c478bd9Sstevel@tonic-gate 	if (getpid() == root_pid) {
1068*7c478bd9Sstevel@tonic-gate 		(void) close_outfile();
1069*7c478bd9Sstevel@tonic-gate 		rm_outfile();
1070*7c478bd9Sstevel@tonic-gate 		exit(1);
1071*7c478bd9Sstevel@tonic-gate 	}
1072*7c478bd9Sstevel@tonic-gate 	/*
1073*7c478bd9Sstevel@tonic-gate 	 * For a child process don't give an error exit or the
1074*7c478bd9Sstevel@tonic-gate 	 * parent process will catch it with the chld_handler and
1075*7c478bd9Sstevel@tonic-gate 	 * try to erase the outfile again.
1076*7c478bd9Sstevel@tonic-gate 	 */
1077*7c478bd9Sstevel@tonic-gate 	exit(0);
1078*7c478bd9Sstevel@tonic-gate }
1079