Annotation of 43BSDReno/usr.sbin/sa/sa.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

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