# 2.11BSD#431 - /usr/src/usr.sbin/sa/sa.c

##### Functions

    Bcmp              X
    Dcmp              X
    Kcmp              X
    cellcmp           X
    col               X
    column            X
    dcmp              X
    doacct            X
    enter             X
    expand            X
    finduser          X
    getmaxuid         X
    getnames          X
    htaballoc         X
    init              X
    kcmp              X
    main              X
    makekey           X
    ncmp              X
    printmoney        X
    strip             X
    sum               X
    taballoc          X
    tabinit           X
    tcmp              X
    usage             X
    wasuser           X

##### Variables

    Dflg              X
    Kflg              X
    acctbuf           X
    aflg              X
    allochead         X
    alloctail         X
    bflg              X
    cflg              X
    dflg              X
    fflg              X
    htab              X
    htabinstall       X
    iflg              X
    jflg              X
    junkp             X
    kflg              X
    lflg              X
    maxuser           X
    mflg              X
    ncom              X
    newbox            X
    nexttab           X
    nflg              X
    ntabs             X
    oflg              X
    pgdiv             X
    rflg              X
    savacct           X
    sflg              X
    tabsleft          X
    tcpu              X
    tflg              X
    thres             X
    timem             X
    tio               X
    treal             X
    tsys              X
    uflg              X
    usracct           X
    utmp              X
    vflg              X

##### Macros

    ACCT              X
    ALLOCQTY          X
    DECLITERATE       X
    HASHCLOGGED       X
    ISPROCESS         X
    ISUSER            X
    NAMELG            X
    NC                X
    NHASH             X
    PROCESSITERATE    X
    SAVACCT           X
    TABCHUNKS         X
    TABDALLOP         X
    USERITERATE       X
    USERKEY           X
    USERSLOP          X
    USRACCT           X
    pgtok             X
    us_cnt            X
    us_ctime          X
    us_imem           X
    us_io             X

##### struct's

    Olduser           X
    allocbox          X
    chunkdesc         X
    hashdallop        X
    process           X
    user              X

##### unions's

    Tab               X

##### typedef's

    cell              X

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

#### Defined functions

Bcmp defined in line 678; used 2 times

- in line 269, 303

Dcmp defined in line 756; used 2 times

- in line 269, 317

Kcmp defined in line 699; used 2 times

- in line 269, 328

cellcmp defined in line 654; used 3 times

- in line 259, 464, 481

col defined in line 564; used 5 times

- in line 544-551(5)

column defined in line 534; used 2 times

- in line 455, 497

dcmp defined in line 736; used 2 times

- in line 269, 313

doacct defined in line 579; used 1 times

- in line 388

enter defined in line 1024; used 6 times

- in line 100, 408, 632, 815, 855, 926

expand defined in line 876; used 7 times

- in line 230, 615-617(3), 636-642(3)

finduser defined in line 917; used 4 times

- in line 102, 623, 837, 909

getmaxuid defined in line 947; used 2 times

- in line 101, 286

getnames defined in line 933; used 1 times

- in line 517

htaballoc defined in line 999; used 2 times

- in line 971, 1074

init defined in line 803; used 1 times

- in line 387

kcmp defined in line 716; used 2 times

- in line 269, 324

main defined in line 272; never used
makekey defined in line 893; used 1 times

- in line 926

ncmp defined in line 667; used 2 times

- in line 269, 332

printmoney defined in line 511; used 1 times

- in line 452

strip defined in line 846; used 1 times

- in line 398

sum defined in line 794; used 7 times

- in line 270, 682-685(3), 776-780(3)

taballoc defined in line 975; used 1 times

- in line 1082

tabinit defined in line 963; used 1 times

- in line 288

tcmp defined in line 773; used 3 times

- in line 269, 289, 672

usage defined in line 504; used 2 times

- in line 367, 380

wasuser defined in line 902; used 4 times

- in line 103, 431, 519, 941

#### Defined variables

Dflg defined in line 34; used 2 times

- in line 316, 554

Kflg defined in line 38; used 2 times

- in line 327, 558

UserKey defined in line 891; used 3 times

- in line 897-899(3)

acctbuf defined in line 31; used 1 times

- in line 29

aflg defined in line 41; used 3 times

- in line 335, 345, 399

allochead defined in line 153; used 4 times

- in line 170, 181, 965, 984

alloctail defined in line 154; used 7 times

- in line 175, 188, 966, 983-987(4)

bflg defined in line 50; used 1 times

- in line 302

cflg defined in line 33; used 3 times

- in line 309, 539, 572

dflg defined in line 35; used 2 times

- in line 312, 554

fflg defined in line 46; used 5 times

- in line 352, 852, 858-860(2), 869

htab defined in line 220; used 7 times

- in line 969, 1008-1012(4), 1046, 1075

htabinstall defined in line 262; used 3 times

- in line 908-910(2), 1081

iflg defined in line 36; used 2 times

- in line 299, 386

jflg defined in line 37; used 2 times

