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