Annotation of coherent/f/usr/spool/uucppublic/sa.c, revision 1.1

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

unix.superglobalmegacorp.com

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