|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)sa.c 4.12 (Berkeley) 5/11/89";
3: #endif
4:
5: /*
6: * Extensive modifications to internal data structures
7: * to allow arbitrary number of different commands and users added.
8: *
9: * Also allowed the digit option on the -v flag (interactive
10: * threshold compress) to be a digit string, so one can
11: * set the threshold > 9.
12: *
13: * Also added the -f flag, to force no interactive threshold
14: * compression with the -v flag.
15: *
16: * Robert Henry
17: * UC Berkeley
18: * 31jan81
19: */
20: #include <stdio.h>
21: #include <ctype.h>
22: #include <sys/types.h>
23: #include <sys/acct.h>
24: #include <signal.h>
25: #include <utmp.h>
26: #include <pwd.h>
27: #include "pathnames.h"
28:
29: /* interpret command time accounting */
30:
31: #define NC sizeof(acctbuf.ac_comm)
32:
33: struct acct acctbuf;
34: int lflg;
35: int cflg;
36: int Dflg;
37: int dflg;
38: int iflg;
39: int jflg;
40: int Kflg;
41: int kflg;
42: int nflg;
43: int aflg;
44: int rflg;
45: int oflg;
46: int tflg;
47: int vflg;
48: int fflg;
49: int uflg;
50: int thres;
51: int sflg;
52: int bflg;
53: int mflg;
54:
55: struct utmp utmp;
56: #define NAMELG (sizeof(utmp.ut_name)+1)
57:
58: struct Olduser{
59: int Us_cnt;
60: double Us_ctime;
61: double Us_io;
62: double Us_imem;
63: };
64:
65: struct user {
66: char name[NC]; /* this is <\001><user id><\000> */
67: struct Olduser oldu;
68: char us_name[NAMELG];
69: };
70: #define us_cnt oldu.Us_cnt
71: #define us_ctime oldu.Us_ctime
72: #define us_io oldu.Us_io
73: #define us_imem oldu.Us_imem
74:
75: /*
76: * We protect ourselves from preposterous user id's by looking
77: * through the passwd file for the highest uid allocated, and
78: * then adding 10 to that.
79: * This prevents the user structure from growing too large.
80: */
81: #define USERSLOP 10
82: int maxuser; /* highest uid from /etc/passwd, + 10 for slop*/
83:
84: struct process {
85: char name[NC];
86: int count;
87: double realt;
88: double cput;
89: double syst;
90: double imem;
91: double io;
92: };
93:
94: union Tab{
95: struct process p;
96: struct user u;
97: };
98:
99: typedef union Tab cell;
100:
101: int (*cmp)(); /* compares 2 cells; set to appropriate func */
102: cell *enter();
103: struct user *finduser();
104: struct user *wasuser();
105:
106: /*
107: * Table elements are keyed by the name of the file exec'ed.
108: * Because on large systems, many files can be exec'ed,
109: * a static table size may grow to be too large.
110: *
111: * Table elements are allocated in chunks dynamically, linked
112: * together so that they may be retrieved sequentially.
113: *
114: * An index into the table structure is provided by hashing through
115: * a seperate hash table.
116: * The hash table is segmented, and dynamically extendable.
117: * Realize that the hash table and accounting information is kept
118: * in different segments!
119: *
120: * We have a linked list of hash table segments; within each
121: * segment we use a quadratic rehash that touches no more than 1/2
122: * of the buckets in the hash table when probing.
123: * If the probe does not find the desired symbol, it moves to the
124: * next segment, or allocates a new segment.
125: *
126: * Hash table segments are kept on the linked list with the first
127: * segment always first (that will probably contain the
128: * most frequently executed commands) and
129: * the last added segment immediately after the first segment,
130: * to hopefully gain something by locality of reference.
131: *
132: * We store the per user information in the same structure as
133: * the per exec'ed file information. This allows us to use the
134: * same managers for both, as the number of user id's may be very
135: * large.
136: * User information is keyed by the first character in the name
137: * being a '\001', followed by four bytes of (long extended)
138: * user id number, followed by a null byte.
139: * The actual user names are kept in a seperate field of the
140: * user structure, and is filled in upon demand later.
141: * Iteration through all users by low user id to high user id
142: * is done by just probing the table, which is gross.
143: */
144: #define USERKEY '\001'
145: #define ISPROCESS(tp) (tp->p.name[0] && (tp->p.name[0] != USERKEY))
146: #define ISUSER(tp) (tp->p.name[0] && (tp->p.name[0] == USERKEY))
147:
148: #define TABDALLOP 500
149: struct allocbox{
150: struct allocbox *nextalloc;
151: cell tabslots[TABDALLOP];
152: };
153:
154: struct allocbox *allochead; /*head of chunk list*/
155: struct allocbox *alloctail; /*tail*/
156: struct allocbox *newbox; /*for creating a new chunk*/
157: cell *nexttab; /*next table element that is free*/
158: int tabsleft; /*slots left in current chunk*/
159: int ntabs;
160: /*
161: * Iterate through all symbols in the symbol table in declaration
162: * order.
163: * struct allocbox *allocwalk;
164: * cell *sp, *ub;
165: *
166: * sp points to the desired item, allocwalk and ub are there
167: * to make the iteration go.
168: */
169:
170: #define DECLITERATE(allocwalk, walkpointer, ubpointer) \
171: for(allocwalk = allochead; \
172: allocwalk != 0; \
173: allocwalk = allocwalk->nextalloc) \
174: for (walkpointer = &allocwalk->tabslots[0],\
175: ubpointer = &allocwalk->tabslots[TABDALLOP], \
176: ubpointer = ubpointer > ( (cell *)alloctail) \
177: ? nexttab : ubpointer ;\
178: walkpointer < ubpointer; \
179: walkpointer++ )
180:
181: #define TABCHUNKS(allocwalk, tabptr, size) \
182: for (allocwalk = allochead; \
183: allocwalk != 0; \
184: allocwalk = allocwalk->nextalloc) \
185: if ( \
186: (tabptr = &allocwalk->tabslots[0]), \
187: (size = \
188: ( (&allocwalk->tabslots[TABDALLOP]) \
189: > ((cell *)alloctail) \
190: ) \
191: ? (nexttab - tabptr) : TABDALLOP \
192: ), \
193: 1 \
194: )
195: #define PROCESSITERATE(allocwalk, walkpointer, ubpointer) \
196: DECLITERATE(allocwalk, walkpointer, ubpointer) \
197: if (ISPROCESS(walkpointer))
198:
199: #define USERITERATE(allocwalk, walkpointer, ubpointer) \
200: DECLITERATE(allocwalk, walkpointer, ubpointer) \
201: if (ISUSER(walkpointer))
202: /*
203: * When we have to sort the segmented accounting table, we
204: * create a vector of sorted queues that is merged
205: * to sort the entire accounting table.
206: */
207: struct chunkdesc {
208: cell *chunk_tp;
209: int chunk_n;
210: };
211:
212: /*
213: * Hash table segments and manager
214: */
215: #define NHASH 1103
216: struct hashdallop {
217: int h_nused;
218: struct hashdallop *h_next;
219: cell *h_tab[NHASH];
220: };
221: struct hashdallop *htab; /* head of the list */
222: int htabinstall; /* install the symbol */
223:
224: double treal;
225: double tcpu;
226: double tsys;
227: double tio;
228: double timem;
229: cell *junkp;
230: char *sname;
231: double ncom;
232: time_t expand();
233: char *getname();
234:
235: /*
236: * usracct saves records of type Olduser.
237: * There is one record for every possible uid less than
238: * the largest uid seen in the previous usracct or in savacct.
239: * uid's that had no activity correspond to zero filled slots;
240: * thus one can index the file and get the user record out.
241: * It would be better to save only user information for users
242: * that the system knows about to save space, but that is not
243: * upward compatabile with the old system.
244: *
245: * In the old version of sa, uid's greater than 999 were not handled
246: * properly; this system will do that.
247: */
248:
249: #ifdef DEBUG
250: #define USRACCT "./usracct"
251: #define SAVACCT "./savacct"
252: #define ACCT "./acct"
253: #else
254: #define USRACCT _PATH_USRACCT
255: #define SAVACCT _PATH_SAVACCT
256: #define ACCT _PATH_ACCT
257: #endif DEBUG
258:
259:
260: char *usracct = USRACCT;
261: char *savacct = SAVACCT;
262:
263: int cellcmp();
264: cell *junkp = 0;
265: /*
266: * The threshold is built up from digits in the argv ;
267: * eg, -v1s0u1
268: * will build a value of thres of 101.
269: *
270: * If the threshold is zero after processing argv, it is set to 1
271: */
272: int thres = 0;
273: int htabinstall = 1;
274: int maxuser = -1;
275: int (*cmp)();
276:
277: /* we assume pagesize is at least 1k */
278: int pgdiv;
279: #define pgtok(x) ((x) / pgdiv)
280:
281: extern tcmp(), ncmp(), bflgcmp(), dcmp(), Dcmp(), kcmp(), Kcmp();
282: extern double sum();
283:
284: main(argc, argv)
285: char **argv;
286: {
287: FILE *ff;
288: double ft;
289: register struct allocbox *allocwalk;
290: register cell *tp, *ub;
291: int i, j, size, nchunks, smallest;
292: struct chunkdesc *chunkvector;
293:
294: pgdiv = getpagesize() / 1024;
295: if (pgdiv == 0)
296: pgdiv = 1;
297: maxuser = USERSLOP + getmaxuid();
298:
299: tabinit();
300: cmp = tcmp;
301: if (argc>1)
302: if (argv[1][0]=='-') {
303: argv++;
304: argc--;
305: for(i=1; argv[0][i]; i++)
306: switch(argv[0][i]) {
307:
308: case 'o':
309: oflg++;
310: break;
311:
312: case 'i':
313: iflg++;
314: break;
315:
316: case 'b':
317: bflg++;
318: cmp = bflgcmp;
319: break;
320:
321: case 'l':
322: lflg++;
323: break;
324:
325: case 'c':
326: cflg++;
327: break;
328:
329: case 'd':
330: dflg++;
331: cmp = dcmp;
332: break;
333:
334: case 'D':
335: Dflg++;
336: cmp = Dcmp;
337: break;
338:
339: case 'j':
340: jflg++;
341: break;
342:
343: case 'k':
344: kflg++;
345: cmp = kcmp;
346: break;
347:
348: case 'K':
349: Kflg++;
350: cmp = Kcmp;
351: break;
352:
353: case 'n':
354: nflg++;
355: cmp = ncmp;
356: break;
357:
358: case 'a':
359: aflg++;
360: break;
361:
362: case 'r':
363: rflg++;
364: break;
365:
366: case 't':
367: tflg++;
368: break;
369:
370: case 's':
371: sflg++;
372: aflg++;
373: break;
374:
375: case '0':
376: case '1':
377: case '2':
378: case '3':
379: case '4':
380: case '5':
381: case '6':
382: case '7':
383: case '8':
384: case '9':
385: thres = thres * 10 + (argv[0][i]-'0');
386: break;
387:
388: case 'v':
389: vflg++;
390: break;
391:
392: case 'f':
393: fflg++; /* force v option; no tty interaction */
394: break;
395:
396: case 'u':
397: uflg++;
398: break;
399:
400: case 'm':
401: mflg++;
402: break;
403:
404: case 'U':
405: case 'S':
406: if (i != 1 || argv[0][2]) { /* gross! */
407: fprintf(stderr, "-U and -S options must be separate\n");
408: exit(1);
409: }
410: argc++, argv--; /* backup - yuk */
411: goto doUS;
412:
413: default:
414: fprintf(stderr, "Invalid option %c\n", argv[0][1]);
415: exit(1);
416: }
417: }
418:
419: #define optfile(f) {if (argc < 2) \
420: { fprintf(stderr, "Missing filename\n"); exit(1); } \
421: argc--, argv++; f = argv[0]; }
422:
423: doUS:
424: for (argc--, argv++; argc && argv[0][0] == '-'; argc--, argv++) {
425: switch(argv[0][1]) {
426: case 'U':
427: optfile(usracct);
428: break;
429:
430: case 'S':
431: optfile(savacct);
432: break;
433:
434: default:
435: fprintf(stderr, "Invalid option %c\n", argv[0][1]);
436: exit(1);
437: }
438: }
439:
440: if (thres == 0)
441: thres = 1;
442: if (iflg==0)
443: init();
444: if (argc<1)
445: doacct(ACCT);
446: else while (argc--)
447: doacct(*argv++);
448: if (uflg) {
449: return;
450: }
451:
452: /*
453: * cleanup pass
454: * put junk together
455: */
456:
457: if (vflg)
458: strip();
459: if(!aflg)
460: PROCESSITERATE(allocwalk, tp, ub){
461: for(j=0; j<NC; j++)
462: if(tp->p.name[j] == '?')
463: goto yes;
464: if(tp->p.count != 1)
465: continue;
466: yes:
467: if(junkp == 0)
468: junkp = enter("***other");
469: junkp->p.count += tp->p.count;
470: junkp->p.realt += tp->p.realt;
471: junkp->p.cput += tp->p.cput;
472: junkp->p.syst += tp->p.syst;
473: junkp->p.imem += tp->p.imem;
474: junkp->p.io += tp->p.io;
475: tp->p.name[0] = 0;
476: }
477: if (sflg) {
478: signal(SIGINT, SIG_IGN);
479: if ((ff = fopen(usracct, "w")) != NULL) {
480: static struct user ZeroUser = {0};
481: struct user *up;
482: int uid;
483: /*
484: * Write out just enough user slots,
485: * filling with zero slots for users that
486: * weren't found.
487: * The file can be indexed directly by uid
488: * to get the correct record.
489: */
490: for (uid = 0; uid < maxuser; uid++){
491: if ( (up = wasuser(uid)) != 0)
492: fwrite((char *)&(up->oldu),
493: sizeof(struct Olduser),1,ff);
494: else
495: fwrite((char *)&(ZeroUser.oldu),
496: sizeof(struct Olduser),1,ff);
497: }
498: }
499: if ((ff = fopen(savacct, "w")) == NULL) {
500: printf("Can't save\n");
501: exit(0);
502: }
503: PROCESSITERATE(allocwalk, tp, ub)
504: fwrite((char *)&(tp->p), sizeof(struct process), 1, ff);
505: fclose(ff);
506: creat(sname, 0644);
507: signal(SIGINT, SIG_DFL);
508: }
509: /*
510: * sort and print
511: */
512: if (mflg) {
513: printmoney();
514: exit(0);
515: }
516: column(ncom, treal, tcpu, tsys, timem, tio);
517: printf("\n");
518:
519: /*
520: * the fragmented table is sorted by sorting each fragment
521: * and then merging.
522: */
523: nchunks = 0;
524: TABCHUNKS(allocwalk, tp, size){
525: qsort(tp, size, sizeof(cell), cellcmp);
526: nchunks ++;
527: }
528: chunkvector = (struct chunkdesc *)calloc(nchunks,
529: sizeof(struct chunkdesc));
530: nchunks = 0;
531: TABCHUNKS(allocwalk, tp, size){
532: chunkvector[nchunks].chunk_tp = tp;
533: chunkvector[nchunks].chunk_n = size;
534: nchunks++;
535: }
536: for(; nchunks; ){
537: /*
538: * Find the smallest element at the head of the queues.
539: */
540: smallest = 0;
541: for (i = 1; i < nchunks; i++){
542: if (cellcmp(chunkvector[i].chunk_tp,
543: chunkvector[smallest].chunk_tp) < 0)
544: smallest = i;
545: }
546: tp = chunkvector[smallest].chunk_tp++;
547: /*
548: * If this queue is drained, drop the chunk count,
549: * and readjust the queues.
550: */
551: if (--chunkvector[smallest].chunk_n == 0){
552: nchunks--;
553: for (i = smallest; i < nchunks; i++)
554: chunkvector[i] = chunkvector[i+1];
555: }
556: if (ISPROCESS(tp)){
557: ft = tp->p.count;
558: column(ft, tp->p.realt, tp->p.cput,
559: tp->p.syst, tp->p.imem, tp->p.io);
560: printf(" %.14s\n", tp->p.name);
561: }
562: } /* iterate to merge the lists */
563: }
564:
565: printmoney()
566: {
567: register i;
568: register char *cp;
569: register struct user *up;
570:
571: getnames(); /* fetches all of the names! */
572: for (i = 0; i < maxuser; i++) {
573: if ( (up = wasuser(i)) != 0){
574: if (up->us_cnt) {
575: if (up->us_name[0])
576: printf("%-8s", up->us_name);
577: else
578: printf("%-8d", i);
579: printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n",
580: up->us_cnt, up->us_ctime / 60,
581: up->us_io,
582: up->us_imem / AHZ);
583: }
584: }
585: }
586: }
587:
588: column(n, a, b, c, d, e)
589: double n, a, b, c, d, e;
590: {
591:
592: printf("%8.0f", n);
593: if(cflg) {
594: if(n == ncom)
595: printf("%9s", ""); else
596: printf("%8.2f%%", 100.*n/ncom);
597: }
598: col(n, a, treal, "re");
599: if (oflg)
600: col(n, 60*AHZ*(b/(b+c)), tcpu+tsys, "u/s");
601: else if(lflg) {
602: col(n, b, tcpu, "u");
603: col(n, c, tsys, "s");
604: } else
605: col(n, b+c, tcpu+tsys, "cp");
606: if(tflg)
607: printf("%8.1fre/cp", a/(b+c));
608: if(dflg || !Dflg)
609: printf("%10.0favio", e/(n?n:1));
610: else
611: printf("%10.0ftio", e);
612: if (kflg || !Kflg)
613: printf("%10.0fk", d/((b+c)!=0.0?(b+c):1.0));
614: else
615: printf("%10.0fk*sec", d/AHZ);
616: }
617:
618: col(n, a, m, cp)
619: double n, a, m;
620: char *cp;
621: {
622:
623: if(jflg)
624: printf("%11.2f%s", a/(n*(double)AHZ), cp); else
625: printf("%11.2f%s", a/(60.*(double)AHZ), cp);
626: if(cflg) {
627: if(a == m)
628: printf("%9s", ""); else
629: printf("%8.2f%%", 100.*a/m);
630: }
631: }
632:
633: doacct(f)
634: char *f;
635: {
636: FILE *ff;
637: long x, y, z;
638: struct acct fbuf;
639: register char *cp;
640: register int c;
641: register struct user *up;
642: register cell *tp;
643: #ifdef DEBUG
644: int nrecords = 0;
645: #endif DEBUG
646:
647: if (sflg && sname) {
648: printf("Only 1 file with -s\n");
649: exit(0);
650: }
651: if (sflg)
652: sname = f;
653: if ((ff = fopen(f, "r"))==NULL) {
654: printf("Can't open %s\n", f);
655: return;
656: }
657: while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) {
658: #ifdef DEBUG
659: if (++nrecords % 1000 == 0)
660: printf("Input record from %s number %d\n",
661: f, nrecords);
662: #endif DEBUG
663: for (cp = fbuf.ac_comm; *cp && cp < &fbuf.ac_comm[NC]; cp++)
664: if (!isascii(*cp) || iscntrl(*cp))
665: *cp = '?';
666: if (cp == fbuf.ac_comm)
667: *cp++ = '?';
668: if (fbuf.ac_flag&AFORK) {
669: if (cp >= &fbuf.ac_comm[NC])
670: cp = &fbuf.ac_comm[NC-1];
671: *cp++ = '*';
672: }
673: if (cp < &fbuf.ac_comm[NC])
674: *cp = '\0';
675: x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime);
676: y = pgtok((u_short)fbuf.ac_mem);
677: z = expand(fbuf.ac_io) / AHZ;
678: if (uflg) {
679: printf("%3d %6.2f cpu %8luk mem %6ld io %.*s\n",
680: fbuf.ac_uid, x/(double)AHZ, y, z, NC, fbuf.ac_comm);
681: continue;
682: }
683: up = finduser(fbuf.ac_uid);
684: if (up == 0)
685: continue; /* preposterous user id */
686: up->us_cnt++;
687: up->us_ctime += x/(double)AHZ;
688: up->us_imem += x * y;
689: up->us_io += z;
690: ncom += 1.0;
691:
692: tp = enter(fbuf.ac_comm);
693: tp->p.imem += x * y;
694: timem += x * y;
695: tp->p.count++;
696: x = expand(fbuf.ac_etime);
697: tp->p.realt += x;
698: treal += x;
699: x = expand(fbuf.ac_utime);
700: tp->p.cput += x;
701: tcpu += x;
702: x = expand(fbuf.ac_stime);
703: tp->p.syst += x;
704: tsys += x;
705: tp->p.io += z;
706: tio += z;
707: }
708: fclose(ff);
709: }
710:
711: /*
712: * Generalized cell compare routine, to cast out users
713: */
714: cellcmp(p1, p2)
715: cell *p1, *p2;
716: {
717: if (ISPROCESS(p1)){
718: if (ISPROCESS(p2))
719: return((*cmp)(p1, p2));
720: return(-1);
721: }
722: if (ISPROCESS(p2))
723: return(1);
724: return(0);
725: }
726:
727: ncmp(p1, p2)
728: cell *p1, *p2;
729: {
730:
731: if(p1->p.count == p2->p.count)
732: return(tcmp(p1, p2));
733: if(rflg)
734: return(p1->p.count - p2->p.count);
735: return(p2->p.count - p1->p.count);
736: }
737:
738: bflgcmp(p1, p2)
739: cell *p1, *p2;
740: {
741: double f1, f2;
742: double sum();
743:
744: f1 = sum(p1)/p1->p.count;
745: f2 = sum(p2)/p2->p.count;
746: if(f1 < f2) {
747: if(rflg)
748: return(-1);
749: return(1);
750: }
751: if(f1 > f2) {
752: if(rflg)
753: return(1);
754: return(-1);
755: }
756: return(0);
757: }
758:
759: Kcmp(p1, p2)
760: cell *p1, *p2;
761: {
762:
763: if (p1->p.imem < p2->p.imem) {
764: if(rflg)
765: return(-1);
766: return(1);
767: }
768: if (p1->p.imem > p2->p.imem) {
769: if(rflg)
770: return(1);
771: return(-1);
772: }
773: return(0);
774: }
775:
776: kcmp(p1, p2)
777: cell *p1, *p2;
778: {
779: double a1, a2;
780:
781: a1 = p1->p.imem / ((p1->p.cput+p1->p.syst)?(p1->p.cput+p1->p.syst):1);
782: a2 = p2->p.imem / ((p2->p.cput+p2->p.syst)?(p2->p.cput+p2->p.syst):1);
783: if (a1 < a2) {
784: if(rflg)
785: return(-1);
786: return(1);
787: }
788: if (a1 > a2) {
789: if(rflg)
790: return(1);
791: return(-1);
792: }
793: return(0);
794: }
795:
796: dcmp(p1, p2)
797: cell *p1, *p2;
798: {
799: double a1, a2;
800:
801: a1 = p1->p.io / (p1->p.count?p1->p.count:1);
802: a2 = p2->p.io / (p2->p.count?p2->p.count:1);
803: if (a1 < a2) {
804: if(rflg)
805: return(-1);
806: return(1);
807: }
808: if (a1 > a2) {
809: if(rflg)
810: return(1);
811: return(-1);
812: }
813: return(0);
814: }
815:
816: Dcmp(p1, p2)
817: cell *p1, *p2;
818: {
819:
820: if (p1->p.io < p2->p.io) {
821: if(rflg)
822: return(-1);
823: return(1);
824: }
825: if (p1->p.io > p2->p.io) {
826: if(rflg)
827: return(1);
828: return(-1);
829: }
830: return(0);
831: }
832:
833: tcmp(p1, p2)
834: cell *p1, *p2;
835: {
836: extern double sum();
837: double f1, f2;
838:
839: f1 = sum(p1);
840: f2 = sum(p2);
841: if(f1 < f2) {
842: if(rflg)
843: return(-1);
844: return(1);
845: }
846: if(f1 > f2) {
847: if(rflg)
848: return(1);
849: return(-1);
850: }
851: return(0);
852: }
853:
854: double sum(p)
855: cell *p;
856: {
857:
858: if(p->p.name[0] == 0)
859: return(0.0);
860: return( p->p.cput + p->p.syst);
861: }
862:
863: init()
864: {
865: struct user userbuf;
866: struct process tbuf;
867: register cell *tp;
868: register struct user *up;
869: int uid;
870: FILE *f;
871:
872: if ((f = fopen(savacct, "r")) == NULL)
873: goto gshm;
874: while (fread((char *)&tbuf, sizeof(struct process), 1, f) == 1) {
875: tp = enter(tbuf.name);
876: ncom += tbuf.count;
877: tp->p.count = tbuf.count;
878: treal += tbuf.realt;
879: tp->p.realt = tbuf.realt;
880: tcpu += tbuf.cput;
881: tp->p.cput = tbuf.cput;
882: tsys += tbuf.syst;
883: tp->p.syst = tbuf.syst;
884: tio += tbuf.io;
885: tp->p.io = tbuf.io;
886: timem += tbuf.imem;
887: tp->p.imem = tbuf.imem;
888: }
889: fclose(f);
890: gshm:
891: if ((f = fopen(usracct, "r")) == NULL)
892: return;
893: for(uid = 0;
894: fread((char *)&(userbuf.oldu), sizeof(struct Olduser), 1, f) == 1;
895: uid++){
896: if (userbuf.us_cnt){
897: up = finduser(uid);
898: if (up == 0)
899: continue; /* preposterous user id */
900: up->oldu = userbuf.oldu;
901: }
902: }
903: fclose(f);
904: }
905:
906: strip()
907: {
908: int c;
909: register struct allocbox *allocwalk;
910: register cell *tp, *ub, *junkp;
911:
912: if (fflg)
913: printf("Categorizing commands used %d times or fewer as **junk**\n",
914: thres);
915: junkp = enter("**junk**");
916: PROCESSITERATE(allocwalk, tp, ub){
917: if (tp->p.name[0] && tp->p.count <= thres) {
918: if (!fflg)
919: printf("%.14s--", tp->p.name);
920: if (fflg || ((c=getchar())=='y')) {
921: tp->p.name[0] = '\0';
922: junkp->p.count += tp->p.count;
923: junkp->p.realt += tp->p.realt;
924: junkp->p.cput += tp->p.cput;
925: junkp->p.syst += tp->p.syst;
926: junkp->p.imem += tp->p.imem;
927: junkp->p.io += tp->p.io;
928: }
929: if (!fflg)
930: while (c && c!='\n')
931: c = getchar();
932: }
933: }
934: }
935:
936: time_t
937: expand(t)
938: unsigned t;
939: {
940: register time_t nt;
941:
942: nt = t&017777;
943: t >>= 13;
944: while (t!=0) {
945: t--;
946: nt <<= 3;
947: }
948: return(nt);
949: }
950:
951: static char UserKey[NAMELG + 2];
952:
953: char *
954: makekey(uid)
955: int uid;
956: {
957: (void)sprintf(UserKey+1, "%04x", uid);
958: UserKey[0] = USERKEY;
959: return(UserKey);
960: }
961:
962: struct user *
963: wasuser(uid)
964: int uid;
965: {
966: struct user *tp;
967:
968: htabinstall = 0;
969: tp = finduser(uid);
970: htabinstall = 1;
971: return(tp);
972: }
973:
974: /*
975: * Only call this if you really want to insert it in the table!
976: */
977: struct user *
978: finduser(uid)
979: int uid;
980: {
981:
982: if (uid > maxuser){
983: fprintf(stderr, "Preposterous user id, %d: ignored\n", uid);
984: return(0);
985: }
986: return((struct user*)enter(makekey(uid)));
987: }
988:
989: /*
990: * Set the names of all users in the password file.
991: * We will later not print those that didn't do anything.
992: */
993: getnames()
994: {
995: register struct user *tp;
996: register struct passwd *pw;
997: struct passwd *getpwent();
998:
999: setpwent();
1000: while (pw = getpwent()){
1001: /* use first name in passwd file for duplicate uid's */
1002: if ((tp = wasuser(pw->pw_uid)) != 0 && !isalpha(tp->us_name[0]))
1003: strncpy(tp->us_name, pw->pw_name, NAMELG);
1004: }
1005: endpwent();
1006: }
1007:
1008: int
1009: getmaxuid()
1010: {
1011: register struct user *tp;
1012: register struct passwd *pw;
1013: struct passwd *getpwent();
1014: int maxuid = -1;
1015:
1016: setpwent();
1017: while(pw = getpwent()){
1018: if (pw->pw_uid > maxuid)
1019: maxuid = pw->pw_uid;
1020: }
1021: endpwent();
1022: return(maxuid);
1023: }
1024:
1025: tabinit()
1026: {
1027: allochead = 0;
1028: alloctail = 0;
1029: nexttab = 0;
1030: tabsleft = 0;
1031: htab = 0;
1032: ntabs = 0;
1033: htaballoc(); /* get the first part of the hash table */
1034: }
1035:
1036: #define ALLOCQTY sizeof (struct allocbox)
1037: cell *
1038: taballoc()
1039: {
1040:
1041: if (tabsleft == 0){
1042: newbox = (struct allocbox *)calloc(1, ALLOCQTY);
1043: tabsleft = TABDALLOP;
1044: nexttab = &newbox->tabslots[0];
1045: if (alloctail == 0){
1046: allochead = alloctail = newbox;
1047: } else {
1048: alloctail->nextalloc = newbox;
1049: alloctail = newbox;
1050: }
1051: }
1052: --tabsleft;
1053: ++ntabs;
1054: #ifdef DEBUG
1055: if (ntabs % 100 == 0)
1056: printf("##Accounting table slot # %d\n", ntabs);
1057: #endif DEBUG
1058: return(nexttab++);
1059: }
1060:
1061: htaballoc()
1062: {
1063: register struct hashdallop *new;
1064: #ifdef DEBUG
1065: static int ntables = 0;
1066:
1067: printf("%%%New hash table chunk allocated, number %d\n", ++ntables);
1068: #endif DEBUG
1069: new = (struct hashdallop *)calloc(1, sizeof (struct hashdallop));
1070: if (htab == 0)
1071: htab = new;
1072: else { /* add AFTER the 1st slot */
1073: new->h_next = htab->h_next;
1074: htab->h_next = new;
1075: }
1076: }
1077:
1078: #define HASHCLOGGED (NHASH / 2)
1079: /*
1080: * Lookup a symbol passed in as the argument.
1081: *
1082: * We take pains to avoid function calls; this function
1083: * is called quite frequently, and the calling overhead
1084: * contributes significantly to the overall execution speed of sa.
1085: */
1086: cell *
1087: enter(name)
1088: char *name;
1089: {
1090: static int initialprobe;
1091: register cell **hp;
1092: register char *from, *to;
1093: register int len, nprobes;
1094: static struct hashdallop *hdallop, *emptyhd;
1095: static cell **emptyslot, **hp_ub;
1096:
1097: emptyslot = 0;
1098: for (nprobes = 0, from = name, len = 0;
1099: *from && len < NC;
1100: nprobes <<= 2, nprobes += *from++, len++)
1101: continue;
1102: nprobes += from[-1] << 5;
1103: nprobes %= NHASH;
1104: if (nprobes < 0)
1105: nprobes += NHASH;
1106:
1107: initialprobe = nprobes;
1108: for (hdallop = htab; hdallop != 0; hdallop = hdallop->h_next){
1109: for (hp = &(hdallop->h_tab[initialprobe]),
1110: nprobes = 1,
1111: hp_ub = &(hdallop->h_tab[NHASH]);
1112: (*hp) && (nprobes < NHASH);
1113: hp += nprobes,
1114: hp -= (hp >= hp_ub) ? NHASH:0,
1115: nprobes += 2)
1116: {
1117: from = name;
1118: to = (*hp)->p.name;
1119:
1120: for (len = 0; (len<NC) && *from; len++)
1121: if (*from++ != *to++)
1122: goto nextprobe;
1123: if (len >= NC) /*both are maximal length*/
1124: return(*hp);
1125: if (*to == 0) /*assert *from == 0*/
1126: return(*hp);
1127: nextprobe: ;
1128: }
1129: if (*hp == 0 && emptyslot == 0 &&
1130: hdallop->h_nused < HASHCLOGGED) {
1131: emptyslot = hp;
1132: emptyhd = hdallop;
1133: }
1134: }
1135: if (emptyslot == 0) {
1136: htaballoc();
1137: hdallop = htab->h_next; /* aren't we smart! */
1138: hp = &hdallop->h_tab[initialprobe];
1139: } else {
1140: hdallop = emptyhd;
1141: hp = emptyslot;
1142: }
1143: if (htabinstall){
1144: *hp = taballoc();
1145: hdallop->h_nused++;
1146: for(len = 0, from = name, to = (*hp)->p.name; (len<NC); len++)
1147: if ((*to++ = *from++) == '\0')
1148: break;
1149: return(*hp);
1150: }
1151: return(0);
1152: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.