Commit | Line | Data |
---|---|---|
31cef89c | 1 | static char *sccsid = "@(#)sa.c 4.1 (Berkeley) 10/1/80"; |
2efccdb1 BJ |
2 | #include <stdio.h> |
3 | #include <sys/types.h> | |
4 | #include <sys/acct.h> | |
5 | #include <signal.h> | |
6 | ||
7 | /* interpret command time accounting */ | |
8 | ||
9 | #define size 2500 | |
10 | #define NC sizeof(acctbuf.ac_comm) | |
11 | struct acct acctbuf; | |
12 | int lflg; | |
13 | int cflg; | |
14 | int Dflg; | |
15 | int dflg; | |
16 | int iflg; | |
17 | int jflg; | |
18 | int Kflg; | |
19 | int kflg; | |
20 | int nflg; | |
21 | int aflg; | |
22 | int rflg; | |
23 | int oflg; | |
24 | int tflg; | |
25 | int vflg; | |
26 | int uflg; | |
27 | int thres = 1; | |
28 | int sflg; | |
29 | int bflg; | |
30 | int mflg; | |
31 | ||
32 | struct user { | |
33 | int us_cnt; | |
34 | double us_ctime; | |
35 | double us_io; | |
36 | double us_imem; | |
37 | } user[1000]; | |
38 | ||
39 | struct tab { | |
40 | char name[NC]; | |
41 | int count; | |
42 | double realt; | |
43 | double cput; | |
44 | double syst; | |
45 | double imem; | |
46 | double io; | |
47 | } tab[size]; | |
48 | ||
49 | double treal; | |
50 | double tcpu; | |
51 | double tsys; | |
52 | double tio; | |
53 | double timem; | |
54 | int junkp = -1; | |
55 | char *sname; | |
56 | double ncom; | |
57 | time_t expand(); | |
58 | char *getname(); | |
59 | ||
60 | main(argc, argv) | |
61 | char **argv; | |
62 | { | |
63 | FILE *ff; | |
64 | int i, j, k; | |
65 | int (*cmp)(); | |
66 | extern tcmp(), ncmp(), bcmp(), dcmp(), Dcmp(), kcmp(), Kcmp(); | |
67 | extern double sum(); | |
68 | double ft; | |
69 | ||
70 | cmp = tcmp; | |
71 | if (argc>1) | |
72 | if (argv[1][0]=='-') { | |
73 | argv++; | |
74 | argc--; | |
75 | for(i=1; argv[0][i]; i++) | |
76 | switch(argv[0][i]) { | |
77 | ||
78 | case 'o': | |
79 | oflg++; | |
80 | break; | |
81 | ||
82 | case 'i': | |
83 | iflg++; | |
84 | break; | |
85 | ||
86 | case 'b': | |
87 | bflg++; | |
88 | cmp = bcmp; | |
89 | break; | |
90 | ||
91 | case 'l': | |
92 | lflg++; | |
93 | break; | |
94 | ||
95 | case 'c': | |
96 | cflg++; | |
97 | break; | |
98 | ||
99 | case 'd': | |
100 | dflg++; | |
101 | cmp = dcmp; | |
102 | break; | |
103 | ||
104 | case 'D': | |
105 | Dflg++; | |
106 | cmp = Dcmp; | |
107 | break; | |
108 | ||
109 | case 'j': | |
110 | jflg++; | |
111 | break; | |
112 | ||
113 | case 'k': | |
114 | kflg++; | |
115 | cmp = kcmp; | |
116 | break; | |
117 | ||
118 | case 'K': | |
119 | Kflg++; | |
120 | cmp = Kcmp; | |
121 | break; | |
122 | ||
123 | case 'n': | |
124 | nflg++; | |
125 | cmp = ncmp; | |
126 | break; | |
127 | ||
128 | case 'a': | |
129 | aflg++; | |
130 | break; | |
131 | ||
132 | case 'r': | |
133 | rflg++; | |
134 | break; | |
135 | ||
136 | case 't': | |
137 | tflg++; | |
138 | break; | |
139 | ||
140 | case 's': | |
141 | sflg++; | |
142 | aflg++; | |
143 | break; | |
144 | ||
145 | case '0': | |
146 | case '1': | |
147 | case '2': | |
148 | case '3': | |
149 | case '4': | |
150 | case '5': | |
151 | case '6': | |
152 | case '7': | |
153 | case '8': | |
154 | case '9': | |
155 | thres = argv[0][i]-'0'; | |
156 | break; | |
157 | ||
158 | case 'v': | |
159 | vflg++; | |
160 | break; | |
161 | ||
162 | case 'u': | |
163 | uflg++; | |
164 | break; | |
165 | ||
166 | case 'm': | |
167 | mflg++; | |
168 | break; | |
169 | } | |
170 | } | |
171 | if (iflg==0) | |
172 | init(); | |
173 | if (argc<2) | |
174 | doacct("/usr/adm/acct"); | |
175 | else while (--argc) | |
176 | doacct(*++argv); | |
177 | if (uflg) { | |
178 | return; | |
179 | } | |
180 | ||
181 | /* | |
182 | * cleanup pass | |
183 | * put junk together | |
184 | */ | |
185 | ||
186 | if (vflg) | |
187 | strip(); | |
188 | if(!aflg) | |
189 | for (i=0; i<size; i++) | |
190 | if (tab[i].name[0]) { | |
191 | for(j=0; j<NC; j++) | |
192 | if(tab[i].name[j] == '?') | |
193 | goto yes; | |
194 | if(tab[i].count != 1) | |
195 | continue; | |
196 | yes: | |
197 | if(junkp == -1) | |
198 | junkp = enter("***other"); | |
199 | tab[junkp].count += tab[i].count; | |
200 | tab[junkp].realt += tab[i].realt; | |
201 | tab[junkp].cput += tab[i].cput; | |
202 | tab[junkp].syst += tab[i].syst; | |
203 | tab[junkp].imem += tab[i].imem; | |
204 | tab[junkp].io += tab[i].io; | |
205 | tab[i].name[0] = 0; | |
206 | } | |
207 | for(i=k=0; i<size; i++) | |
208 | if(tab[i].name[0]) { | |
209 | tab[k] = tab[i]; | |
210 | k++; | |
211 | } | |
212 | if (sflg) { | |
213 | signal(SIGINT, SIG_IGN); | |
214 | if ((ff = fopen("/usr/adm/usracct", "w")) != NULL) { | |
215 | fwrite((char *)user, sizeof(user), 1, ff); | |
216 | fclose(ff); | |
217 | } | |
218 | if ((ff = fopen("/usr/adm/savacct", "w")) == NULL) { | |
219 | printf("Can't save\n"); | |
220 | exit(0); | |
221 | } | |
222 | fwrite((char *)tab, sizeof(tab[0]), k, ff); | |
223 | fclose(ff); | |
224 | creat("/usr/adm/acct", 0644); | |
225 | signal(SIGINT, SIG_DFL); | |
226 | } | |
227 | /* | |
228 | * sort and print | |
229 | */ | |
230 | ||
231 | if (mflg) { | |
232 | printmoney(); | |
233 | exit(0); | |
234 | } | |
235 | qsort(tab, k, sizeof(tab[0]), cmp); | |
236 | column(ncom, treal, tcpu, tsys, timem, tio); | |
237 | printf("\n"); | |
238 | for (i=0; i<k; i++) | |
239 | if (tab[i].name[0]) { | |
240 | ft = tab[i].count; | |
241 | column(ft, tab[i].realt, tab[i].cput, tab[i].syst, tab[i].imem, tab[i].io); | |
242 | printf(" %.14s\n", tab[i].name); | |
243 | } | |
244 | } | |
245 | ||
246 | printmoney() | |
247 | { | |
248 | register i; | |
249 | char buf[128]; | |
250 | register char *cp; | |
251 | ||
252 | for (i=0; i<sizeof(user)/sizeof(user[0]); i++) { | |
253 | if (user[i].us_cnt && user[i].us_ctime) { | |
254 | cp = getname(i); | |
255 | if (cp == 0) | |
256 | printf("%-8d", i); | |
257 | else | |
258 | printf("%-8s", cp); | |
259 | printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n", | |
260 | user[i].us_cnt, user[i].us_ctime/60, | |
261 | user[i].us_io, | |
262 | user[i].us_imem / (60 * 2)); | |
263 | } | |
264 | } | |
265 | } | |
266 | ||
267 | column(n, a, b, c, d, e) | |
268 | double n, a, b, c, d, e; | |
269 | { | |
270 | ||
271 | printf("%8.0f", n); | |
272 | if(cflg) { | |
273 | if(n == ncom) | |
274 | printf("%9s", ""); else | |
275 | printf("%8.2f%%", 100.*n/ncom); | |
276 | } | |
277 | col(n, a, treal, "re"); | |
278 | if (oflg) | |
279 | col(n, 3600*(b/(b+c)), tcpu+tsys, "u/s"); | |
280 | else if(lflg) { | |
281 | col(n, b, tcpu, "u"); | |
282 | col(n, c, tsys, "s"); | |
283 | } else | |
284 | col(n, b+c, tcpu+tsys, "cp"); | |
285 | if(tflg) | |
286 | printf("%8.1f", a/(b+c), "re/cp"); | |
287 | if(dflg || !Dflg) | |
288 | printf("%10.0favio", e/(n?n:1)); | |
289 | else | |
290 | printf("%10.0ftio", e); | |
291 | if (kflg || !Kflg) | |
292 | printf("%10.0fk", d/(2*((b+c)!=0.0?(b+c):1.0))); | |
293 | else | |
294 | printf("%10.0fk*sec", d/(2*60)); | |
295 | } | |
296 | ||
297 | col(n, a, m, cp) | |
298 | double n, a, m; | |
299 | char *cp; | |
300 | { | |
301 | ||
302 | if(jflg) | |
303 | printf("%11.2f%s", a/(n*60.), cp); else | |
304 | printf("%11.2f%s", a/3600., cp); | |
305 | if(cflg) { | |
306 | if(a == m) | |
307 | printf("%9s", ""); else | |
308 | printf("%8.2f%%", 100.*a/m); | |
309 | } | |
310 | } | |
311 | ||
312 | doacct(f) | |
313 | char *f; | |
314 | { | |
315 | int i; | |
316 | FILE *ff; | |
317 | long x, y, z; | |
318 | struct acct fbuf; | |
319 | register char *cp; | |
320 | register int c; | |
321 | ||
322 | if (sflg && sname) { | |
323 | printf("Only 1 file with -s\n"); | |
324 | exit(0); | |
325 | } | |
326 | if (sflg) | |
327 | sname = f; | |
328 | if ((ff = fopen(f, "r"))==NULL) { | |
329 | printf("Can't open %s\n", f); | |
330 | return; | |
331 | } | |
332 | while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) { | |
333 | if (fbuf.ac_comm[0]==0) { | |
334 | fbuf.ac_comm[0] = '?'; | |
335 | } | |
336 | for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) { | |
337 | c = *cp & 0377; | |
338 | if (c && (c < ' ' || c >= 0200)) { | |
339 | *cp = '?'; | |
340 | } | |
341 | } | |
342 | if (fbuf.ac_flag&AFORK) { | |
343 | for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) | |
344 | if (*cp==0) { | |
345 | *cp = '*'; | |
346 | break; | |
347 | } | |
348 | } | |
349 | x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime); | |
350 | y = fbuf.ac_mem; | |
351 | z = expand(fbuf.ac_io); | |
352 | if (uflg) { | |
353 | printf("%3d%6.1fcp %6dmem %6dio %.14s\n", | |
354 | fbuf.ac_uid, x/60.0, y, z, | |
355 | fbuf.ac_comm); | |
356 | continue; | |
357 | } | |
358 | c = fbuf.ac_uid; | |
359 | user[c].us_cnt++; | |
360 | user[c].us_ctime += x/60.; | |
361 | user[c].us_imem += x * y; | |
362 | user[c].us_io += z; | |
363 | ncom += 1.0; | |
364 | i = enter(fbuf.ac_comm); | |
365 | tab[i].imem += x * y; | |
366 | timem += x * y; | |
367 | tab[i].count++; | |
368 | x = expand(fbuf.ac_etime)*60; | |
369 | tab[i].realt += x; | |
370 | treal += x; | |
371 | x = expand(fbuf.ac_utime); | |
372 | tab[i].cput += x; | |
373 | tcpu += x; | |
374 | x = expand(fbuf.ac_stime); | |
375 | tab[i].syst += x; | |
376 | tsys += x; | |
377 | tab[i].io += z; | |
378 | tio += z; | |
379 | } | |
380 | fclose(ff); | |
381 | } | |
382 | ||
383 | ncmp(p1, p2) | |
384 | struct tab *p1, *p2; | |
385 | { | |
386 | ||
387 | if(p1->count == p2->count) | |
388 | return(tcmp(p1, p2)); | |
389 | if(rflg) | |
390 | return(p1->count - p2->count); | |
391 | return(p2->count - p1->count); | |
392 | } | |
393 | ||
394 | bcmp(p1, p2) | |
395 | struct tab *p1, *p2; | |
396 | { | |
397 | double f1, f2; | |
398 | double sum(); | |
399 | ||
400 | f1 = sum(p1)/p1->count; | |
401 | f2 = sum(p2)/p2->count; | |
402 | if(f1 < f2) { | |
403 | if(rflg) | |
404 | return(-1); | |
405 | return(1); | |
406 | } | |
407 | if(f1 > f2) { | |
408 | if(rflg) | |
409 | return(1); | |
410 | return(-1); | |
411 | } | |
412 | return(0); | |
413 | } | |
414 | ||
415 | Kcmp(p1, p2) | |
416 | struct tab *p1, *p2; | |
417 | { | |
418 | ||
419 | if (p1->imem < p2->imem) { | |
420 | if(rflg) | |
421 | return(-1); | |
422 | return(1); | |
423 | } | |
424 | if (p1->imem > p2->imem) { | |
425 | if(rflg) | |
426 | return(1); | |
427 | return(-1); | |
428 | } | |
429 | return(0); | |
430 | } | |
431 | ||
432 | kcmp(p1, p2) | |
433 | struct tab *p1, *p2; | |
434 | { | |
435 | double a1, a2; | |
436 | ||
437 | a1 = p1->imem / ((p1->cput+p1->syst)?(p1->cput+p1->syst):1); | |
438 | a2 = p2->imem / ((p2->cput+p2->syst)?(p2->cput+p2->syst):1); | |
439 | if (a1 < a2) { | |
440 | if(rflg) | |
441 | return(-1); | |
442 | return(1); | |
443 | } | |
444 | if (a1 > a2) { | |
445 | if(rflg) | |
446 | return(1); | |
447 | return(-1); | |
448 | } | |
449 | return(0); | |
450 | } | |
451 | ||
452 | dcmp(p1, p2) | |
453 | struct tab *p1, *p2; | |
454 | { | |
455 | double a1, a2; | |
456 | ||
457 | a1 = p1->io / (p1->count?p1->count:1); | |
458 | a2 = p2->io / (p2->count?p2->count:1); | |
459 | if (a1 < a2) { | |
460 | if(rflg) | |
461 | return(-1); | |
462 | return(1); | |
463 | } | |
464 | if (a1 > a2) { | |
465 | if(rflg) | |
466 | return(1); | |
467 | return(-1); | |
468 | } | |
469 | return(0); | |
470 | } | |
471 | ||
472 | Dcmp(p1, p2) | |
473 | struct tab *p1, *p2; | |
474 | { | |
475 | ||
476 | if (p1->io < p2->io) { | |
477 | if(rflg) | |
478 | return(-1); | |
479 | return(1); | |
480 | } | |
481 | if (p1->io > p2->io) { | |
482 | if(rflg) | |
483 | return(1); | |
484 | return(-1); | |
485 | } | |
486 | return(0); | |
487 | } | |
488 | ||
489 | tcmp(p1, p2) | |
490 | struct tab *p1, *p2; | |
491 | { | |
492 | extern double sum(); | |
493 | double f1, f2; | |
494 | ||
495 | f1 = sum(p1); | |
496 | f2 = sum(p2); | |
497 | if(f1 < f2) { | |
498 | if(rflg) | |
499 | return(-1); | |
500 | return(1); | |
501 | } | |
502 | if(f1 > f2) { | |
503 | if(rflg) | |
504 | return(1); | |
505 | return(-1); | |
506 | } | |
507 | return(0); | |
508 | } | |
509 | ||
510 | double sum(p) | |
511 | struct tab *p; | |
512 | { | |
513 | ||
514 | if(p->name[0] == 0) | |
515 | return(0.0); | |
516 | return( | |
517 | p->cput+ | |
518 | p->syst); | |
519 | } | |
520 | ||
521 | init() | |
522 | { | |
523 | struct tab tbuf; | |
524 | int i; | |
525 | FILE *f; | |
526 | ||
527 | if ((f = fopen("/usr/adm/savacct", "r")) == NULL) | |
528 | goto gshm; | |
529 | while (fread((char *)&tbuf, sizeof(tbuf), 1, f) == 1) { | |
530 | i = enter(tbuf.name); | |
531 | ncom += tbuf.count; | |
532 | tab[i].count = tbuf.count; | |
533 | treal += tbuf.realt; | |
534 | tab[i].realt = tbuf.realt; | |
535 | tcpu += tbuf.cput; | |
536 | tab[i].cput = tbuf.cput; | |
537 | tsys += tbuf.syst; | |
538 | tab[i].syst = tbuf.syst; | |
539 | tio += tbuf.io; | |
540 | tab[i].io = tbuf.io; | |
541 | timem += tbuf.imem; | |
542 | tab[i].imem = tbuf.imem; | |
543 | } | |
544 | fclose(f); | |
545 | gshm: | |
546 | if ((f = fopen("/usr/adm/usracct", "r")) == NULL) | |
547 | return; | |
548 | fread((char *)user, sizeof(user), 1, f); | |
549 | fclose(f); | |
550 | } | |
551 | ||
552 | enter(np) | |
553 | char *np; | |
554 | { | |
555 | int i, j; | |
556 | ||
557 | for (i=j=0; i<NC; i++) { | |
558 | if (np[i]==0) | |
559 | j = i; | |
560 | if (j) | |
561 | np[i] = 0; | |
562 | } | |
563 | for (i=j=0; j<NC; j++) { | |
564 | i = i*7 + np[j]; | |
565 | } | |
566 | if (i < 0) | |
567 | i = -i; | |
568 | for (i%=size; tab[i].name[0]; i = (i+1)%size) { | |
569 | for (j=0; j<NC; j++) | |
570 | if (tab[i].name[j]!=np[j]) | |
571 | goto no; | |
572 | goto yes; | |
573 | no:; | |
574 | } | |
575 | for (j=0; j<NC; j++) | |
576 | tab[i].name[j] = np[j]; | |
577 | yes: | |
578 | return(i); | |
579 | } | |
580 | ||
581 | strip() | |
582 | { | |
583 | int i, j, c; | |
584 | ||
585 | j = enter("**junk**"); | |
586 | for (i = 0; i<size; i++) { | |
587 | if (tab[i].name[0] && tab[i].count<=thres) { | |
588 | printf("%.14s--", tab[i].name); | |
589 | if ((c=getchar())=='y') { | |
590 | tab[i].name[0] = '\0'; | |
591 | tab[j].count += tab[i].count; | |
592 | tab[j].realt += tab[i].realt; | |
593 | tab[j].cput += tab[i].cput; | |
594 | tab[j].syst += tab[i].syst; | |
595 | } | |
596 | while (c && c!='\n') | |
597 | c = getchar(); | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
602 | time_t | |
603 | expand(t) | |
604 | unsigned t; | |
605 | { | |
606 | register time_t nt; | |
607 | ||
608 | nt = t&017777; | |
609 | t >>= 13; | |
610 | while (t!=0) { | |
611 | t--; | |
612 | nt <<= 3; | |
613 | } | |
614 | return(nt); | |
615 | } | |
616 | ||
617 | #include <utmp.h> | |
618 | #include <pwd.h> | |
619 | ||
620 | struct utmp utmp; | |
621 | #define NMAX sizeof (utmp.ut_name) | |
622 | #define NUID 2048 | |
623 | ||
624 | char names[NUID][NMAX+1]; | |
625 | ||
626 | char * | |
627 | getname(uid) | |
628 | { | |
629 | register struct passwd *pw; | |
630 | static init; | |
631 | struct passwd *getpwent(); | |
632 | ||
633 | if (names[uid][0]) | |
634 | return (&names[uid][0]); | |
635 | if (init == 2) | |
636 | return (0); | |
637 | if (init == 0) | |
638 | setpwent(), init = 1; | |
639 | while (pw = getpwent()) { | |
640 | if (pw->pw_uid >= NUID) | |
641 | continue; | |
642 | if (names[pw->pw_uid][0]) | |
643 | continue; | |
644 | strncpy(names[pw->pw_uid], pw->pw_name, NMAX); | |
645 | if (pw->pw_uid == uid) | |
646 | return (&names[uid][0]); | |
647 | } | |
648 | init = 2; | |
649 | endpwent(); | |
650 | return (0); | |
651 | } |