Annotation of 43BSDReno/usr.sbin/sa/sa.c, revision 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.