Annotation of coherent/d/bin/sa.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * System accounting
        !             3:  * of command execution (in
        !             4:  * conjuction with acct system
        !             5:  * call.)
        !             6:  */
        !             7: 
        !             8: #include <stdio.h>
        !             9: #include <ctype.h>
        !            10: #include <pwd.h>
        !            11: #include <acct.h>
        !            12: #include <sys/times.h>
        !            13: #include <sys/dir.h>
        !            14: #include <sys/machine.h>
        !            15: 
        !            16: #define        MIN     60              /* Seconds in a minute */
        !            17: #define        MINHZ   (MIN*HZ)        /* HZ in a minute */
        !            18: #define        CPUTIME 0               /* Sort by CPU time */
        !            19: #define        PERCALL 1               /* Sort by CPU time per call */
        !            20: #define        CALLS   2               /* Sort by numbers of calls */
        !            21: 
        !            22: #define        NUSER   100             /* Maximum number of users */
        !            23: #define        NCOMM   500             /* Maximum number of commands */
        !            24: #define        NSORT   NUSER
        !            25: #define        NCNAME  (sizeof(ac.ac_comm))    /* Size of a command name) */
        !            26: 
        !            27: struct acct    ac;
        !            28: 
        !            29: /*
        !            30:  * structure of /usr/adm/usracct
        !            31:  * for per-user type of `sa' information.
        !            32:  */
        !            33: struct svu     {
        !            34:        unsigned svu_count;             /* Number of processes measured */
        !            35:        short   svu_uid;                /* User number */
        !            36:        time_t  svu_stime;              /* Total system time (HZ) */
        !            37:        time_t  svu_utime;              /* Total user time */
        !            38:        time_t  svu_etime;              /* Total elapsed time  (sec.)*/
        !            39: }      svu[NUSER];
        !            40: 
        !            41: /*
        !            42:  * For per command information as
        !            43:  * is stored in /usr/adm/savacct.
        !            44:  */
        !            45: struct svc     {
        !            46:        unsigned svc_count;             /* Number of calls */
        !            47:        char    svc_comm[NCNAME];       /* Command name */
        !            48:        time_t  svc_stime;
        !            49:        time_t  svc_utime;
        !            50:        time_t  svc_etime;
        !            51: }      svc[NCOMM];
        !            52: struct svc     *junkp, *otherp;
        !            53: 
        !            54: /*
        !            55:  * For the final sort.  This is
        !            56:  * the combined information of
        !            57:  * the two structures above.
        !            58:  * I.e. either one or the other.
        !            59:  */
        !            60: struct sort {
        !            61:        unsigned s_count;               /* Number of calls */
        !            62:        char    s_comm[NCNAME];         /* Command name */
        !            63:        short   s_uid;                  /* User number */
        !            64:        time_t  s_key;                  /* Sort key */
        !            65:        time_t  s_stime;                /* System time */
        !            66:        time_t  s_utime;                /* User time */
        !            67:        time_t  s_etime;                /* Elapsed time */
        !            68: }      sort[NSORT];
        !            69: 
        !            70: char   *acctf = "/usr/adm/acct";               /* Raw accounting file */
        !            71: char   *sacctf = "/usr/adm/savacct";           /* Summary file */
        !            72: char   *uacctf = "/usr/adm/usracct";           /* Per-user summary */
        !            73: char   junk[NCNAME] = "**junk**";
        !            74: char   other[NCNAME] = "***other";
        !            75: 
        !            76: int    aflag;                  /* Move unlikely commands to "**other" */
        !            77: int    cflag;                  /* Give percentage of total time */
        !            78: int    jflag;                  /* Give seconds instead of minutes/call */
        !            79: int    lflag;                  /* Separate system & user times */
        !            80: int    mflag;                  /* Number of processes and CPU min. per user */
        !            81: int    rflag;                  /* Reverse sort order */
        !            82: int    sflag;                  /* Merge accounting file when done */
        !            83: int    tflag;                  /* Print ratio of real to CPU time */
        !            84: int    uflag;                  /* Print user-id and command name */
        !            85: int    vflag;                  /* Prompt if used fewer than `n' times */
        !            86: int    sortflag = CPUTIME;     /* Sort mode */
        !            87: 
        !            88: long   ctol();
        !            89: time_t units();
        !            90: struct svc     *make();
        !            91: struct svc     *move();
        !            92: char   *uname();
        !            93: int    compar();
        !            94: 
        !            95: main(argc, argv)
        !            96: char *argv[];
        !            97: {
        !            98:        register char *ap;
        !            99: 
        !           100:        while (argc>1 && *argv[1]=='-') {
        !           101:                for (ap = &argv[1][1]; *ap != '\0'; ap++)
        !           102:                        switch (*ap) {
        !           103:                        case 'a':
        !           104:                                aflag = 1;
        !           105:                                break;
        !           106: 
        !           107:                        case 'b':
        !           108:                                sortflag = PERCALL;
        !           109:                                break;
        !           110: 
        !           111:                        case 'c':
        !           112:                                cflag = 1;
        !           113:                                break;
        !           114: 
        !           115:                        case 'j':
        !           116:                                jflag = 1;
        !           117:                                break;
        !           118: 
        !           119:                        case 'l':
        !           120:                                lflag = 1;
        !           121:                                break;
        !           122: 
        !           123:                        case 'm':
        !           124:                                mflag = 1;
        !           125:                                break;
        !           126: 
        !           127:                        case 'n':
        !           128:                                sortflag = CALLS;
        !           129:                                break;
        !           130: 
        !           131:                        case 'r':
        !           132:                                rflag = 1;
        !           133:                                break;
        !           134: 
        !           135:                        case 's':
        !           136:                                sflag = 1;
        !           137:                                break;
        !           138: 
        !           139:                        case 't':
        !           140:                                tflag = 1;
        !           141:                                break;
        !           142: 
        !           143:                        case 'u':
        !           144:                                uflag = 1;
        !           145:                                break;
        !           146: 
        !           147:                        case 'v':
        !           148:                                if (ap[1]>='0' && ap[1]<='9')
        !           149:                                        vflag = *++ap - '0';
        !           150:                                break;
        !           151: 
        !           152:                        default:
        !           153:                                usage();
        !           154:                        }
        !           155:                argc--;
        !           156:                argv++;
        !           157:        }
        !           158:        if (argc == 2)
        !           159:                acctf = argv[1];
        !           160:        else if (argc > 2)
        !           161:                usage();
        !           162:        if (!uflag)
        !           163:                rsummary();
        !           164:        rraw(acctf);
        !           165:        if (sflag && !uflag)
        !           166:                samerge();
        !           167:        if (!uflag)
        !           168:                saprint();
        !           169:        exit(0);
        !           170: }
        !           171: 
        !           172: /*
        !           173:  * Read the summary file of old accounting information
        !           174:  * from both user and command saved accounting files.
        !           175:  */
        !           176: rsummary()
        !           177: {
        !           178:        register FILE *fp;
        !           179: 
        !           180:        if ((fp = fopen(sacctf, "r")) != NULL) {
        !           181:                register struct svc *svcp;
        !           182: 
        !           183:                for (svcp = svc; svcp < &svc[NCOMM]; svcp++)
        !           184:                        if (fread(svcp, sizeof *svcp, 1, fp) != 1)
        !           185:                                break;
        !           186:                if (svcp >= &svc[NCOMM])
        !           187:                        fprintf(stderr, "%s is too large\n", sacctf);
        !           188:                fclose(fp);
        !           189:        }
        !           190:        if ((fp = fopen(uacctf, "r")) != NULL) {
        !           191:                register struct svu *svup;
        !           192: 
        !           193:                for (svup = svu; svup < &svu[NUSER]; svup++)
        !           194:                        if (fread(svup, sizeof *svup, 1, fp) != 1)
        !           195:                                break;
        !           196:                if (svup >= &svu[NUSER])
        !           197:                        fprintf(stderr, "%s is too large\n", uacctf);
        !           198:                fclose(fp);
        !           199:        }
        !           200: }
        !           201: 
        !           202: /*
        !           203:  * Read the raw accounting.
        !           204:  */
        !           205: rraw(af)
        !           206: char *af;
        !           207: {
        !           208:        FILE *afp;
        !           209:        register struct svc *svcp;
        !           210: 
        !           211:        if ((afp = fopen(af, "r")) == NULL) {
        !           212:                fprintf(stderr, "Cannot open raw accounting file `%s'\n", af);
        !           213:                exit(1);
        !           214:        }
        !           215:        while (fread(&ac, sizeof ac, 1, afp) == 1) {
        !           216:                if (uflag)
        !           217:                        printf("%-*s  %.*s\n", DIRSIZ, uname(ac.ac_uid),
        !           218:                            NCNAME, ac.ac_comm);
        !           219:                else {
        !           220:                        senter(&ac);
        !           221:                        uenter(&ac);
        !           222:                }
        !           223:        }
        !           224:        fclose(afp);
        !           225:        /*
        !           226:         * Create (if not there) junk and other classes.
        !           227:         */
        !           228:        if (aflag) {
        !           229:                otherp = make(other);
        !           230:                for (svcp = svc; svcp<&svc[NCOMM] && svcp->svc_count; svcp++) {
        !           231:                        if (svcp == otherp)
        !           232:                                continue;
        !           233:                        if (svcp->svc_count==1 || unprintable(svcp->svc_comm))
        !           234:                                otherp = move(svcp--, otherp);
        !           235:                }
        !           236:        }
        !           237:        if (vflag) {
        !           238:                junkp = make(junk);
        !           239:                for (svcp = svc; svcp<&svc[NCOMM] && svcp->svc_count; svcp++) {
        !           240:                        if (svcp == junkp)
        !           241:                                continue;
        !           242:                        if (svcp->svc_count<=vflag && yes(svcp->svc_comm))
        !           243:                                junkp = move(svcp--, junkp);
        !           244:                }
        !           245:        }
        !           246: }
        !           247: 
        !           248: /*
        !           249:  * Merge system accounting info back
        !           250:  * into the two merged files and
        !           251:  * truncate the raw accounting file.
        !           252:  * Accounting probably should be
        !           253:  * turned off when `sa' is called
        !           254:  * if this is to be done.
        !           255:  */
        !           256: samerge()
        !           257: {
        !           258:        register FILE *fp;
        !           259: 
        !           260:        if ((fp = fopen(sacctf, "w")) != NULL) {
        !           261:                register struct svc *svcp;
        !           262: 
        !           263:                for (svcp = svc; svcp<&svc[NCOMM] && svcp->svc_count; svcp++)
        !           264:                        if (fwrite(svcp, sizeof *svcp, 1, fp) != 1)
        !           265:                                saerr("%s: write error", sacctf);
        !           266:                fclose(fp);
        !           267:        } else
        !           268:                saerr("cannot rewrite %s", sacctf);
        !           269:        if ((fp = fopen(uacctf, "w")) != NULL) {
        !           270:                register struct svu *svup;
        !           271: 
        !           272:                for (svup = svu; svup<&svu[NUSER] && svup->svu_count; svup++)
        !           273:                        if (fwrite(svup, sizeof *svup, 1, fp) != 1)
        !           274:                                saerr("%s: write error", uacctf);
        !           275:                fclose(fp);
        !           276:        } else
        !           277:                saerr("cannot rewrite %s", uacctf);
        !           278:        if ((fp = fopen(acctf, "w")) == NULL)
        !           279:                saerr("cannot truncate %s", acctf);
        !           280:        fclose(fp);
        !           281: }
        !           282: 
        !           283: /*
        !           284:  * Output the accounting
        !           285:  * information according to
        !           286:  * sorting and printing options.
        !           287:  */
        !           288: saprint()
        !           289: {
        !           290:        register struct sort *sp;
        !           291:        time_t tottime;
        !           292: 
        !           293:        if (mflag)
        !           294:                userenter(); else
        !           295:                commenter();
        !           296:        for (sp = sort; sp<&sort[NSORT] && sp->s_count; sp++)
        !           297:                if (sortflag == CPUTIME)
        !           298:                        sp->s_key = sp->s_stime+sp->s_utime;
        !           299:                else if (sortflag == PERCALL)
        !           300:                        sp->s_key = (sp->s_stime+sp->s_utime)/sp->s_count;
        !           301:                else            /* # calls */
        !           302:                        sp->s_key = sp->s_count;
        !           303:        qsort(sort, sp-sort, sizeof *sp, compar);
        !           304:        if (mflag)
        !           305:                printf("%-*s #PROC", DIRSIZ, ""); else
        !           306:                printf("%-*s #CALL", NCNAME, "");
        !           307:        if (lflag)
        !           308:                printf("  USER  SYS"); else
        !           309:                printf("  CPU");
        !           310:        printf("  REAL");
        !           311:        if (cflag)
        !           312:                printf(" CPU %% ");
        !           313:        if (tflag)
        !           314:                printf(" CPU/REAL %%");
        !           315:        putchar('\n');
        !           316:        if (cflag) {
        !           317:                tottime = 0;
        !           318:                for (sp = sort; sp<&sort[NSORT] && sp->s_count; sp++) {
        !           319:                        tottime += sp->s_stime;
        !           320:                        tottime += sp->s_utime;
        !           321:                }
        !           322:        }
        !           323:        for (sp = sort; sp<&sort[NSORT] && sp->s_count; sp++) {
        !           324:                if (mflag)
        !           325:                        printf("%-*s", DIRSIZ, uname(sp->s_uid)); else
        !           326:                        printf("%-*s", NCNAME, sp->s_comm);
        !           327:                printf(" %5d", sp->s_count);
        !           328:                if (lflag)
        !           329:                        printf(" %5ld %5ld", units(sp->s_utime, sp),
        !           330:                            units(sp->s_stime, sp));
        !           331:                else
        !           332:                        printf(" %5ld", units(sp->s_utime+sp->s_stime, sp));
        !           333:                printf(" %5ld", units(sp->s_etime*HZ, sp));
        !           334:                if (cflag)
        !           335:                        percent(sp->s_utime+sp->s_stime, tottime);
        !           336:                if (tflag) {
        !           337:                        printf("  ");
        !           338:                        percent(sp->s_utime+sp->s_stime, sp->s_etime*HZ);
        !           339:                }
        !           340:                putchar('\n');
        !           341:        }
        !           342: }
        !           343: 
        !           344: /*
        !           345:  * Enter user information for the sort.
        !           346:  */
        !           347: userenter()
        !           348: {
        !           349:        register struct sort *sp;
        !           350:        register struct svu *svup;
        !           351: 
        !           352:        sp = sort;
        !           353:        svup = svu;
        !           354:        while (svup < &svu[NCOMM] && svup->svu_count) {
        !           355:                sp->s_count = svup->svu_count;
        !           356:                sp->s_uid = svup->svu_uid;
        !           357:                sp->s_stime = svup->svu_stime;
        !           358:                sp->s_utime = svup->svu_utime;
        !           359:                sp->s_etime = svup->svu_etime;
        !           360:                sp++;
        !           361:                svup++;
        !           362:        }
        !           363: /*
        !           364:        free(svc);
        !           365:  */
        !           366: }
        !           367: 
        !           368: /*
        !           369:  * Enter the commands into the list for
        !           370:  * sorting.
        !           371:  */
        !           372: commenter()
        !           373: {
        !           374:        register struct sort *sp;
        !           375:        register struct svc *svcp;
        !           376: 
        !           377:        sp = sort;
        !           378:        svcp = svc;
        !           379:        while (svcp < &svc[NCOMM] && svcp->svc_count) {
        !           380:                sp->s_count = svcp->svc_count;
        !           381:                strncpy(sp->s_comm, svcp->svc_comm, NCNAME);
        !           382:                sp->s_stime = svcp->svc_stime;
        !           383:                sp->s_utime = svcp->svc_utime;
        !           384:                sp->s_etime = svcp->svc_etime;
        !           385:                sp++;
        !           386:                svcp++;
        !           387:        }
        !           388: /*
        !           389:        free(svu);
        !           390:  */
        !           391: }
        !           392: 
        !           393: /*
        !           394:  * Enter this accounting entry into
        !           395:  * the command table for savacct.
        !           396:  */
        !           397: senter(ap)
        !           398: register struct acct *ap;
        !           399: {
        !           400:        register struct svc *svcp;
        !           401: 
        !           402:        for (svcp = svc; svcp<&svc[NCOMM] && svcp->svc_count; svcp++)
        !           403:                if (strncmp(svcp->svc_comm, ap->ac_comm, NCNAME) == 0)
        !           404:                        break;
        !           405:        if (svcp >= &svc[NCOMM])
        !           406:                saerr("Command table overflow");
        !           407:        if (svcp->svc_count++ == 0)
        !           408:                strncpy(svcp->svc_comm, ap->ac_comm, NCNAME);
        !           409:        svcp->svc_stime += ctol(ap->ac_stime);
        !           410:        svcp->svc_utime += ctol(ap->ac_utime);
        !           411:        svcp->svc_etime += ctol(ap->ac_etime);
        !           412: }
        !           413: 
        !           414: /*
        !           415:  * Enter this accounting entry into
        !           416:  * the user table for usracct.
        !           417:  */
        !           418: uenter(ap)
        !           419: register struct acct *ap;
        !           420: {
        !           421:        register struct svu *svup;
        !           422: 
        !           423:        for (svup = svu; svup<&svu[NUSER] && svup->svu_count; svup++)
        !           424:                if (svup->svu_uid == ap->ac_uid)
        !           425:                        break;
        !           426:        if (svup >= &svu[NUSER])
        !           427:                saerr("User table overflow");
        !           428:        svup->svu_count++;
        !           429:        svup->svu_uid = ap->ac_uid;
        !           430:        svup->svu_stime += ctol(ap->ac_stime);
        !           431:        svup->svu_utime += ctol(ap->ac_utime);
        !           432:        svup->svu_etime += ctol(ap->ac_etime);
        !           433: }
        !           434: 
        !           435: /*
        !           436:  * Make a new zero entry with
        !           437:  * the indicated name.
        !           438:  */
        !           439: struct svc *
        !           440: make(name)
        !           441: register char *name;
        !           442: {
        !           443:        register struct svc *svcp;
        !           444: 
        !           445:        for (svcp = svc; svcp<&svc[NCOMM] && svcp->svc_count; svcp++)
        !           446:                if (strncmp(name, svcp->svc_comm, NCNAME) == 0)
        !           447:                        return (svcp);
        !           448:        if (svcp >= &svc[NCOMM])
        !           449:                saerr("out of room for %s", name);
        !           450:        strncpy(svcp->svc_comm, name, NCNAME);
        !           451:        return (svcp);
        !           452: }
        !           453: 
        !           454: /*
        !           455:  * Move an entry to one of the deprecated
        !           456:  * places.
        !           457:  */
        !           458: struct svc *
        !           459: move(svcp, depp)
        !           460: register struct svc *svcp;
        !           461: struct svc *depp;
        !           462: {
        !           463: 
        !           464:        depp->svc_count += svcp->svc_count;
        !           465:        depp->svc_stime += svcp->svc_stime;
        !           466:        depp->svc_utime += svcp->svc_utime;
        !           467:        depp->svc_etime += svcp->svc_etime;
        !           468:        while (svcp->svc_count) {
        !           469:                if (svcp == depp)
        !           470:                        depp--;
        !           471:                bcopy(svcp+1, svcp, sizeof *svcp);
        !           472:                svcp++;
        !           473:        }
        !           474:        (svcp-1)->svc_count = 0;
        !           475:        return (depp);
        !           476: }
        !           477: 
        !           478: /*
        !           479:  * Return the user-name for
        !           480:  * a user-ID.
        !           481:  */
        !           482: char *
        !           483: uname(uid)
        !           484: short uid;
        !           485: {
        !           486:        register struct passwd *pwp;
        !           487:        static char ubuf[15];
        !           488: 
        !           489:        if ((pwp = getpwuid(uid)) != NULL)
        !           490:                return (pwp->pw_name);
        !           491:        return (sprintf(ubuf, "%d", uid));
        !           492: }
        !           493: 
        !           494: /*
        !           495:  * Block copy of `n' bytes.
        !           496:  */
        !           497: bcopy(f, t, n)
        !           498: register char *f, *t;
        !           499: register unsigned n;
        !           500: {
        !           501:        if (n)
        !           502:                do {
        !           503:                        *t++ = *f++;
        !           504:                } while (--n);
        !           505: }
        !           506: 
        !           507: /*
        !           508:  * Return non-zero if an NCNAME-length string
        !           509:  * is unprintable.
        !           510:  */
        !           511: unprintable(s)
        !           512: register char *s;
        !           513: {
        !           514:        register int n = NCNAME;
        !           515:        register int c;
        !           516: 
        !           517:        do {
        !           518:                if ((c = *s++) == '\0')
        !           519:                        break;
        !           520:                if (!isascii(c) || !isprint(c))
        !           521:                        return (1);
        !           522:        } while (--n);
        !           523:        return (0);
        !           524: }
        !           525: 
        !           526: /*
        !           527:  * Ask whether or not to delete and
        !           528:  * entry.  Return 1 if yes.
        !           529:  */
        !           530: yes(s)
        !           531: register char *s;
        !           532: {
        !           533:        register int c, ans = 0;
        !           534: 
        !           535:        printf("%.*s ? ", NCNAME, s);
        !           536:        if ((c = getchar()) == 'y')
        !           537:                ans = 1;
        !           538:        while (c!='\n' && c!=EOF)
        !           539:                c = getchar();
        !           540:        return (ans);
        !           541: }
        !           542: 
        !           543: /*
        !           544:  * Qsort compare routine.
        !           545:  */
        !           546: compar(sp1, sp2)
        !           547: register struct sort *sp1, *sp2;
        !           548: {
        !           549:        register int rval;
        !           550: 
        !           551:        if (sp1->s_key == sp2->s_key)
        !           552:                return (0);
        !           553:        rval = 1;
        !           554:        if (sp1->s_key > sp2->s_key)
        !           555:                rval = -1;
        !           556:        if (rflag)
        !           557:                return (-rval);
        !           558:        return (rval);
        !           559: }
        !           560: 
        !           561: /*
        !           562:  * Return the number of CPU minutes from CPU HZ.
        !           563:  * or if `-j', return seconds/call.
        !           564:  */
        !           565: time_t
        !           566: units(hz, sp)
        !           567: time_t hz;
        !           568: register struct sort *sp;
        !           569: {
        !           570:        if (jflag)
        !           571:                return ((hz + HZ/2) / (HZ*sp->s_count)); else
        !           572:                return ((hz + MINHZ/2) / MINHZ);
        !           573: }
        !           574: 
        !           575: /*
        !           576:  * Print the percentage of
        !           577:  * `t' out of `total'.
        !           578:  */
        !           579: percent(t, total)
        !           580: time_t t, total;
        !           581: {
        !           582:        t *= 100;
        !           583:        printf("%3ld.", t/total);
        !           584:        t %= total;
        !           585:        if (t < 0)
        !           586:                t = -t;
        !           587:        printf("%1ld ", t*10/total);
        !           588: }
        !           589: 
        !           590: usage()
        !           591: {
        !           592:        fprintf(stderr, "Usage: sa [-abcjlmnrstu] [-v[n]] [file]\n");
        !           593:        exit(1);
        !           594: }
        !           595: 
        !           596: /* VARARGS */
        !           597: saerr(x)
        !           598: {
        !           599:        fprintf(stderr, "sa: %r", &x);
        !           600:        putc('\n', stderr);
        !           601:        exit(1);
        !           602: }

unix.superglobalmegacorp.com

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