- in line 320, 569

junkp defined in line 260; used 16 times

- in line 407-414(8), 850-855(2), 862-867(6)

kflg defined in line 39; used 2 times

- in line 323, 558

lflg defined in line 32; used 2 times

- in line 306, 547

maxuser defined in line 80; used 4 times

- in line 286, 430, 518, 922

mflg defined in line 51; used 2 times

- in line 358, 451

ncom defined in line 229; used 5 times

- in line 455, 540-542(2), 630, 816

newbox defined in line 155; used 5 times

- in line 980-987(5)

nexttab defined in line 156; used 5 times

- in line 176, 190, 967, 982, 996

nflg defined in line 40; used 1 times

- in line 331

ntabs defined in line 158; used 4 times

- in line 970, 991-994(3)

oflg defined in line 43; used 2 times

- in line 296, 545

pgdiv defined in line 266; used 4 times

- in line 267, 283-285(3)

rflg defined in line 42; used 14 times

- in line 338, 673, 687-692(2), 704-709(2), 724-729(2), 744-749(2), 761-766(2), 782-787(2)

savacct defined in line 257; used 3 times

- in line 364, 439, 812

sccsid defined in line 2; never used
sflg defined in line 49; used 2 times

- in line 344, 417

tabsleft defined in line 157; used 4 times

- in line 968, 979-981(2), 990

tcpu defined in line 224; used 6 times

- in line 455, 546-551(3), 641, 820

tflg defined in line 44; used 2 times

- in line 341, 552

thres defined in line 261; used 5 times

- in line 349, 384-385(2), 854-857(2)

timem defined in line 227; used 3 times

- in line 455, 634, 826

tio defined in line 226; used 3 times

- in line 455, 646, 824

treal defined in line 223; used 4 times

- in line 455, 544, 638, 818

tsys defined in line 225; used 6 times

- in line 455, 546-551(3), 644, 822

uflg defined in line 47; used 3 times

- in line 355, 389, 618

usracct defined in line 256; used 3 times

- in line 361, 419, 831

utmp defined in line 53; used 1 times

- in line 54

vflg defined in line 45; used 2 times

- in line 348, 397

#### Defined struct's

Olduser defined in line 56; used 8 times

- in line 65(2), 433-436(4), 834(2)

allocbox defined in line 148; used 14 times

- in line 149-155(8), 277(2), 849(2), 980(2)

chunkdesc defined in line 206; used 6 times

- in line 281(2), 467-468(4)

hashdallop defined in line 215; used 12 times

- in line 217-220(4), 1001(2), 1007(4), 1032(2)

process defined in line 82; used 8 times

- in line 93(2), 444(2), 806(2), 814(2)

user defined in line 63; used 30 times

- in line 94(2), 102-103(4), 420-421(4), 515(2), 587(2), 805-808(4), 902-906(4), 917(2), 926(2), 935(2), 950(2)

#### Defined union's

Tab defined in line 92; used 2 times

- in line 97(2)

#### Defined typedef's

cell defined in line 97; used 27 times

- in line 100, 156, 228, 260, 655, 668, 679, 700, 717, 737, 757, 774, 795, 975, 1024-150(2), 175, 188, 207, 218, 278, 464, 588, 807, 850, 1029-1033(2)

#### Defined macros

ACCT defined in line 253; used 1 times

- in line 377

ALLOCQTY defined in line 974; used 1 times

- in line 980

DECLITERATE defined in line 169; used 2 times

- in line 195-199(2)

HASHCLOGGED defined in line 1016; used 1 times

- in line 1068

ISPROCESS defined in line 144; used 5 times

- in line 196, 495, 657-662(3)

ISUSER defined in line 145; used 1 times

- in line 200

NAMELG defined in line 54; used 3 times

- in line 66, 891, 942

NC defined in line 29; used 12 times

- in line 64, 83, 401, 603, 609-613(3), 620, 1037, 1058-1061(2), 1084

NHASH defined in line 214; used 7 times

- in line 218, 1016, 1041-1043(2), 1049-1052(3)

PROCESSITERATE defined in line 194; used 3 times

- in line 400, 443, 856

SAVACCT defined in line 252; used 1 times

- in line 257

TABCHUNKS defined in line 180; used 2 times

- in line 463, 470

TABDALLOP defined in line 147; used 5 times

- in line 150, 174, 187-190(2), 981

USERITERATE defined in line 198; never used
USERKEY defined in line 143; used 3 times

- in line 144-145(2), 898

USERSLOP defined in line 79; never used
USRACCT defined in line 251; used 1 times

- in line 256

pgtok defined in line 267; used 1 times

- in line 616

us_cnt defined in line 68; used 4 times

- in line 520, 526, 626, 836

us_ctime defined in line 69; used 2 times

- in line 526, 627

us_imem defined in line 71; used 2 times

- in line 528, 628

us_io defined in line 70; used 2 times

- in line 527, 629

Last modified: 1997-02-16 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3736 |