BSD 3 development
[unix-history] / usr / src / cmd / sa.c
CommitLineData
d5165122
BJ
1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/acct.h>
4#include <signal.h>
5
6/* interpret command time accounting */
7
8#define size 2500
9#define NC sizeof(acctbuf.ac_comm)
10struct acct acctbuf;
11int lflg;
12int cflg;
13int iflg;
14int jflg;
15int nflg;
16int aflg;
17int rflg;
18int oflg;
19int tflg;
20int vflg;
21int uflg;
22int thres = 1;
23int sflg;
24int bflg;
25int mflg;
26
27struct user {
28 int ncomm;
29 int fill;
30 float fctime;
31} user[1000];
32
33struct tab {
34 char name[NC];
35 int count;
36 float realt;
37 float cput;
38 float syst;
39} tab[size];
40
41float treal;
42float tcpu;
43float tsys;
44int junkp = -1;
45char *sname;
46float ncom;
47time_t expand();
48
49main(argc, argv)
50char **argv;
51{
52 FILE *ff;
53 int i, j, k;
54 extern tcmp(), ncmp(), bcmp();
55 extern float sum();
56 float ft;
57
58 if (argc>1)
59 if (argv[1][0]=='-') {
60 argv++;
61 argc--;
62 for(i=1; argv[0][i]; i++)
63 switch(argv[0][i]) {
64
65 case 'o':
66 oflg++;
67 break;
68
69 case 'i':
70 iflg++;
71 break;
72
73 case 'b':
74 bflg++;
75 break;
76
77 case 'l':
78 lflg++;
79 break;
80
81 case 'c':
82 cflg++;
83 break;
84
85 case 'j':
86 jflg++;
87 break;
88
89 case 'n':
90 nflg++;
91 break;
92
93 case 'a':
94 aflg++;
95 break;
96
97 case 'r':
98 rflg++;
99 break;
100
101 case 't':
102 tflg++;
103 break;
104
105 case 's':
106 sflg++;
107 aflg++;
108 break;
109
110 case '0':
111 case '1':
112 case '2':
113 case '3':
114 case '4':
115 case '5':
116 case '6':
117 case '7':
118 case '8':
119 case '9':
120 thres = argv[0][i]-'0';
121 break;
122
123 case 'v':
124 vflg++;
125 break;
126
127 case 'u':
128 uflg++;
129 break;
130
131 case 'm':
132 mflg++;
133 break;
134 }
135 }
136 if (iflg==0)
137 init();
138 if (argc<2)
139 doacct("/usr/adm/acct");
140 else while (--argc)
141 doacct(*++argv);
142 if (uflg) {
143 return;
144 }
145
146/*
147 * cleanup pass
148 * put junk together
149 */
150
151 if (vflg)
152 strip();
153 if(!aflg)
154 for (i=0; i<size; i++)
155 if (tab[i].name[0]) {
156 for(j=0; j<NC; j++)
157 if(tab[i].name[j] == '?')
158 goto yes;
159 if(tab[i].count != 1)
160 continue;
161 yes:
162 if(junkp == -1)
163 junkp = enter("***other");
164 tab[junkp].count += tab[i].count;
165 tab[junkp].realt += tab[i].realt;
166 tab[junkp].cput += tab[i].cput;
167 tab[junkp].syst += tab[i].syst;
168 tab[i].name[0] = 0;
169 }
170 for(i=k=0; i<size; i++)
171 if(tab[i].name[0]) {
172 for(j=0; j<NC; j++)
173 tab[k].name[j] = tab[i].name[j];
174 tab[k].count = tab[i].count;
175 tab[k].realt = tab[i].realt;
176 tab[k].cput = tab[i].cput;
177 tab[k].syst = tab[i].syst;
178 k++;
179 }
180 if (sflg) {
181 signal(SIGINT, SIG_IGN);
182 if ((ff = fopen("/usr/adm/usracct", "w")) != NULL) {
183 fwrite((char *)user, sizeof(user), 1, ff);
184 fclose(ff);
185 }
186 if ((ff = fopen("/usr/adm/savacct", "w")) == NULL) {
187 printf("Can't save\n");
188 exit(0);
189 }
190 fwrite((char *)tab, sizeof(tab[0]), k, ff);
191 fclose(ff);
192 creat("/usr/adm/acct", 0644);
193 signal(SIGINT, SIG_DFL);
194 }
195/*
196 * sort and print
197 */
198
199 if (mflg) {
200 printmoney();
201 exit(0);
202 }
203 qsort(tab, k, sizeof(tab[0]), nflg? ncmp: (bflg?bcmp:tcmp));
204 column(ncom, treal, tcpu, tsys);
205 printf("\n");
206 for (i=0; i<k; i++)
207 if (tab[i].name[0]) {
208 ft = tab[i].count;
209 column(ft, tab[i].realt, tab[i].cput, tab[i].syst);
210 printf(" %.14s\n", tab[i].name);
211 }
212}
213
214printmoney()
215{
216 register i;
217 char buf[128];
218 register char *cp;
219
220 for (i=0; i<256; i++) {
221 if (user[i].ncomm) {
222 if (getpw(i, buf)!=0)
223 printf("%-8d", i);
224 else {
225 cp = buf;
226 while (*cp!=':' &&*cp!='\n' && *cp)
227 cp++;
228 *cp = 0;
229 printf("%-8s", buf);
230 }
231 printf("%7u %9.2f\n",
232 user[i].ncomm, user[i].fctime/60);
233 }
234 }
235}
236
237column(n, a, b, c)
238double n, a, b, c;
239{
240
241 printf("%8.0f", n);
242 if(cflg) {
243 if(n == ncom)
244 printf("%9s", ""); else
245 printf("%8.2f%%", 100.*n/ncom);
246 }
247 col(n, a, treal);
248 if (oflg)
249 col(n, 3600*(b/(b+c)), tcpu+tsys);
250 else if(lflg) {
251 col(n, b, tcpu);
252 col(n, c, tsys);
253 } else
254 col(n, b+c, tcpu+tsys);
255 if(tflg)
256 printf("%8.1f", a/(b+c));
257}
258
259col(n, a, m)
260double n, a, m;
261{
262
263 if(jflg)
264 printf("%11.2f", a/(n*60.)); else
265 printf("%11.2f", a/3600.);
266 if(cflg) {
267 if(a == m)
268 printf("%9s", ""); else
269 printf("%8.2f%%", 100.*a/m);
270 }
271}
272
273doacct(f)
274char *f;
275{
276 int i;
277 FILE *ff;
278 long x;
279 struct acct fbuf;
280 register char *cp;
281 register int c;
282
283 if (sflg && sname) {
284 printf("Only 1 file with -s\n");
285 exit(0);
286 }
287 if (sflg)
288 sname = f;
289 if ((ff = fopen(f, "r"))==NULL) {
290 printf("Can't open %s\n", f);
291 return;
292 }
293 while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) {
294 if (fbuf.ac_comm[0]==0) {
295 fbuf.ac_comm[0] = '?';
296 }
297 for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) {
298 c = *cp & 0377;
299 if (c && (c < ' ' || c >= 0200)) {
300 *cp = '?';
301 }
302 }
303 if (fbuf.ac_flag&AFORK) {
304 for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++)
305 if (*cp==0) {
306 *cp = '*';
307 break;
308 }
309 }
310 x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime);
311 if (uflg) {
312 printf("%3d%6.1f %.14s\n", fbuf.ac_uid&0377, x/60.0,
313 fbuf.ac_comm);
314 continue;
315 }
316 c = fbuf.ac_uid&0377;
317 user[c].ncomm++;
318 user[c].fctime += x/60.;
319 ncom += 1.0;
320 i = enter(fbuf.ac_comm);
321 tab[i].count++;
322 x = expand(fbuf.ac_etime)*60;
323 tab[i].realt += x;
324 treal += x;
325 x = expand(fbuf.ac_utime);
326 tab[i].cput += x;
327 tcpu += x;
328 x = expand(fbuf.ac_stime);
329 tab[i].syst += x;
330 tsys += x;
331 }
332 fclose(ff);
333}
334
335ncmp(p1, p2)
336struct tab *p1, *p2;
337{
338
339 if(p1->count == p2->count)
340 return(tcmp(p1, p2));
341 if(rflg)
342 return(p1->count - p2->count);
343 return(p2->count - p1->count);
344}
345
346bcmp(p1, p2)
347struct tab *p1, *p2;
348{
349 float f1, f2;
350 float sum();
351
352 f1 = sum(p1)/p1->count;
353 f2 = sum(p2)/p2->count;
354 if(f1 < f2) {
355 if(rflg)
356 return(-1);
357 return(1);
358 }
359 if(f1 > f2) {
360 if(rflg)
361 return(1);
362 return(-1);
363 }
364 return(0);
365}
366tcmp(p1, p2)
367struct tab *p1, *p2;
368{
369 extern float sum();
370 float f1, f2;
371
372 f1 = sum(p1);
373 f2 = sum(p2);
374 if(f1 < f2) {
375 if(rflg)
376 return(-1);
377 return(1);
378 }
379 if(f1 > f2) {
380 if(rflg)
381 return(1);
382 return(-1);
383 }
384 return(0);
385}
386
387float sum(p)
388struct tab *p;
389{
390
391 if(p->name[0] == 0)
392 return(0.0);
393 return(
394 p->cput+
395 p->syst);
396}
397
398init()
399{
400 struct tab tbuf;
401 int i;
402 FILE *f;
403
404 if ((f = fopen("/usr/adm/savacct", "r")) == NULL)
405 goto gshm;
406 while (fread((char *)&tbuf, sizeof(tbuf), 1, f) == 1) {
407 i = enter(tbuf.name);
408 ncom += tbuf.count;
409 tab[i].count = tbuf.count;
410 treal += tbuf.realt;
411 tab[i].realt = tbuf.realt;
412 tcpu += tbuf.cput;
413 tab[i].cput = tbuf.cput;
414 tsys += tbuf.syst;
415 tab[i].syst = tbuf.syst;
416 }
417 fclose(f);
418 gshm:
419 if ((f = fopen("/usr/adm/usracct", "r")) == NULL)
420 return;
421 fread((char *)user, sizeof(user), 1, f);
422 fclose(f);
423}
424
425enter(np)
426char *np;
427{
428 int i, j;
429
430 for (i=j=0; i<NC; i++) {
431 if (np[i]==0)
432 j = i;
433 if (j)
434 np[i] = 0;
435 }
436 for (i=j=0; j<NC; j++) {
437 i = i*7 + np[j];
438 }
439 if (i < 0)
440 i = -i;
441 for (i%=size; tab[i].name[0]; i = (i+1)%size) {
442 for (j=0; j<NC; j++)
443 if (tab[i].name[j]!=np[j])
444 goto no;
445 goto yes;
446 no:;
447 }
448 for (j=0; j<NC; j++)
449 tab[i].name[j] = np[j];
450yes:
451 return(i);
452}
453
454strip()
455{
456 int i, j, c;
457
458 j = enter("**junk**");
459 for (i = 0; i<size; i++) {
460 if (tab[i].name[0] && tab[i].count<=thres) {
461 printf("%.14s--", tab[i].name);
462 if ((c=getchar())=='y') {
463 tab[i].name[0] = '\0';
464 tab[j].count += tab[i].count;
465 tab[j].realt += tab[i].realt;
466 tab[j].cput += tab[i].cput;
467 tab[j].syst += tab[i].syst;
468 }
469 while (c && c!='\n')
470 c = getchar();
471 }
472 }
473}
474
475time_t
476expand(t)
477unsigned t;
478{
479 register time_t nt;
480
481 nt = t&017777;
482 t >>= 13;
483 while (t!=0) {
484 t--;
485 nt <<= 3;
486 }
487 return(nt);
488}