xref: /illumos-gate/usr/src/cmd/acct/acctmerg.c (revision 2a8bcb4e)
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 
30 /*
31  *	acctmerg [-a] [-i] [-p] [-t] [-u] [-v] [file...]
32  *	-a	output in tacct.h/ascii (instead of tacct.h)
33  *	-i	input is in tacct.h/ascii (instead of tacct.h)
34  *	-p	print input files with no processing
35  *	-t	output single record that totals all input
36  *	-u	summarize by uid, rather than uid/name
37  *	-v	output in verbose tacct.h/ascii
38  *	reads std input and 0-NFILE files, all in tacct.h format,
39  *	sorted by uid/name.
40  *	merge/adds all records with same uid/name (or same uid if -u,
41  *	or all records if -t], writes to std. output
42  *	(still in tacct.h format)
43  *	note that this can be used to summarize the std input
44  */
45 
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include "acctdef.h"
50 #include <stdlib.h>
51 
52 int	nfile;			/* index of last used in fl */
53 FILE	*fl[NFILE]	= {stdin};
54 
55 struct	tacct tb[NFILE];	/* current record from each file */
56 struct	tacct	tt = {
57 	0,
58 	"TOTAL"
59 };
60 int	asciiout;
61 int	asciiinp;
62 int	printonly;
63 int	totalonly;
64 int	uidsum;
65 int	verbose;
66 
67 int 	exitcode = 0;
68 
69 void prtacct(struct tacct *);
70 struct tacct *getleast(void);
71 void output(struct tacct *);
72 void tacctadd(struct tacct *, struct tacct *);
73 void sumcurr(struct tacct *);
74 
75 int
main(int argc,char ** argv)76 main(int argc, char **argv)
77 {
78 	int i;
79 	struct tacct *tp;
80 
81 	while (--argc > 0) {
82 		if (**++argv == '-')
83 			switch (*++*argv) {
84 			case 'a':
85 				asciiout++;
86 				continue;
87 			case 'i':
88 				asciiinp++;
89 				continue;
90 			case 'p':
91 				printonly++;
92 				continue;
93 			case 't':
94 				totalonly++;
95 				continue;
96 			case 'u':
97 				uidsum++;
98 				continue;
99 			case 'v':
100 				verbose++;
101 				asciiout++;
102 				continue;
103 			}
104 		else {
105 			if (++nfile >= NFILE) {
106 				fprintf(stderr, "acctmerg: >%d files\n", NFILE);
107 				exit(1);
108 			}
109 			if ((fl[nfile] = fopen(*argv, "r")) == NULL) {
110 				fprintf(stderr, "acctmerg: can't open %s\n", *argv);
111 				exitcode = 1;
112 				/*	exit(1); 	*/
113 			}
114 		}
115 	}
116 
117 	if (printonly) {
118 		for (i = 0; i <= nfile; i++)
119 			while (getnext(i))
120 				prtacct(&tb[i]);
121 		exit(exitcode);
122 	}
123 
124 	for (i = 0; i <= nfile; i++)
125 		if(getnext(i) == 0) {
126 			fprintf(stderr,"acctmerg: read error file %d.  File may be empty.\n", i);
127 			exitcode = 2;
128 
129 		}
130 
131 	while ((tp = getleast()) != NULL)	/* get least uid of all files, */
132 		sumcurr(tp);			/* sum all entries for that uid, */
133 	if (totalonly)				/* and write the 'summed' record */
134 		output(&tt);
135 
136 	exit(exitcode);
137 }
138 
139 /*
140  *	getleast returns ptr to least (lowest uid)  element of current
141  *	avail, NULL if none left; always returns 1st of equals
142  */
143 struct tacct *
getleast(void)144 getleast(void)
145 {
146 	struct tacct *tp, *least;
147 
148 	least = NULL;
149 	for (tp = tb; tp <= &tb[nfile]; tp++) {
150 		if (tp->ta_name[0] == '\0')
151 			continue;
152 		if (least == NULL ||
153 			tp->ta_uid < least->ta_uid ||
154 			((tp->ta_uid == least->ta_uid) &&
155 			!uidsum &&
156 			(strncmp(tp->ta_name, least->ta_name, NSZ) < 0)))
157 			least = tp;
158 	}
159 	return(least);
160 }
161 
162 /*
163  *	sumcurr sums all entries with same uid/name (into tp->tacct record)
164  *	writes it out, gets new entry
165  */
166 void
sumcurr(struct tacct * tp)167 sumcurr(struct tacct *tp)
168 {
169 	struct tacct tc;
170 	char *memcpy();
171 
172 	memcpy(&tc, tp, sizeof(struct tacct));
173 	tacctadd(&tt, tp);	/* gets total of all uids */
174 	getnext(tp-&tb[0]);	/* get next one in same file */
175 	while (tp <= &tb[nfile])
176 		if (tp->ta_name[0] != '\0' &&
177 			tp->ta_uid == tc.ta_uid &&
178 			(uidsum || EQN(tp->ta_name, tc.ta_name))) {
179 			tacctadd(&tc, tp);
180 			tacctadd(&tt, tp);
181 			getnext(tp-&tb[0]);
182 		} else
183 			tp++;	/* look at next file */
184 	if (!totalonly)
185 		output(&tc);
186 }
187 
188 void
tacctadd(struct tacct * t1,struct tacct * t2)189 tacctadd(struct tacct *t1, struct tacct *t2)
190 {
191 	t1->ta_cpu[0] = t1->ta_cpu[0] + t2->ta_cpu[0];
192 	t1->ta_cpu[1] = t1->ta_cpu[1] + t2->ta_cpu[1];
193 	t1->ta_kcore[0] = t1->ta_kcore[0] + t2->ta_kcore[0];
194 	t1->ta_kcore[1] = t1->ta_kcore[1] + t2->ta_kcore[1];
195 	t1->ta_con[0] = t1->ta_con[0] + t2->ta_con[0];
196 	t1->ta_con[1] = t1->ta_con[1] + t2->ta_con[1];
197 	t1->ta_du = t1->ta_du + t2->ta_du;
198 	t1->ta_pc += t2->ta_pc;
199 	t1->ta_sc += t2->ta_sc;
200 	t1->ta_dc += t2->ta_dc;
201 	t1->ta_fee += t2->ta_fee;
202 }
203 
204 void
output(struct tacct * tp)205 output(struct tacct *tp)
206 {
207 	if (asciiout)
208 		prtacct(tp);
209 	else
210 		fwrite(tp, sizeof(*tp), 1, stdout);
211 }
212 
213 /*
214  *	getnext reads next record from stream i, returns 1 if one existed
215  */
216 int
getnext(int i)217 getnext(int i)
218 {
219 	struct tacct *tp;
220 
221 	tp = &tb[i];
222 	tp->ta_name[0] = '\0';
223 	if (fl[i] == NULL)
224 		return(0);
225 	if (asciiinp) {
226 		if (fscanf(fl[i],
227 			"%ld\t%s\t%e %e %e %e %e %e %e %lu\t%hu\t%hu\t%hu",
228 			&tp->ta_uid,
229 			tp->ta_name,
230 			&tp->ta_cpu[0], &tp->ta_cpu[1],
231 			&tp->ta_kcore[0], &tp->ta_kcore[1],
232 			&tp->ta_con[0], &tp->ta_con[1],
233 			&tp->ta_du,
234 			&tp->ta_pc,
235 			&tp->ta_sc,
236 			&tp->ta_dc,
237 			&tp->ta_fee) != EOF)
238 			return(1);
239 	} else {
240 		if (fread(tp, sizeof(*tp), 1, fl[i]) == 1)
241 			return(1);
242 	}
243 	fclose(fl[i]);
244 	fl[i] = NULL;
245 	return(0);
246 }
247 
248 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";
249 char fmtv[] = "%ld\t%.*s\t%e %e %e %e %e %e %e %lu %hu\t%hu\t%hu\n";
250 
251 void
prtacct(struct tacct * tp)252 prtacct(struct tacct *tp)
253 {
254 	printf(verbose ? fmtv : fmt,
255 	    tp->ta_uid,
256 	    OUTPUT_NSZ,
257 	    tp->ta_name,
258 	    tp->ta_cpu[0], tp->ta_cpu[1],
259 	    tp->ta_kcore[0], tp->ta_kcore[1],
260 	    tp->ta_con[0], tp->ta_con[1],
261 	    tp->ta_du,
262 	    tp->ta_pc,
263 	    tp->ta_sc,
264 	    tp->ta_dc,
265 	    tp->ta_fee);
266 }
267