xref: /illumos-gate/usr/src/cmd/acct/acctmerg.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 /*
26  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 /*
32  *	acctmerg [-a] [-i] [-p] [-t] [-u] [-v] [file...]
33  *	-a	output in tacct.h/ascii (instead of tacct.h)
34  *	-i	input is in tacct.h/ascii (instead of tacct.h)
35  *	-p	print input files with no processing
36  *	-t	output single record that totals all input
37  *	-u	summarize by uid, rather than uid/name
38  *	-v	output in verbose tacct.h/ascii
39  *	reads std input and 0-NFILE files, all in tacct.h format,
40  *	sorted by uid/name.
41  *	merge/adds all records with same uid/name (or same uid if -u,
42  *	or all records if -t], writes to std. output
43  *	(still in tacct.h format)
44  *	note that this can be used to summarize the std input
45  */
46 
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <sys/param.h>
50 #include "acctdef.h"
51 #include <stdlib.h>
52 
53 int	nfile;			/* index of last used in fl */
54 FILE	*fl[NFILE]	= {stdin};
55 
56 struct	tacct tb[NFILE];	/* current record from each file */
57 struct	tacct	tt = {
58 	0,
59 	"TOTAL"
60 };
61 int	asciiout;
62 int	asciiinp;
63 int	printonly;
64 int	totalonly;
65 int	uidsum;
66 int	verbose;
67 
68 int 	exitcode = 0;
69 
70 void prtacct(struct tacct *);
71 struct tacct *getleast(void);
72 void output(struct tacct *);
73 void tacctadd(struct tacct *, struct tacct *);
74 void sumcurr(struct tacct *);
75 
76 int
77 main(int argc, char **argv)
78 {
79 	int i;
80 	struct tacct *tp;
81 
82 	while (--argc > 0) {
83 		if (**++argv == '-')
84 			switch (*++*argv) {
85 			case 'a':
86 				asciiout++;
87 				continue;
88 			case 'i':
89 				asciiinp++;
90 				continue;
91 			case 'p':
92 				printonly++;
93 				continue;
94 			case 't':
95 				totalonly++;
96 				continue;
97 			case 'u':
98 				uidsum++;
99 				continue;
100 			case 'v':
101 				verbose++;
102 				asciiout++;
103 				continue;
104 			}
105 		else {
106 			if (++nfile >= NFILE) {
107 				fprintf(stderr, "acctmerg: >%d files\n", NFILE);
108 				exit(1);
109 			}
110 			if ((fl[nfile] = fopen(*argv, "r")) == NULL) {
111 				fprintf(stderr, "acctmerg: can't open %s\n", *argv);
112 				exitcode = 1;
113 				/*	exit(1); 	*/
114 			}
115 		}
116 	}
117 
118 	if (printonly) {
119 		for (i = 0; i <= nfile; i++)
120 			while (getnext(i))
121 				prtacct(&tb[i]);
122 		exit(exitcode);
123 	}
124 
125 	for (i = 0; i <= nfile; i++)
126 		if(getnext(i) == 0) {
127 			fprintf(stderr,"acctmerg: read error file %d.  File may be empty.\n", i);
128 			exitcode = 2;
129 
130 		}
131 
132 	while ((tp = getleast()) != NULL)	/* get least uid of all files, */
133 		sumcurr(tp);			/* sum all entries for that uid, */
134 	if (totalonly)				/* and write the 'summed' record */
135 		output(&tt);
136 
137 	exit(exitcode);
138 }
139 
140 /*
141  *	getleast returns ptr to least (lowest uid)  element of current
142  *	avail, NULL if none left; always returns 1st of equals
143  */
144 struct tacct *
145 getleast(void)
146 {
147 	struct tacct *tp, *least;
148 
149 	least = NULL;
150 	for (tp = tb; tp <= &tb[nfile]; tp++) {
151 		if (tp->ta_name[0] == '\0')
152 			continue;
153 		if (least == NULL ||
154 			tp->ta_uid < least->ta_uid ||
155 			((tp->ta_uid == least->ta_uid) &&
156 			!uidsum &&
157 			(strncmp(tp->ta_name, least->ta_name, NSZ) < 0)))
158 			least = tp;
159 	}
160 	return(least);
161 }
162 
163 /*
164  *	sumcurr sums all entries with same uid/name (into tp->tacct record)
165  *	writes it out, gets new entry
166  */
167 void
168 sumcurr(struct tacct *tp)
169 {
170 	struct tacct tc;
171 	char *memcpy();
172 
173 	memcpy(&tc, tp, sizeof(struct tacct));
174 	tacctadd(&tt, tp);	/* gets total of all uids */
175 	getnext(tp-&tb[0]);	/* get next one in same file */
176 	while (tp <= &tb[nfile])
177 		if (tp->ta_name[0] != '\0' &&
178 			tp->ta_uid == tc.ta_uid &&
179 			(uidsum || EQN(tp->ta_name, tc.ta_name))) {
180 			tacctadd(&tc, tp);
181 			tacctadd(&tt, tp);
182 			getnext(tp-&tb[0]);
183 		} else
184 			tp++;	/* look at next file */
185 	if (!totalonly)
186 		output(&tc);
187 }
188 
189 void
190 tacctadd(struct tacct *t1, struct tacct *t2)
191 {
192 	t1->ta_cpu[0] = t1->ta_cpu[0] + t2->ta_cpu[0];
193 	t1->ta_cpu[1] = t1->ta_cpu[1] + t2->ta_cpu[1];
194 	t1->ta_kcore[0] = t1->ta_kcore[0] + t2->ta_kcore[0];
195 	t1->ta_kcore[1] = t1->ta_kcore[1] + t2->ta_kcore[1];
196 	t1->ta_con[0] = t1->ta_con[0] + t2->ta_con[0];
197 	t1->ta_con[1] = t1->ta_con[1] + t2->ta_con[1];
198 	t1->ta_du = t1->ta_du + t2->ta_du;
199 	t1->ta_pc += t2->ta_pc;
200 	t1->ta_sc += t2->ta_sc;
201 	t1->ta_dc += t2->ta_dc;
202 	t1->ta_fee += t2->ta_fee;
203 }
204 
205 void
206 output(struct tacct *tp)
207 {
208 	if (asciiout)
209 		prtacct(tp);
210 	else
211 		fwrite(tp, sizeof(*tp), 1, stdout);
212 }
213 
214 /*
215  *	getnext reads next record from stream i, returns 1 if one existed
216  */
217 int
218 getnext(int i)
219 {
220 	struct tacct *tp;
221 
222 	tp = &tb[i];
223 	tp->ta_name[0] = '\0';
224 	if (fl[i] == NULL)
225 		return(0);
226 	if (asciiinp) {
227 		if (fscanf(fl[i],
228 			"%ld\t%s\t%e %e %e %e %e %e %e %lu\t%hu\t%hu\t%hu",
229 			&tp->ta_uid,
230 			tp->ta_name,
231 			&tp->ta_cpu[0], &tp->ta_cpu[1],
232 			&tp->ta_kcore[0], &tp->ta_kcore[1],
233 			&tp->ta_con[0], &tp->ta_con[1],
234 			&tp->ta_du,
235 			&tp->ta_pc,
236 			&tp->ta_sc,
237 			&tp->ta_dc,
238 			&tp->ta_fee) != EOF)
239 			return(1);
240 	} else {
241 		if (fread(tp, sizeof(*tp), 1, fl[i]) == 1)
242 			return(1);
243 	}
244 	fclose(fl[i]);
245 	fl[i] = NULL;
246 	return(0);
247 }
248 
249 char fmt[] = "%ld\t%.*s\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%lu\t%hu\t%hu\t%hu\n";
250 char fmtv[] = "%ld\t%.*s\t%e %e %e %e %e %e %e %lu %hu\t%hu\t%hu\n";
251 
252 void
253 prtacct(struct tacct *tp)
254 {
255 	printf(verbose ? fmtv : fmt,
256 	    tp->ta_uid,
257 	    OUTPUT_NSZ,
258 	    tp->ta_name,
259 	    tp->ta_cpu[0], tp->ta_cpu[1],
260 	    tp->ta_kcore[0], tp->ta_kcore[1],
261 	    tp->ta_con[0], tp->ta_con[1],
262 	    tp->ta_du,
263 	    tp->ta_pc,
264 	    tp->ta_sc,
265 	    tp->ta_dc,
266 	    tp->ta_fee);
267 }
268