|
|
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.