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
main(int argc,char ** argv)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 *
getleast(void)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
sumcurr(struct tacct * tp)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
tacctadd(struct tacct * t1,struct tacct * t2)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
output(struct tacct * tp)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
getnext(int i)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
prtacct(struct tacct * tp)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