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