Annotation of 3BSD/cmd/w.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * w - print system status (who and what)
                      3:  *
                      4:  * This program is similar to the systat command on Tenex/Tops 10/20
                      5:  * It needs read permission on /dev/mem, /dev/kmem, and /dev/drum.
                      6:  */
                      7: #include <sys/param.h>
                      8: #include <a.out.h>
                      9: #include <stdio.h>
                     10: #include <utmp.h>
                     11: #include <psout.h>
                     12: #include <time.h>
                     13: #include <sys/stat.h>
                     14: #include <sys/proc.h>
                     15: #include <sys/dir.h>
                     16: #include <sys/user.h>
                     17: #include <sys/pte.h>
                     18: #include <sys/vm.h>
                     19: 
                     20: #define ARGWIDTH       33      /* # chars left on 80 col crt for args */
                     21: 
                     22: struct smproc {
                     23:        char    w_flag;                 /* proc.p_flag */
                     24:        short   w_size;                 /* proc.p_size */
                     25:        long    w_seekaddr;             /* where to find args */
                     26:        long    w_lastpg;               /* disk address of stack */
                     27:        int     w_igintr;               /* true if ignores INTR and QUIT */
                     28:        time_t  w_time;                 /* CPU time used by this process */
                     29:        time_t  w_ctime;                /* CPU time used by children */
                     30:        dev_t   w_tty;                  /* tty device of process */
                     31:        char    w_comm[15];             /* user.u_comm, null terminated */
                     32:        char    w_args[ARGWIDTH+1];     /* args if interesting process */
                     33: } pr[NPROC];
                     34: 
                     35: struct nlist nl[] = {
                     36:        { "_proc" },
                     37: #define        X_PROC          0
                     38:        { "_swapdev" },
                     39: #define        X_SWAPDEV       1
                     40:        { "_swplo" },
                     41: #define        X_SWPLO         2
                     42:        { "_Usrptma" },
                     43: #define        X_USRPTMA       3
                     44:        { "_usrpt" },
                     45: #define        X_USRPT         4
                     46:        { "_nswap" },
                     47: #define        X_NSWAP         5
                     48:        { "_avenrun" },
                     49: #define        X_AVENRUN       6
                     50:        { "_bootime" },
                     51: #define        X_BOOTIME       7
                     52:        { 0 },
                     53: };
                     54: 
                     55: FILE   *ps;
                     56: FILE   *ut;
                     57: FILE   *bootfd;
                     58: int    kmem;
                     59: int    mem;
                     60: int    swap;                   /* /dev/kmem, mem, and swap */
                     61: int    nswap;
                     62: dev_t  tty;
                     63: char   doing[520];             /* process attached to terminal */
                     64: time_t proctime;               /* cpu time of process in doing */
                     65: double avenrun[3];
                     66: 
                     67: #define        DIV60(t)        ((t+30)/60)    /* x/60 rounded */ 
                     68: #define        TTYEQ           (tty == pr[i].w_tty)
                     69: 
                     70: char   *getargs();
                     71: char   *fread();
                     72: char   *ctime();
                     73: FILE   *popen();
                     74: struct tm *localtime();
                     75: 
                     76: int    debug;                  /* true if -d flag: debugging output */
                     77: int    header = 1;             /* true if -h flag: don't print heading */
                     78: int    lflag = 1;              /* true if -l flag: long style output */
                     79: int    login;                  /* true if invoked as login shell */
                     80: int    idle;                   /* number of minutes user is idle */
                     81: time_t jobtime;                /* total cpu time visible */
                     82: time_t now;                    /* the current time of day */
                     83: struct tm *nowt;               /* current time as time struct */
                     84: time_t bootime, uptime;        /* time of last reboot & elapsed time since */
                     85: int    np;                     /* number of processes currently active */
                     86: struct utmp utmp;
                     87: struct proc mproc;
                     88: struct user up;
                     89: char   fill[512];
                     90: 
                     91: main(argc, argv)
                     92:        char **argv;
                     93: {
                     94:        int days;
                     95:        register int i;
                     96:        int empty;
                     97:        char obuf[BUFSIZ];
                     98: 
                     99:        setbuf(stdout, obuf);
                    100:        login = (argv[0][0] == '-');
                    101:        while (argc > 1) {
                    102:                if (argv[1][0] == '-') {
                    103:                        for (i=1; argv[1][i]; i++) {
                    104:                                switch(argv[1][i]) {
                    105: 
                    106:                                case 'd':
                    107:                                        debug++;
                    108:                                        break;
                    109: 
                    110:                                case 'h':
                    111:                                        header = 0;
                    112:                                        break;
                    113: 
                    114:                                case 'l':
                    115:                                        lflag++;
                    116:                                        break;
                    117:                                case 's':
                    118:                                        lflag = 0;
                    119:                                        break;
                    120: 
                    121:                                default:
                    122:                                        printf("Bad flag %s\n", argv[1]);
                    123:                                        exit(1);
                    124:                                }
                    125:                        }
                    126:                        argc--; argv++;
                    127:                } else {
                    128:                        printf("Usage: %s [ -lh ]\n", argv[0]);
                    129:                        exit(1);
                    130:                }
                    131:        }
                    132: 
                    133:        readpr();
                    134: 
                    135:        ut = fopen("/etc/utmp","r");
                    136:        if (header) {
                    137:                time(&now);
                    138:                nowt = localtime(&now);
                    139:                prtat(nowt);
                    140:                lseek(kmem, (long)nl[X_BOOTIME].n_value, 0);
                    141:                read(kmem, &bootime, sizeof (bootime));
                    142:                uptime = now - bootime;
                    143:                printf("  up");
                    144:                days = uptime / (60*60*24);
                    145:                if (days > 0) {
                    146:                        printf(" %d day%s, ", days, days>1?"s":"");
                    147:                        uptime %= (60*60*24);
                    148:                }
                    149:                prttime(DIV60(uptime), "");
                    150:                printf("\t\t");
                    151:                printf("load average:");
                    152:                lseek(kmem, (long)nl[X_AVENRUN].n_value, 0);
                    153:                read(kmem, avenrun, sizeof(avenrun));
                    154:                for (i = 0; i < 3; i++) {
                    155:                        printf(" %.2f", avenrun[i]);
                    156:                        if (i < 2)
                    157:                                printf(",");
                    158:                }
                    159:                printf("\n");
                    160:                if (lflag)
                    161:                        printf("User     tty       login@  idle   JCPU   PCPU  what\n");
                    162:                else
                    163:                        printf("User    tty  idle  what\n");
                    164:                fflush(stdout);
                    165:        }
                    166:        for (;;) {      /* for each entry in utmp */
                    167:                if (fread(&utmp, sizeof(utmp), 1, ut) == NULL) {
                    168:                        fclose(ut);
                    169:                        exit(0);
                    170:                }
                    171:                if (utmp.ut_name[0] == '\0')
                    172:                        continue;       /* that tty is free */
                    173:                gettty();
                    174:                jobtime = 0;
                    175:                proctime = 0;
                    176:                strcpy(doing, "-");     /* default act: normally never prints */
                    177:                empty = 1;
                    178:                idle = findidle();
                    179:                for (i=0; i<np; i++) {  /* for each process on this tty */
                    180:                        if (!(TTYEQ))
                    181:                                continue;
                    182:                        jobtime += pr[i].w_time + pr[i].w_ctime;
                    183:                        proctime += pr[i].w_time;
                    184:                        if (!pr[i].w_igintr || empty) {
                    185:                                if (!pr[i].w_igintr)
                    186:                                        empty = 0;
                    187:                                strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm);
                    188:                                if (doing[0]==0 || doing[0]=='-' && doing[1]<=' ' || doing[0] == '?') {
                    189:                                        strcat(doing, " (");
                    190:                                        strcat(doing, pr[i].w_comm);
                    191:                                        strcat(doing, ")");
                    192:                                }
                    193:                        }
                    194:                }
                    195:                putline();
                    196:        }
                    197: }
                    198: 
                    199: /* figure out the major/minor device # pair for this tty */
                    200: gettty()
                    201: {
                    202:        char ttybuf[20];
                    203:        struct stat statbuf;
                    204: 
                    205:        ttybuf[0] = 0;
                    206:        strcpy(ttybuf, "/dev/");
                    207:        strcat(ttybuf, utmp.ut_line);
                    208:        stat(ttybuf, &statbuf);
                    209:        tty = statbuf.st_rdev;
                    210: }
                    211: 
                    212: /*
                    213:  * putline: print out the accumulated line of info about one user.
                    214:  */
                    215: putline()
                    216: {
                    217:        register int tm;
                    218: 
                    219:        /* print login name of the user */
                    220:        printf("%-8.8s ", utmp.ut_name);
                    221: 
                    222:        /* print tty user is on */
                    223:        if (lflag)
                    224:                /* long form: all (up to) 8 chars */
                    225:                printf("%-8.8s", utmp.ut_line);
                    226:        else {
                    227:                /* short form: 2 chars, skipping 'tty' if there */
                    228:                if (utmp.ut_line[0]=='t' && utmp.ut_line[1]=='t' && utmp.ut_line[2]=='y')
                    229:                        printf("%-2.2s", &utmp.ut_line[3]);
                    230:                else
                    231:                        printf("%-2.2s", utmp.ut_line);
                    232:        }
                    233: 
                    234:        if (lflag)
                    235:                /* print when the user logged in */
                    236:                prtat(localtime(&utmp.ut_time));
                    237: 
                    238:        /* print idle time */
                    239:        prttime(idle," ");
                    240: 
                    241:        if (lflag) {
                    242:                /* print CPU time for all processes & children */
                    243:                prttime(DIV60(jobtime)," ");
                    244:                /* print cpu time for interesting process */
                    245:                prttime(DIV60(proctime)," ");
                    246:        }
                    247: 
                    248:        /* what user is doing, either command tail or args */
                    249:        printf(" %-.32s\n",doing);
                    250:        fflush(stdout);
                    251: }
                    252: 
                    253: /* find & return number of minutes current tty has been idle */
                    254: findidle()
                    255: {
                    256:        struct stat stbuf;
                    257:        long lastaction, diff;
                    258:        char ttyname[20];
                    259: 
                    260:        strcpy(ttyname, "/dev/");
                    261:        strcatn(ttyname, utmp.ut_line, 8);
                    262:        stat(ttyname, &stbuf);
                    263:        time(&now);
                    264:        lastaction = stbuf.st_atime;
                    265:        diff = now - lastaction;
                    266:        diff = DIV60(diff);
                    267:        if (diff < 0) diff = 0;
                    268:        return(diff);
                    269: }
                    270: 
                    271: /*
                    272:  * prttime prints a time in hours and minutes.
                    273:  * The character string tail is printed at the end, obvious
                    274:  * strings to pass are "", " ", or "am".
                    275:  */
                    276: prttime(tim, tail)
                    277:        time_t tim;
                    278:        char *tail;
                    279: {
                    280:        register int didhrs = 0;
                    281: 
                    282:        if (tim >= 60) {
                    283:                printf("%3d:", tim/60);
                    284:                didhrs++;
                    285:        } else {
                    286:                printf("    ");
                    287:        }
                    288:        tim %= 60;
                    289:        if (tim > 0 || didhrs) {
                    290:                printf(didhrs&&tim<10 ? "%02d" : "%2d", tim);
                    291:        } else {
                    292:                printf("  ");
                    293:        }
                    294:        printf("%s", tail);
                    295: }
                    296: 
                    297: /* prtat prints a 12 hour time given a pointer to a time of day */
                    298: prtat(p)
                    299:        struct tm *p;
                    300: {
                    301:        register int t, pm;
                    302: 
                    303:        t = p -> tm_hour;
                    304:        pm = (t > 11);
                    305:        if (t > 11)
                    306:                t -= 12;
                    307:        if (t == 0)
                    308:                t = 12;
                    309:        prttime(t*60 + p->tm_min, pm ? "pm" : "am");
                    310: }
                    311: 
                    312: /*
                    313:  * readpr finds and reads in the array pr, containing the interesting
                    314:  * parts of the proc and user tables for each live process.
                    315:  */
                    316: readpr()
                    317: {
                    318:        int pn, mf, addr, c;
                    319:        int szpt, pfnum, i;
                    320:        struct pte *Usrptma, *usrpt, *pte, apte;
                    321:        daddr_t swplo;
                    322:        struct dblock db;
                    323: 
                    324:        nlist("/vmunix", nl);
                    325:        if (nl[0].n_type==0) {
                    326:                fprintf(stderr, "No namelist\n");
                    327:                exit(1);
                    328:        }
                    329:        Usrptma = (struct pte *) nl[X_USRPTMA].n_value;
                    330:        usrpt = (struct pte *) nl[X_USRPT].n_value;
                    331:        if ((kmem = open("/dev/kmem", 0)) < 0) {
                    332:                fprintf(stderr, "No kmem\n");
                    333:                exit(1);
                    334:        }
                    335:        if((mem = open("/dev/mem", 0)) < 0) {
                    336:                fprintf(stderr, "No mem\n");
                    337:                exit(1);
                    338:        }
                    339:        if ((swap = open("/dev/drum", 0)) < 0) {
                    340:                fprintf(stderr, "No drum\n");
                    341:                exit(1);
                    342:        }
                    343:        /*
                    344:         * read mem to find swap dev.
                    345:         */
                    346:        lseek(kmem, (long)nl[X_SWAPDEV].n_value, 0);
                    347:        read(kmem, &nl[X_SWAPDEV].n_value, sizeof(nl[X_SWAPDEV].n_value));
                    348:        /*
                    349:         * Find base of swap
                    350:         */
                    351:        lseek(kmem, (long)nl[X_SWPLO].n_value, 0);
                    352:        read(kmem, &swplo, sizeof(swplo));
                    353:        lseek(kmem, (long)nl[X_NSWAP].n_value, 0);
                    354:        read(kmem, &nswap, sizeof(nswap));
                    355:        /*
                    356:         * Locate proc table
                    357:         */
                    358:        np = 0;
                    359:        for (pn=0; pn<NPROC; pn++) {
                    360:                lseek(kmem, (long)(nl[X_PROC].n_value + pn*(sizeof mproc)), 0);
                    361:                read(kmem, &mproc, sizeof mproc);
                    362:                /* decide if it's an interesting process */
                    363:                if (mproc.p_stat==0 || mproc.p_pgrp==0)
                    364:                        continue;
                    365: 
                    366:                /* find & read in the user structure */
                    367:                if ((mproc.p_flag & SLOAD) == 0) {
                    368:                        /* not in memory - get from swap device */
                    369:                        addr = (mproc.p_swaddr+swplo)<<9;
                    370:                        lseek(swap, (long)addr, 0);
                    371:                        if (read(swap, &up, sizeof(up)) != sizeof(up)) {
                    372:                                continue;
                    373:                        }
                    374:                } else {
                    375:                        /* in memory - find pages */
                    376:                        for(c=0; c<UPAGES; c++) {
                    377:                                lseek(mem,mproc.p_addr[c]<<9,0);
                    378:                                addr = (int) ((char *)&up) + 512*c;
                    379:                                if ((mf=read(mem,addr,512)) != 512)
                    380:                                        continue;
                    381:                        }
                    382:                        szpt = up.u_pcb.pcb_szpt;
                    383:                        pte = &Usrptma[btokmx(mproc.p_p0br) + szpt-1];
                    384:                        lseek(kmem, (int)pte, 0);
                    385:                        read(kmem, &apte, sizeof(apte));
                    386:                        pr[np].w_seekaddr = ctob(apte.pg_pfnum);
                    387:                }
                    388:                vstodb(0, 1, &up.u_smap, &db, 1);
                    389:                pr[np].w_lastpg = ctob(swplo + db.db_base);
                    390:                if (up.u_ttyp == NULL)
                    391:                        continue;
                    392: 
                    393:                /* save the interesting parts */
                    394:                pr[np].w_flag = mproc.p_flag;
                    395:                pr[np].w_size = mproc.p_dsize + mproc.p_ssize;
                    396:                pr[np].w_igintr = (up.u_signal[2]==1 && up.u_signal[3]==1);
                    397:                pr[np].w_time = up.u_utime + up.u_stime;
                    398:                pr[np].w_ctime = up.u_cutime + up.u_cstime;
                    399:                pr[np].w_tty = up.u_ttyd;
                    400:                up.u_comm[14] = 0;      /* Bug: This bombs next field. */
                    401:                strcpy(pr[np].w_comm, up.u_comm);
                    402:                if (pr[np].w_igintr == 0) {
                    403:                        /*
                    404:                         * Get args if there's a chance we'll print it.
                    405:                         * Cant just save pointer: getargs returns static place.
                    406:                         * Cant use strcpyn: that crock blank pads.
                    407:                         */
                    408:                        pr[np].w_args[0] = 0;
                    409:                        strcatn(pr[np].w_args,getargs(&pr[np]),ARGWIDTH);
                    410:                }
                    411:                np++;
                    412:        }
                    413: }
                    414: 
                    415: /*
                    416:  * getargs: given a pointer to a proc structure, this looks at the swap area
                    417:  * and tries to reconstruct the arguments. This is straight out of ps.
                    418:  */
                    419: char *
                    420: getargs(p)
                    421:        struct smproc *p;
                    422: {
                    423:        int c, addr, nbad;
                    424:        static int abuf[512/sizeof(int)];
                    425:        struct pte pagetbl[NPTEPG];
                    426:        register int *ip;
                    427:        register char *cp, *cp1;
                    428: 
                    429:        if ((p->w_flag & SLOAD) == 0) {
                    430:                lseek(swap, p->w_lastpg, 0);
                    431:                if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
                    432:                        return(p->w_comm);
                    433:        } else {
                    434:                c = p->w_seekaddr;
                    435:                lseek(mem,c,0);
                    436:                if (read(mem,pagetbl,NBPG) != NBPG)
                    437:                        return(p->w_comm);
                    438:                if (pagetbl[NPTEPG-1].pg_fod==0 && pagetbl[NPTEPG-1].pg_pfnum) {
                    439:                        lseek(mem,ctob(pagetbl[NPTEPG-1].pg_pfnum),0);
                    440:                        if (read(mem,abuf,sizeof(abuf)) != sizeof(abuf))
                    441:                                return(p->w_comm);
                    442:                } else {
                    443:                        lseek(swap, p->w_lastpg, 0);
                    444:                        if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
                    445:                                return(p->w_comm);
                    446:                }
                    447:        }
                    448:        abuf[127] = 0;
                    449:        for (ip = &abuf[126]; ip > abuf;) {
                    450:                /* Look from top for -1 or 0 as terminator flag. */
                    451:                if (*--ip == -1 || *ip == 0) {
                    452:                        cp = (char *)(ip+1);
                    453:                        if (*cp==0)
                    454:                                cp++;
                    455:                        nbad = 0;       /* up to 5 funny chars as ?'s */
                    456:                        for (cp1 = cp; cp1 < (char *)&abuf[128]; cp1++) {
                    457:                                c = *cp1&0177;
                    458:                                if (c==0)  /* nulls between args => spaces */
                    459:                                        *cp1 = ' ';
                    460:                                else if (c < ' ' || c > 0176) {
                    461:                                        if (++nbad >= 5) {
                    462:                                                *cp1++ = ' ';
                    463:                                                break;
                    464:                                        }
                    465:                                        *cp1 = '?';
                    466:                                } else if (c=='=') {    /* Oops - found an
                    467:                                                         * environment var, back
                    468:                                                         * over & erase it. */
                    469:                                        *cp1 = 0;
                    470:                                        while (cp1>cp && *--cp1!=' ')
                    471:                                                *cp1 = 0;
                    472:                                        break;
                    473:                                }
                    474:                        }
                    475:                        while (*--cp1==' ')     /* strip trailing spaces */
                    476:                                *cp1 = 0;
                    477:                        return(cp);
                    478:                }
                    479:        }
                    480:        return (p->w_comm);
                    481: }
                    482: 
                    483: /*
                    484:  * Given a base/size pair in virtual swap area,
                    485:  * return a physical base/size pair which is the
                    486:  * (largest) initial, physically contiguous block.
                    487:  */
                    488: vstodb(vsbase, vssize, dmp, dbp, rev)
                    489:        register int vsbase;
                    490:        int vssize;
                    491:        struct dmap *dmp;
                    492:        register struct dblock *dbp;
                    493: {
                    494:        register int blk = DMMIN;
                    495:        register swblk_t *ip = dmp->dm_map;
                    496: 
                    497:        if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
                    498:                panic("vstodb");
                    499:        while (vsbase >= blk) {
                    500:                vsbase -= blk;
                    501:                if (blk < DMMAX)
                    502:                        blk *= 2;
                    503:                ip++;
                    504:        }
                    505:        if (*ip <= 0 || *ip + blk > nswap)
                    506:                panic("vstodb *ip");
                    507:        dbp->db_size = min(vssize, blk - vsbase);
                    508:        dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
                    509: }
                    510: 
                    511: panic(cp)
                    512:        char *cp;
                    513: {
                    514: 
                    515:        /* printf("%s\n", cp); */
                    516: }
                    517: 
                    518: min(a, b)
                    519: {
                    520: 
                    521:        return (a < b ? a : b);
                    522: }

unix.superglobalmegacorp.com

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