|
|
1.1 ! root 1: #ifndef lint ! 2: static char *sccsid = "@(#)sa.c 4.10 (Berkeley) 10/22/87"; ! 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: (void)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.