Annotation of researchv10no/cmd/sa.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.