1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)ps.c	5.9 (Berkeley) 5/8/86";
  15: #endif not lint
  16: 
  17: #include <stdio.h>
  18: #include <ctype.h>
  19: #include <a.out.h>
  20: #include <pwd.h>
  21: #include <sys/param.h>
  22: #include <sys/ioctl.h>
  23: #include <sys/tty.h>
  24: #include <sys/dir.h>
  25: #include <sys/user.h>
  26: #include <sys/proc.h>
  27: #include <machine/pte.h>
  28: #include <sys/vm.h>
  29: #include <sys/text.h>
  30: #include <sys/stat.h>
  31: #include <sys/mbuf.h>
  32: #include <math.h>
  33: #include <errno.h>
  34: 
  35: char *nl_names[] = {
  36:     "_proc",
  37: #define X_PROC      0
  38:     "_Usrptmap",
  39: #define X_USRPTMAP  1
  40:     "_usrpt",
  41: #define X_USRPT     2
  42:     "_text",
  43: #define X_TEXT      3
  44:     "_nswap",
  45: #define X_NSWAP     4
  46:     "_maxslp",
  47: #define X_MAXSLP    5
  48:     "_ccpu",
  49: #define X_CCPU      6
  50:     "_ecmx",
  51: #define X_ECMX      7
  52:     "_nproc",
  53: #define X_NPROC     8
  54:     "_ntext",
  55: #define X_NTEXT     9
  56:     "_dmmin",
  57: #define X_DMMIN     10
  58:     "_dmmax",
  59: #define X_DMMAX     11
  60:     "_Sysmap",
  61: #define X_SYSMAP    12
  62:     "_Syssize",
  63: #define X_SYSSIZE   13
  64:     "_inode",
  65: #define X_INODE     14
  66:     "_file",
  67: #define X_FILE      15
  68:     "_cfree",
  69: #define X_CFREE     16
  70:     "_callout",
  71: #define X_CALLOUT   17
  72:     "_swapmap",
  73: #define X_SWAPMAP   18
  74:     "_argmap",
  75: #define X_ARGMAP    19
  76:     "_kernelmap",
  77: #define X_KERNELMAP 20
  78:     "_mbmap",
  79: #define X_MBMAP     21
  80:     "_namecache",
  81: #define X_NCH       22
  82:     "_quota",
  83: #define X_QUOTA     23
  84:     "_dquot",
  85: #define X_DQUOT     24
  86:     "_swbuf",
  87: #define X_SWBUF     25
  88:     "_buf",
  89: #define X_BUF       26
  90:     "_cmap",
  91: #define X_CMAP      27
  92:     "_buffers",
  93: #define X_BUFFERS   28
  94:     ""
  95: };
  96: 
  97: struct nlist *nl;           /* all because we can't init unions */
  98: int nllen;              /* # of nlist entries */
  99: 
 100: struct  savcom {
 101:     union {
 102:         struct  lsav *lp;
 103:         float   u_pctcpu;
 104:         struct  vsav *vp;
 105:         int s_ssiz;
 106:     } s_un;
 107:     struct  asav *ap;
 108: } *savcom;
 109: 
 110: struct  asav {
 111:     char    *a_cmdp;
 112:     int a_flag;
 113:     short   a_stat, a_uid, a_pid, a_nice, a_pri, a_slptime, a_time;
 114:     size_t  a_size, a_rss, a_tsiz, a_txtrss;
 115:     short   a_xccount;
 116:     char    a_tty[MAXNAMLEN+1];
 117:     dev_t   a_ttyd;
 118:     time_t  a_cpu;
 119:     size_t  a_maxrss;
 120: };
 121: 
 122: char    *lhdr;
 123: int wcwidth;        /* width of the wchan field for sprintf*/
 124: struct  lsav {
 125:     short   l_ppid;
 126:     char    l_cpu;
 127:     int l_addr;
 128:     caddr_t l_wchan;
 129: };
 130: 
 131: char    *uhdr;
 132: char    *shdr;
 133: 
 134: char    *vhdr;
 135: struct  vsav {
 136:     u_int   v_majflt;
 137:     size_t  v_swrss, v_txtswrss;
 138:     float   v_pctcpu;
 139: };
 140: 
 141: #define NPROC   16
 142: 
 143: struct  proc proc[NPROC];       /* a few, for less syscalls */
 144: struct  proc *mproc;
 145: struct  text *text;
 146: 
 147: union {
 148:     struct  user user;
 149:     char    upages[UPAGES][NBPG];
 150: } user;
 151: #define u   user.user
 152: 
 153: #ifndef PSFILE
 154: char    *psdb   = "/etc/psdatabase";
 155: #else
 156: char    *psdb   = PSFILE;
 157: #endif
 158: 
 159: int chkpid = -1;
 160: int aflg, cflg, eflg, gflg, kflg, lflg, nflg, sflg,
 161:     uflg, vflg, xflg, Uflg;
 162: int nchans;             /* total # of wait channels */
 163: char    *tptr;
 164: char    *gettty(), *getcmd(), *getname(), *savestr(), *state();
 165: char    *rindex(), *calloc(), *sbrk(), *strcpy(), *strcat(), *strncat();
 166: char    *strncpy(), *index(), *ttyname(), mytty[MAXPATHLEN+1];
 167: char    *malloc(), *getchan();
 168: long    lseek();
 169: off_t   vtophys();
 170: double  pcpu(), pmem();
 171: int wchancomp();
 172: int pscomp();
 173: int nswap, maxslp;
 174: struct  text *atext;
 175: double  ccpu;
 176: int ecmx;
 177: struct  pte *Usrptmap, *usrpt;
 178: int nproc, ntext;
 179: int dmmin, dmmax;
 180: struct  pte *Sysmap;
 181: int Syssize;
 182: 
 183: int nttys;
 184: 
 185: struct  ttys {
 186:     dev_t   ttyd;
 187:     int cand;
 188:     char    name[MAXNAMLEN+1];
 189: } *allttys;
 190: int cand[16] = {-1, -1, -1, -1, -1, -1, -1, -1,
 191:         -1, -1, -1, -1, -1, -1, -1, -1};
 192: struct lttys {
 193:     struct ttys ttys;
 194:     struct lttys *next;
 195: } *lallttys;
 196: 
 197: /*
 198:  * struct for the symbolic wait channel info
 199:  *
 200:  * WNAMESIZ is the max # of chars saved of the symbolic wchan gleaned
 201:  * from the namelist.  Normally, only WSNAMESIZ are printed in the long
 202:  * format, unless the terminal width is greater than WTSIZ wide.
 203:  */
 204: #define WNAMESIZ    12
 205: #define WSNAMESIZ   6
 206: #define WTSIZ       95
 207: 
 208: struct wchan {
 209:     char    wc_name[WNAMESIZ+1];    /* symbolic name */
 210:     caddr_t wc_caddr;       /* addr in kmem */
 211: } *wchanhd;             /* an array sorted by wc_caddr */
 212: 
 213: #define NWCINDEX    10      /* the size of the index array */
 214: 
 215: caddr_t wchan_index[NWCINDEX];      /* used to speed searches */
 216: /*
 217:  * names listed here are not kept as wait channels -- this is used to
 218:  * remove names that confuse ps, like symbols that define the end of an
 219:  * array that happen to be equal to the next symbol.
 220:  */
 221: char *wchan_stop_list[] = {
 222:     "umbabeg",
 223:     "umbaend",
 224:     "calimit",
 225:     NULL
 226: };
 227: 
 228: int npr;
 229: 
 230: int cmdstart;
 231: int twidth;
 232: struct  winsize win;
 233: char    *kmemf, *memf, *swapf, *nlistf;
 234: int kmem, mem, swap = -1;
 235: int rawcpu, sumcpu;
 236: 
 237: int pcbpf;
 238: int argaddr;
 239: 
 240: #define pgtok(a)    ((a)/(1024/NBPG))
 241: 
 242: main(argc, argv)
 243:     char **argv;
 244: {
 245:     register int i, j;
 246:     register char *ap;
 247:     int uid;
 248:     off_t procp;
 249:     int width;
 250: 
 251:     if (ioctl(1, TIOCGWINSZ, &win) == -1)
 252:         twidth = 80;
 253:     else
 254:         twidth = (win.ws_col == 0 ? 80 : win.ws_col);
 255:     argc--, argv++;
 256:     if (argc > 0) {
 257:         ap = argv[0];
 258:         while (*ap) switch (*ap++) {
 259: 
 260:         case 'C':
 261:             rawcpu++;
 262:             break;
 263:         case 'S':
 264:             sumcpu++;
 265:             break;
 266: 
 267:         case 'U':
 268:             Uflg++;
 269:             break;
 270: 
 271:         case 'a':
 272:             aflg++;
 273:             break;
 274:         case 'c':
 275:             cflg = !cflg;
 276:             break;
 277:         case 'e':
 278:             eflg++;
 279:             break;
 280:         case 'g':
 281:             gflg++;
 282:             break;
 283:         case 'k':
 284:             kflg++;
 285:             break;
 286:         case 'l':
 287:             lflg++;
 288:             break;
 289:         case 'n':
 290:             nflg++;
 291:             break;
 292:         case 's':
 293:             sflg++;
 294:             break;
 295:         case 't':
 296:             if (*ap)
 297:                 tptr = ap;
 298:             else if ((tptr = ttyname(0)) != 0) {
 299:                 tptr = strcpy(mytty, tptr);
 300:                 if (strncmp(tptr, "/dev/", 5) == 0)
 301:                     tptr += 5;
 302:             }
 303:             if (strncmp(tptr, "tty", 3) == 0)
 304:                 tptr += 3;
 305:             aflg++;
 306:             gflg++;
 307:             if (tptr && *tptr == '?')
 308:                 xflg++;
 309:             while (*ap)
 310:                 ap++;
 311:             break;
 312:         case 'u':
 313:             uflg++;
 314:             break;
 315:         case 'v':
 316:             cflg = 1;
 317:             vflg++;
 318:             break;
 319:         case 'w':
 320:             if (twidth < 132)
 321:                 twidth = 132;
 322:             else
 323:                 twidth = BUFSIZ;
 324:             break;
 325:         case 'x':
 326:             xflg++;
 327:             break;
 328:         default:
 329:             if (!isdigit(ap[-1]))
 330:                 break;
 331:             chkpid = atoi(--ap);
 332:             *ap = 0;
 333:             aflg++;
 334:             xflg++;
 335:             break;
 336:         }
 337:     }
 338:     openfiles(argc, argv);
 339:     getkvars(argc, argv);
 340:     uid = getuid();
 341:     printhdr();
 342:     procp = getw(nl[X_PROC].n_value);
 343:     nproc = getw(nl[X_NPROC].n_value);
 344:     savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
 345:     for (i=0; i<nproc; i += NPROC) {
 346:         klseek(kmem, (long)procp, 0);
 347:         j = nproc - i;
 348:         if (j > NPROC)
 349:             j = NPROC;
 350:         j *= sizeof (struct proc);
 351:         if (read(kmem, (char *)proc, j) != j) {
 352:             cantread("proc table", kmemf);
 353:             exit(1);
 354:         }
 355:         procp += j;
 356:         for (j = j / sizeof (struct proc) - 1; j >= 0; j--) {
 357:             mproc = &proc[j];
 358:             if (mproc->p_stat == 0 ||
 359:                 mproc->p_pgrp == 0 && xflg == 0)
 360:                 continue;
 361:             if (tptr == 0 && gflg == 0 && xflg == 0 &&
 362:                 mproc->p_ppid == 1)
 363:                 continue;
 364:             if (uid != mproc->p_uid && aflg==0)
 365:                 continue;
 366:             if (chkpid != -1 && chkpid != mproc->p_pid)
 367:                 continue;
 368:             if (vflg && gflg == 0 && xflg == 0) {
 369:                 if (mproc->p_stat == SZOMB ||
 370:                     mproc->p_flag&SWEXIT)
 371:                     continue;
 372:                 if (mproc->p_slptime > MAXSLP &&
 373:                     (mproc->p_stat == SSLEEP ||
 374:                      mproc->p_stat == SSTOP))
 375:                 continue;
 376:             }
 377:             save();
 378:         }
 379:     }
 380:     width = twidth - cmdstart - 2;
 381:     if (width < 0)
 382:         width = 0;
 383:     qsort((char *) savcom, npr, sizeof(savcom[0]), pscomp);
 384:     for (i=0; i<npr; i++) {
 385:         register struct savcom *sp = &savcom[i];
 386:         if (lflg)
 387:             lpr(sp);
 388:         else if (vflg)
 389:             vpr(sp);
 390:         else if (uflg)
 391:             upr(sp);
 392:         else
 393:             spr(sp);
 394:         if (sp->ap->a_stat == SZOMB)
 395:             printf(" <defunct>");
 396:         else if (sp->ap->a_flag & SWEXIT)
 397:             printf(" <exiting>");
 398:         else if (sp->ap->a_pid == 0)
 399:             printf(" swapper");
 400:         else if (sp->ap->a_pid == 2)
 401:             printf(" pagedaemon");
 402:         else
 403:             printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
 404:         printf("\n");
 405:     }
 406:     exit(npr == 0);
 407: }
 408: 
 409: getw(loc)
 410:     unsigned long loc;
 411: {
 412:     int word;
 413: 
 414:     klseek(kmem, (long)loc, 0);
 415:     if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
 416:         printf("error reading kmem at %x\n", loc);
 417:     return (word);
 418: }
 419: 
 420: klseek(fd, loc, off)
 421:     int fd;
 422:     long loc;
 423:     int off;
 424: {
 425:     if (kflg) {
 426:         if ((loc = vtophys(loc)) == -1)
 427:             return;
 428:     }
 429:     (void) lseek(fd, (long)loc, off);
 430: }
 431: 
 432: /*
 433:  * Version allows change of db format w/o temporarily bombing ps's
 434:  */
 435: char thisversion[4] = "V2";     /* length must remain 4 */
 436: 
 437: writepsdb(unixname)
 438:     char *unixname;
 439: {
 440:     register FILE *fp;
 441:     struct lttys *lt;
 442:     struct stat stb;
 443: 
 444:     setgid(getgid());
 445:     setuid(getuid());
 446:     if ((fp = fopen(psdb, "w")) == NULL) {
 447:         perror(psdb);
 448:         exit(1);
 449:     } else
 450:         fchmod(fileno(fp), 0644);
 451: 
 452:     fwrite(thisversion, sizeof thisversion, 1, fp);
 453:     fwrite(unixname, strlen(unixname) + 1, 1, fp);
 454:     if (stat(unixname, &stb) < 0)
 455:         stb.st_mtime = 0;
 456:     fwrite((char *) &stb.st_mtime, sizeof stb.st_mtime, 1, fp);
 457: 
 458:     fwrite((char *) &nllen, sizeof nllen, 1, fp);
 459:     fwrite((char *) nl, sizeof (struct nlist), nllen, fp);
 460:     fwrite((char *) cand, sizeof (cand), 1, fp);
 461:     fwrite((char *) &nttys, sizeof nttys, 1, fp);
 462:     for (lt = lallttys ; lt ; lt = lt->next)
 463:         fwrite((char *)&lt->ttys, sizeof (struct ttys), 1, fp);
 464:     fwrite((char *) &nchans, sizeof nchans, 1, fp);
 465:     fwrite((char *) wchanhd, sizeof (struct wchan), nchans, fp);
 466:     fwrite((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
 467:     fclose(fp);
 468: }
 469: 
 470: readpsdb(unixname)
 471:     char *unixname;
 472: {
 473:     register i;
 474:     register FILE *fp;
 475:     char unamebuf[BUFSIZ];
 476:     char *p = unamebuf;
 477:     char dbversion[sizeof thisversion];
 478:     struct stat stb;
 479:     time_t dbmtime;
 480:     extern int errno;
 481: 
 482:     if ((fp = fopen(psdb, "r")) == NULL) {
 483:         if (errno == ENOENT)
 484:             return (0);
 485:         perror(psdb);
 486:         exit(1);
 487:     }
 488: 
 489:     /*
 490: 	 * Does the db file match this unix?
 491: 	 */
 492:     fread(dbversion, sizeof dbversion, 1, fp);
 493:     if (bcmp(thisversion, dbversion, sizeof thisversion))
 494:         goto bad;
 495:     while ((*p = getc(fp)) != '\0')
 496:         p++;
 497:     if (strcmp(unixname, unamebuf))
 498:         goto bad;
 499:     fread((char *) &dbmtime, sizeof dbmtime, 1, fp);
 500:     if (stat(unixname, &stb) < 0)
 501:         stb.st_mtime = 0;
 502:     if (stb.st_mtime != dbmtime)
 503:         goto bad;
 504: 
 505:     fread((char *) &nllen, sizeof nllen, 1, fp);
 506:     nl = (struct nlist *) malloc (nllen * sizeof (struct nlist));
 507:     fread((char *) nl, sizeof (struct nlist), nllen, fp);
 508:     fread((char *) cand, sizeof (cand), 1, fp);
 509:     fread((char *) &nttys, sizeof nttys, 1, fp);
 510:     allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
 511:     if (allttys == NULL) {
 512:         fprintf(stderr, "ps: Can't malloc space for tty table\n");
 513:         exit(1);
 514:     }
 515:     fread((char *) allttys, sizeof (struct ttys), nttys, fp);
 516:     fread((char *) &nchans, sizeof nchans, 1, fp);
 517:     wchanhd = (struct wchan *) malloc(nchans * sizeof (struct wchan));
 518:     if (wchanhd == NULL) {
 519:         fprintf(stderr, "ps: Can't malloc space for wait channels\n");
 520:         nflg++;
 521:         fseek(fp, (long) nchans * sizeof (struct wchan), 1);
 522:     } else
 523:         fread((char *) wchanhd, sizeof (struct wchan), nchans, fp);
 524:     fread((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
 525:     fclose(fp);
 526:     return(1);
 527: 
 528: bad:
 529:     fclose(fp);
 530:     return(0);
 531: }
 532: 
 533: openfiles(argc, argv)
 534:     char **argv;
 535: {
 536: 
 537:     kmemf = "/dev/kmem";
 538:     if (kflg)
 539:         kmemf = argc > 2 ? argv[2] : "/vmcore";
 540:     kmem = open(kmemf, 0);
 541:     if (kmem < 0) {
 542:         perror(kmemf);
 543:         exit(1);
 544:     }
 545:     if (kflg)  {
 546:         mem = kmem;
 547:         memf = kmemf;
 548:     } else {
 549:         memf = "/dev/mem";
 550:         mem = open(memf, 0);
 551:         if (mem < 0) {
 552:             perror(memf);
 553:             exit(1);
 554:         }
 555:     }
 556:     if (kflg == 0 || argc > 3) {
 557:         swapf = argc>3 ? argv[3]: "/dev/drum";
 558:         swap = open(swapf, 0);
 559:         if (swap < 0) {
 560:             perror(swapf);
 561:             exit(1);
 562:         }
 563:     }
 564: }
 565: 
 566: getkvars(argc, argv)
 567:     char **argv;
 568: {
 569:     int faildb = 0;         /* true if psdatabase init failed */
 570:     int i;
 571: 
 572:     nlistf = argc > 1 ? argv[1] : "/vmunix";
 573:     if (Uflg) {
 574:         init_nlist();
 575:         nlist(nlistf, nl);
 576:         getvchans();
 577:         getdev();
 578:         writepsdb(nlistf);
 579:         exit (0);
 580:     } else if (!readpsdb(nlistf)) {
 581:         init_nlist();
 582:         if (!kflg)
 583:             nl[X_SYSMAP].n_un.n_name = "";
 584:         faildb = 1;
 585:         nlist(nlistf, nl);
 586:         nttys = 0;
 587:         getdev();
 588:     }
 589: 
 590:     if (nl[0].n_type == 0) {
 591:         fprintf(stderr, "%s: No namelist\n", nlistf);
 592:         exit(1);
 593:     }
 594:     if (kflg) {
 595:         /* We must do the sys map first because klseek uses it */
 596:         long    addr;
 597: 
 598:         Syssize = nl[X_SYSSIZE].n_value;
 599:         Sysmap = (struct pte *)
 600:             calloc((unsigned) Syssize, sizeof (struct pte));
 601:         if (Sysmap == NULL) {
 602:             fprintf(stderr, "Out of space for Sysmap\n");
 603:             exit(1);
 604:         }
 605:         addr = (long) nl[X_SYSMAP].n_value;
 606:         addr &= ~0x80000000;
 607:         (void) lseek(kmem, addr, 0);
 608:         read(kmem, (char *) Sysmap, Syssize * sizeof (struct pte));
 609:     }
 610:     if (faildb)
 611:         getvchans();
 612:     usrpt = (struct pte *)nl[X_USRPT].n_value;
 613:     Usrptmap = (struct pte *)nl[X_USRPTMAP].n_value;
 614:     klseek(kmem, (long)nl[X_NSWAP].n_value, 0);
 615:     if (read(kmem, (char *)&nswap, sizeof (nswap)) != sizeof (nswap)) {
 616:         cantread("nswap", kmemf);
 617:         exit(1);
 618:     }
 619:     klseek(kmem, (long)nl[X_MAXSLP].n_value, 0);
 620:     if (read(kmem, (char *)&maxslp, sizeof (maxslp)) != sizeof (maxslp)) {
 621:         cantread("maxslp", kmemf);
 622:         exit(1);
 623:     }
 624:     klseek(kmem, (long)nl[X_CCPU].n_value, 0);
 625:     if (read(kmem, (char *)&ccpu, sizeof (ccpu)) != sizeof (ccpu)) {
 626:         cantread("ccpu", kmemf);
 627:         exit(1);
 628:     }
 629:     klseek(kmem, (long)nl[X_ECMX].n_value, 0);
 630:     if (read(kmem, (char *)&ecmx, sizeof (ecmx)) != sizeof (ecmx)) {
 631:         cantread("ecmx", kmemf);
 632:         exit(1);
 633:     }
 634:     if (uflg || vflg) {
 635:         ntext = getw(nl[X_NTEXT].n_value);
 636:         text = (struct text *)
 637:             calloc((unsigned) ntext, sizeof (struct text));
 638:         if (text == 0) {
 639:             fprintf(stderr, "no room for text table\n");
 640:             exit(1);
 641:         }
 642:         atext = (struct text *)getw(nl[X_TEXT].n_value);
 643:         klseek(kmem, (long)atext, 0);
 644:         if (read(kmem, (char *)text, ntext * sizeof (struct text))
 645:             != ntext * sizeof (struct text)) {
 646:             cantread("text table", kmemf);
 647:             exit(1);
 648:         }
 649:     }
 650:     dmmin = getw(nl[X_DMMIN].n_value);
 651:     dmmax = getw(nl[X_DMMAX].n_value);
 652: }
 653: 
 654: /*
 655:  * get the valloc'ed kernel variables for symbolic wait channels
 656:  */
 657: getvchans()
 658: {
 659:     int i, tmp;
 660: 
 661:     if (nflg)
 662:         return;
 663: 
 664: #define addv(i)     addchan(&nl[i].n_un.n_name[1], getw(nl[i].n_value))
 665:     addv(X_INODE);
 666:     addv(X_FILE);
 667:     addv(X_PROC);
 668:     addv(X_TEXT);
 669:     addv(X_CFREE);
 670:     addv(X_CALLOUT);
 671:     addv(X_SWAPMAP);
 672:     addv(X_ARGMAP);
 673:     addv(X_KERNELMAP);
 674:     addv(X_MBMAP);
 675:     addv(X_NCH);
 676:     if (nl[X_QUOTA].n_value != 0) { /* these are #ifdef QUOTA */
 677:         addv(X_QUOTA);
 678:         addv(X_DQUOT);
 679:     }
 680:     addv(X_SWBUF);
 681:     addv(X_BUF);
 682:     addv(X_CMAP);
 683:     addv(X_BUFFERS);
 684:     qsort(wchanhd, nchans, sizeof (struct wchan), wchancomp);
 685:     for (i = 0; i < NWCINDEX; i++) {
 686:         tmp = i * nchans;
 687:         wchan_index[i] = wchanhd[tmp / NWCINDEX].wc_caddr;
 688:     }
 689: #undef addv
 690: }
 691: printhdr()
 692: {
 693:     char *hdr;
 694: 
 695:     if (sflg+lflg+vflg+uflg > 1) {
 696:         fprintf(stderr, "ps: specify only one of s,l,v and u\n");
 697:         exit(1);
 698:     }
 699:     if (lflg) {
 700:         if (nflg)
 701:             wcwidth = 6;
 702:         else if (twidth > WTSIZ)
 703:             wcwidth = -WNAMESIZ;
 704:         else
 705:             wcwidth = -WSNAMESIZ;
 706:         if ((hdr = malloc(strlen(lhdr) + WNAMESIZ)) == NULL) {
 707:             fprintf(stderr, "ps: out of memory\n");
 708:             exit(1);
 709:         }
 710:         sprintf(hdr, lhdr, wcwidth, "WCHAN");
 711:     } else if (vflg)
 712:         hdr = vhdr;
 713:     else if (uflg) {
 714:         /* add enough on so that it can hold the sprintf below */
 715:         if ((hdr = malloc(strlen(uhdr) + 10)) == NULL) {
 716:             fprintf(stderr, "ps: out of memory\n");
 717:             exit(1);
 718:         }
 719:         sprintf(hdr, uhdr, nflg ? " UID" : "USER    ");
 720:     } else
 721:         hdr = shdr;
 722:     if (lflg+vflg+uflg+sflg == 0)
 723:         hdr += strlen("SSIZ ");
 724:     cmdstart = strlen(hdr);
 725:     printf("%s COMMAND\n", hdr);
 726:     (void) fflush(stdout);
 727: }
 728: 
 729: cantread(what, fromwhat)
 730:     char *what, *fromwhat;
 731: {
 732: 
 733:     fprintf(stderr, "ps: error reading %s from %s\n", what, fromwhat);
 734: }
 735: 
 736: struct  direct *dbuf;
 737: int dialbase;
 738: 
 739: getdev()
 740: {
 741:     register DIR *df;
 742:     struct ttys *t;
 743:     struct lttys *lt;
 744: 
 745:     if (chdir("/dev") < 0) {
 746:         perror("/dev");
 747:         exit(1);
 748:     }
 749:     dialbase = -1;
 750:     if ((df = opendir(".")) == NULL) {
 751:         fprintf(stderr, "Can't open . in /dev\n");
 752:         exit(1);
 753:     }
 754:     while ((dbuf = readdir(df)) != NULL)
 755:         maybetty();
 756:     closedir(df);
 757:     allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
 758:     if (allttys == NULL) {
 759:         fprintf(stderr, "ps: Can't malloc space for tty table\n");
 760:         exit(1);
 761:     }
 762:     for (lt = lallttys, t = allttys; lt ; lt = lt->next, t++)
 763:         *t = lt->ttys;
 764: }
 765: 
 766: /*
 767:  * Attempt to avoid stats by guessing minor device
 768:  * numbers from tty names.  Console is known,
 769:  * know that r(hp|up|mt) are unlikely as are different mem's,
 770:  * floppy, null, tty, etc.
 771:  */
 772: maybetty()
 773: {
 774:     register char *cp = dbuf->d_name;
 775:     static struct lttys *dp;
 776:     struct lttys *olddp;
 777:     int x;
 778:     struct stat stb;
 779: 
 780:     switch (cp[0]) {
 781: 
 782:     case 'c':
 783:         if (!strcmp(cp, "console")) {
 784:             x = 0;
 785:             goto donecand;
 786:         }
 787:         /* cu[la]? are possible!?! don't rule them out */
 788:         break;
 789: 
 790:     case 'd':
 791:         if (!strcmp(cp, "drum"))
 792:             return;
 793:         break;
 794: 
 795:     case 'f':
 796:         if (!strcmp(cp, "floppy"))
 797:             return;
 798:         break;
 799: 
 800:     case 'k':
 801:         cp++;
 802:         if (*cp == 'U')
 803:             cp++;
 804:         goto trymem;
 805: 
 806:     case 'r':
 807:         cp++;
 808: #define is(a,b) cp[0] == 'a' && cp[1] == 'b'
 809:         if (is(h,p) || is(r,a) || is(u,p) || is(h,k)
 810:             || is(r,b) || is(m,t)) {
 811:             cp += 2;
 812:             if (isdigit(*cp) && cp[2] == 0)
 813:                 return;
 814:         }
 815:         break;
 816: 
 817:     case 'm':
 818: trymem:
 819:         if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
 820:             return;
 821:         if (cp[0] == 'm' && cp[1] == 't')
 822:             return;
 823:         break;
 824: 
 825:     case 'n':
 826:         if (!strcmp(cp, "null"))
 827:             return;
 828:         if (!strncmp(cp, "nrmt", 4))
 829:             return;
 830:         break;
 831: 
 832:     case 'p':
 833:         if (cp[1] && cp[1] == 't' && cp[2] == 'y')
 834:             return;
 835:         break;
 836: 
 837:     case 'v':
 838:         if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
 839:             cp[3] == 0)
 840:             return;
 841:         break;
 842:     }
 843:     cp = dbuf->d_name + dbuf->d_namlen - 1;
 844:     x = 0;
 845:     if (cp[-1] == 'd') {
 846:         if (dialbase == -1) {
 847:             if (stat("ttyd0", &stb) == 0)
 848:                 dialbase = stb.st_rdev & 017;
 849:             else
 850:                 dialbase = -2;
 851:         }
 852:         if (dialbase == -2)
 853:             x = 0;
 854:         else
 855:             x = 11;
 856:     }
 857:     if (cp > dbuf->d_name && isdigit(cp[-1]) && isdigit(*cp))
 858:         x += 10 * (cp[-1] - ' ') + cp[0] - '0';
 859:     else if (*cp >= 'a' && *cp <= 'f')
 860:         x += 10 + *cp - 'a';
 861:     else if (isdigit(*cp))
 862:         x += *cp - '0';
 863:     else
 864:         x = -1;
 865: donecand:
 866:     olddp = dp;
 867:     dp = (struct lttys *)malloc(sizeof(struct lttys));
 868:     if (dp == NULL) {
 869:         fprintf(stderr, "ps: Can't malloc space for tty table\n");
 870:         exit(1);
 871:     }
 872:     if (lallttys == NULL)
 873:         lallttys = dp;
 874:     nttys++;
 875:     if (olddp)
 876:         olddp->next = dp;
 877:     dp->next = NULL;
 878:     (void) strcpy(dp->ttys.name, dbuf->d_name);
 879:     if (Uflg) {
 880:         if (stat(dp->ttys.name, &stb) == 0 &&
 881:            (stb.st_mode&S_IFMT)==S_IFCHR)
 882:             dp->ttys.ttyd = x = stb.st_rdev;
 883:         else {
 884:             nttys--;
 885:             if (lallttys == dp)
 886:                 lallttys = NULL;
 887:             free(dp);
 888:             dp = olddp;
 889:             if (dp)
 890:                 dp->next = NULL;
 891:             return;
 892:         }
 893:     } else
 894:         dp->ttys.ttyd = -1;
 895:     if (x == -1)
 896:         return;
 897:     x &= 017;
 898:     dp->ttys.cand = cand[x];
 899:     cand[x] = nttys-1;
 900: }
 901: 
 902: char *
 903: gettty()
 904: {
 905:     register char *p;
 906:     register struct ttys *dp;
 907:     struct stat stb;
 908:     int x;
 909: 
 910:     if (u.u_ttyp == 0)
 911:         return("?");
 912:     x = u.u_ttyd & 017;
 913:     for (dp = &allttys[cand[x]]; dp != &allttys[-1];
 914:          dp = &allttys[dp->cand]) {
 915:         if (dp->ttyd == -1) {
 916:             if (stat(dp->name, &stb) == 0 &&
 917:                (stb.st_mode&S_IFMT)==S_IFCHR)
 918:                 dp->ttyd = stb.st_rdev;
 919:             else
 920:                 dp->ttyd = -2;
 921:         }
 922:         if (dp->ttyd == u.u_ttyd)
 923:             goto found;
 924:     }
 925:     /* ick */
 926:     for (dp = allttys; dp < &allttys[nttys]; dp++) {
 927:         if (dp->ttyd == -1) {
 928:             if (stat(dp->name, &stb) == 0 &&
 929:                (stb.st_mode&S_IFMT)==S_IFCHR)
 930:                 dp->ttyd = stb.st_rdev;
 931:             else
 932:                 dp->ttyd = -2;
 933:         }
 934:         if (dp->ttyd == u.u_ttyd)
 935:             goto found;
 936:     }
 937:     return ("?");
 938: found:
 939:     p = dp->name;
 940:     if (p[0]=='t' && p[1]=='t' && p[2]=='y')
 941:         p += 3;
 942:     return (p);
 943: }
 944: 
 945: save()
 946: {
 947:     register struct savcom *sp;
 948:     register struct asav *ap;
 949:     register char *cp;
 950:     register struct text *xp;
 951:     char *ttyp, *cmdp;
 952: 
 953:     if (mproc->p_stat != SZOMB && getu() == 0)
 954:         return;
 955:     ttyp = gettty();
 956:     if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
 957:         return;
 958:     sp = &savcom[npr];
 959:     cmdp = getcmd();
 960:     if (cmdp == 0)
 961:         return;
 962:     sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
 963:     sp->ap->a_cmdp = cmdp;
 964: #define e(a,b) ap->a = mproc->b
 965:     e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
 966:     e(a_uid, p_uid); e(a_pid, p_pid); e(a_pri, p_pri);
 967:     e(a_slptime, p_slptime); e(a_time, p_time);
 968:     ap->a_tty[0] = ttyp[0];
 969:     ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
 970:     if (ap->a_stat == SZOMB) {
 971:         ap->a_cpu = 0;
 972:     } else {
 973:         ap->a_size = mproc->p_dsize + mproc->p_ssize;
 974:         e(a_rss, p_rssize);
 975:         ap->a_ttyd = u.u_ttyd;
 976:         ap->a_cpu = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
 977:         if (sumcpu)
 978:             ap->a_cpu += u.u_cru.ru_utime.tv_sec + u.u_cru.ru_stime.tv_sec;
 979:         if (mproc->p_textp && text) {
 980:             xp = &text[mproc->p_textp - atext];
 981:             ap->a_tsiz = xp->x_size;
 982:             ap->a_txtrss = xp->x_rssize;
 983:             ap->a_xccount = xp->x_ccount;
 984:         }
 985:     }
 986: #undef e
 987:     ap->a_maxrss = mproc->p_maxrss;
 988:     if (lflg) {
 989:         register struct lsav *lp;
 990: 
 991:         sp->s_un.lp = lp = (struct lsav *)
 992:             calloc(1, sizeof (struct lsav));
 993: #define e(a,b) lp->a = mproc->b
 994:         e(l_ppid, p_ppid); e(l_cpu, p_cpu);
 995:         if (ap->a_stat != SZOMB)
 996:             e(l_wchan, p_wchan);
 997: #undef e
 998:         lp->l_addr = pcbpf;
 999:     } else if (vflg) {
1000:         register struct vsav *vp;
1001: 
1002:         sp->s_un.vp = vp = (struct vsav *)
1003:             calloc(1, sizeof (struct vsav));
1004: #define e(a,b) vp->a = mproc->b
1005:         if (ap->a_stat != SZOMB) {
1006:             e(v_swrss, p_swrss);
1007:             vp->v_majflt = u.u_ru.ru_majflt;
1008:             if (mproc->p_textp)
1009:                 vp->v_txtswrss = xp->x_swrss;
1010:         }
1011:         vp->v_pctcpu = pcpu();
1012: #undef e
1013:     } else if (uflg)
1014:         sp->s_un.u_pctcpu = pcpu();
1015:     else if (sflg) {
1016:         if (ap->a_stat != SZOMB) {
1017:             for (cp = (char *)u.u_stack;
1018:                 cp < &user.upages[UPAGES][0]; )
1019:                 if (*cp++)
1020:                     break;
1021:             sp->s_un.s_ssiz = (&user.upages[UPAGES][0] - cp);
1022:         }
1023:     }
1024: 
1025:     npr++;
1026: }
1027: 
1028: double
1029: pmem(ap)
1030:     register struct asav *ap;
1031: {
1032:     double fracmem;
1033:     int szptudot;
1034: 
1035:     if ((ap->a_flag&SLOAD) == 0)
1036:         fracmem = 0.0;
1037:     else {
1038:         szptudot = UPAGES + clrnd(ctopt(ap->a_size+ap->a_tsiz));
1039:         fracmem = ((float)ap->a_rss+szptudot)/CLSIZE/ecmx;
1040:         if (ap->a_xccount)
1041:             fracmem += ((float)ap->a_txtrss)/CLSIZE/
1042:                 ap->a_xccount/ecmx;
1043:     }
1044:     return (100.0 * fracmem);
1045: }
1046: 
1047: double
1048: pcpu()
1049: {
1050:     time_t time;
1051: 
1052:     time = mproc->p_time;
1053:     if (time == 0 || (mproc->p_flag&SLOAD) == 0)
1054:         return (0.0);
1055:     if (rawcpu)
1056:         return (100.0 * mproc->p_pctcpu);
1057:     return (100.0 * mproc->p_pctcpu / (1.0 - exp(time * log(ccpu))));
1058: }
1059: 
1060: getu()
1061: {
1062:     struct pte *pteaddr, apte;
1063:     struct pte arguutl[UPAGES+CLSIZE];
1064:     register int i;
1065:     int ncl, size;
1066: 
1067:     size = sflg ? ctob(UPAGES) : sizeof (struct user);
1068:     if ((mproc->p_flag & SLOAD) == 0) {
1069:         if (swap < 0)
1070:             return (0);
1071:         (void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
1072:         if (read(swap, (char *)&user.user, size) != size) {
1073:             fprintf(stderr, "ps: cant read u for pid %d from %s\n",
1074:                 mproc->p_pid, swapf);
1075:             return (0);
1076:         }
1077:         pcbpf = 0;
1078:         argaddr = 0;
1079:         return (1);
1080:     }
1081:     pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
1082:     klseek(kmem, (long)pteaddr, 0);
1083:     if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
1084:         printf("ps: cant read indir pte to get u for pid %d from %s\n",
1085:             mproc->p_pid, kmemf);
1086:         return (0);
1087:     }
1088:     lseek(mem,
1089:         (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
1090:         0);
1091:     if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
1092:         printf("ps: cant read page table for u of pid %d from %s\n",
1093:             mproc->p_pid, memf);
1094:         return (0);
1095:     }
1096:     if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
1097:         argaddr = ctob(arguutl[0].pg_pfnum);
1098:     else
1099:         argaddr = 0;
1100:     pcbpf = arguutl[CLSIZE].pg_pfnum;
1101:     ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
1102:     while (--ncl >= 0) {
1103:         i = ncl * CLSIZE;
1104:         lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
1105:         if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
1106:             printf("ps: cant read page %d of u of pid %d from %s\n",
1107:                 arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
1108:             return(0);
1109:         }
1110:     }
1111:     return (1);
1112: }
1113: 
1114: char *
1115: getcmd()
1116: {
1117:     char cmdbuf[CLSIZE*NBPG];
1118:     union {
1119:         char    argc[CLSIZE*NBPG];
1120:         int argi[CLSIZE*NBPG/sizeof (int)];
1121:     } argspac;
1122:     register char *cp;
1123:     register int *ip;
1124:     char c;
1125:     int nbad;
1126:     struct dblock db;
1127:     char *file;
1128: 
1129:     if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
1130:         return ("");
1131:     if (cflg) {
1132:         (void) strncpy(cmdbuf, u.u_comm, sizeof (u.u_comm));
1133:         return (savestr(cmdbuf));
1134:     }
1135:     if ((mproc->p_flag & SLOAD) == 0 || argaddr == 0) {
1136:         if (swap < 0)
1137:             goto retucomm;
1138:         vstodb(0, CLSIZE, &u.u_smap, &db, 1);
1139:         (void) lseek(swap, (long)dtob(db.db_base), 0);
1140:         if (read(swap, (char *)&argspac, sizeof(argspac))
1141:             != sizeof(argspac))
1142:             goto bad;
1143:         file = swapf;
1144:     } else {
1145:         lseek(mem, (long)argaddr, 0);
1146:         if (read(mem, (char *)&argspac, sizeof (argspac))
1147:             != sizeof (argspac))
1148:             goto bad;
1149:         file = memf;
1150:     }
1151:     ip = &argspac.argi[CLSIZE*NBPG/sizeof (int)];
1152:     ip -= 2;        /* last arg word and .long 0 */
1153:     while (*--ip)
1154:         if (ip == argspac.argi)
1155:             goto retucomm;
1156:     *(char *)ip = ' ';
1157:     ip++;
1158:     nbad = 0;
1159:     for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG]; cp++) {
1160:         c = *cp & 0177;
1161:         if (c == 0)
1162:             *cp = ' ';
1163:         else if (c < ' ' || c > 0176) {
1164:             if (++nbad >= 5*(eflg+1)) {
1165:                 *cp++ = ' ';
1166:                 break;
1167:             }
1168:             *cp = '?';
1169:         } else if (eflg == 0 && c == '=') {
1170:             while (*--cp != ' ')
1171:                 if (cp <= (char *)ip)
1172:                     break;
1173:             break;
1174:         }
1175:     }
1176:     *cp = 0;
1177:     while (*--cp == ' ')
1178:         *cp = 0;
1179:     cp = (char *)ip;
1180:     (void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG] - cp);
1181:     if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
1182:         (void) strcat(cmdbuf, " (");
1183:         (void) strncat(cmdbuf, u.u_comm, sizeof(u.u_comm));
1184:         (void) strcat(cmdbuf, ")");
1185:     }
1186:     return (savestr(cmdbuf));
1187: 
1188: bad:
1189:     fprintf(stderr, "ps: error locating command name for pid %d from %s\n",
1190:         mproc->p_pid, file);
1191: retucomm:
1192:     (void) strcpy(cmdbuf, " (");
1193:     (void) strncat(cmdbuf, u.u_comm, sizeof (u.u_comm));
1194:     (void) strcat(cmdbuf, ")");
1195:     return (savestr(cmdbuf));
1196: }
1197: 
1198: char    *lhdr =
1199: "      F UID   PID  PPID CP PRI NI ADDR  SZ  RSS %*s STAT TT  TIME";
1200: lpr(sp)
1201:     struct savcom *sp;
1202: {
1203:     register struct asav *ap = sp->ap;
1204:     register struct lsav *lp = sp->s_un.lp;
1205: 
1206:     printf("%7x%4d%6u%6u%3d%4d%3d%5x%4d%5d",
1207:         ap->a_flag, ap->a_uid,
1208:         ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
1209:         ap->a_nice-NZERO, lp->l_addr, pgtok(ap->a_size), pgtok(ap->a_rss));
1210:     if (lp->l_wchan == 0)
1211:         printf(" %*s", wcwidth, "");
1212:     else if (nflg)
1213:         printf(" %*x", wcwidth, (int)lp->l_wchan&0xffffff);
1214:     else
1215:         printf(" %*.*s", wcwidth, abs(wcwidth), getchan(lp->l_wchan));
1216:     printf(" %4.4s ", state(ap));
1217:     ptty(ap->a_tty);
1218:     ptime(ap);
1219: }
1220: 
1221: ptty(tp)
1222:     char *tp;
1223: {
1224: 
1225:     printf("%-2.2s", tp);
1226: }
1227: 
1228: ptime(ap)
1229:     struct asav *ap;
1230: {
1231: 
1232:     printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
1233: }
1234: 
1235: char    *uhdr =
1236: "%s   PID %%CPU %%MEM   SZ  RSS TT STAT  TIME";
1237: upr(sp)
1238:     struct savcom *sp;
1239: {
1240:     register struct asav *ap = sp->ap;
1241:     int vmsize, rmsize;
1242: 
1243:     vmsize = pgtok((ap->a_size + ap->a_tsiz));
1244:     rmsize = pgtok(ap->a_rss);
1245:     if (ap->a_xccount)
1246:         rmsize += pgtok(ap->a_txtrss/ap->a_xccount);
1247:     if (nflg)
1248:         printf("%4d ", ap->a_uid);
1249:     else
1250:         printf("%-8.8s ", getname(ap->a_uid));
1251:     printf("%5d%5.1f%5.1f%5d%5d",
1252:         ap->a_pid, sp->s_un.u_pctcpu, pmem(ap), vmsize, rmsize);
1253:     putchar(' ');
1254:     ptty(ap->a_tty);
1255:     printf(" %4.4s", state(ap));
1256:     ptime(ap);
1257: }
1258: 
1259: char *vhdr =
1260: " SIZE  PID TT STAT  TIME SL RE PAGEIN SIZE  RSS   LIM TSIZ TRS %CPU %MEM"+5;
1261: vpr(sp)
1262:     struct savcom *sp;
1263: {
1264:     register struct vsav *vp = sp->s_un.vp;
1265:     register struct asav *ap = sp->ap;
1266: 
1267:     printf("%5u ", ap->a_pid);
1268:     ptty(ap->a_tty);
1269:     printf(" %4.4s", state(ap));
1270:     ptime(ap);
1271:     printf("%3d%3d%7d%5d%5d",
1272:        ap->a_slptime > 99 ? 99 : ap-> a_slptime,
1273:        ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
1274:        pgtok(ap->a_size), pgtok(ap->a_rss));
1275:     if (ap->a_maxrss == (RLIM_INFINITY/NBPG))
1276:         printf("    xx");
1277:     else
1278:         printf("%6d", pgtok(ap->a_maxrss));
1279:     printf("%5d%4d%5.1f%5.1f",
1280:        pgtok(ap->a_tsiz), pgtok(ap->a_txtrss), vp->v_pctcpu, pmem(ap));
1281: }
1282: 
1283: char    *shdr =
1284: "SSIZ   PID TT STAT  TIME";
1285: spr(sp)
1286:     struct savcom *sp;
1287: {
1288:     register struct asav *ap = sp->ap;
1289: 
1290:     if (sflg)
1291:         printf("%4d ", sp->s_un.s_ssiz);
1292:     printf("%5u", ap->a_pid);
1293:     putchar(' ');
1294:     ptty(ap->a_tty);
1295:     printf(" %4.4s", state(ap));
1296:     ptime(ap);
1297: }
1298: 
1299: char *
1300: state(ap)
1301:     register struct asav *ap;
1302: {
1303:     char stat, load, nice, anom;
1304:     static char res[5];
1305: 
1306:     switch (ap->a_stat) {
1307: 
1308:     case SSTOP:
1309:         stat = 'T';
1310:         break;
1311: 
1312:     case SSLEEP:
1313:         if (ap->a_pri >= PZERO)
1314:             if (ap->a_slptime >= MAXSLP)
1315:                 stat = 'I';
1316:             else
1317:                 stat = 'S';
1318:         else if (ap->a_flag & SPAGE)
1319:             stat = 'P';
1320:         else
1321:             stat = 'D';
1322:         break;
1323: 
1324:     case SWAIT:
1325:     case SRUN:
1326:     case SIDL:
1327:         stat = 'R';
1328:         break;
1329: 
1330:     case SZOMB:
1331:         stat = 'Z';
1332:         break;
1333: 
1334:     default:
1335:         stat = '?';
1336:     }
1337:     load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
1338:     if (ap->a_nice < NZERO)
1339:         nice = '<';
1340:     else if (ap->a_nice > NZERO)
1341:         nice = 'N';
1342:     else
1343:         nice = ' ';
1344:     anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
1345:     res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
1346:     return (res);
1347: }
1348: 
1349: /*
1350:  * Given a base/size pair in virtual swap area,
1351:  * return a physical base/size pair which is the
1352:  * (largest) initial, physically contiguous block.
1353:  */
1354: vstodb(vsbase, vssize, dmp, dbp, rev)
1355:     register int vsbase;
1356:     int vssize;
1357:     struct dmap *dmp;
1358:     register struct dblock *dbp;
1359: {
1360:     register int blk = dmmin;
1361:     register swblk_t *ip = dmp->dm_map;
1362: 
1363:     vsbase = ctod(vsbase);
1364:     vssize = ctod(vssize);
1365:     if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
1366:         panic("vstodb");
1367:     while (vsbase >= blk) {
1368:         vsbase -= blk;
1369:         if (blk < dmmax)
1370:             blk *= 2;
1371:         ip++;
1372:     }
1373:     if (*ip <= 0 || *ip + blk > nswap)
1374:         panic("vstodb *ip");
1375:     dbp->db_size = min(vssize, blk - vsbase);
1376:     dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
1377: }
1378: 
1379: /*ARGSUSED*/
1380: panic(cp)
1381:     char *cp;
1382: {
1383: 
1384: #ifdef DEBUG
1385:     printf("%s\n", cp);
1386: #endif
1387: }
1388: 
1389: min(a, b)
1390: {
1391: 
1392:     return (a < b ? a : b);
1393: }
1394: 
1395: pscomp(s1, s2)
1396:     struct savcom *s1, *s2;
1397: {
1398:     register int i;
1399: 
1400:     if (uflg)
1401:         return (s2->s_un.u_pctcpu > s1->s_un.u_pctcpu ? 1 : -1);
1402:     if (vflg)
1403:         return (vsize(s2) - vsize(s1));
1404:     i = s1->ap->a_ttyd - s2->ap->a_ttyd;
1405:     if (i == 0)
1406:         i = s1->ap->a_pid - s2->ap->a_pid;
1407:     return (i);
1408: }
1409: 
1410: vsize(sp)
1411:     struct savcom *sp;
1412: {
1413:     register struct asav *ap = sp->ap;
1414:     register struct vsav *vp = sp->s_un.vp;
1415: 
1416:     if (ap->a_flag & SLOAD)
1417:         return (ap->a_rss +
1418:             ap->a_txtrss / (ap->a_xccount ? ap->a_xccount : 1));
1419:     return (vp->v_swrss + (ap->a_xccount ? 0 : vp->v_txtswrss));
1420: }
1421: 
1422: #include <utmp.h>
1423: 
1424: struct  utmp utmp;
1425: #define NMAX    (sizeof (utmp.ut_name))
1426: #define SCPYN(a, b) strncpy(a, b, NMAX)
1427: 
1428: #define NUID    64
1429: 
1430: struct ncache {
1431:     int uid;
1432:     char    name[NMAX+1];
1433: } nc[NUID];
1434: 
1435: /*
1436:  * This function assumes that the password file is hashed
1437:  * (or some such) to allow fast access based on a uid key.
1438:  */
1439: char *
1440: getname(uid)
1441: {
1442:     register struct passwd *pw;
1443:     struct passwd *getpwent();
1444:     register int cp;
1445:     extern int _pw_stayopen;
1446: 
1447:     _pw_stayopen = 1;
1448: 
1449: #if (((NUID) & ((NUID) - 1)) != 0)
1450:     cp = uid % (NUID);
1451: #else
1452:     cp = uid & ((NUID) - 1);
1453: #endif
1454:     if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
1455:         return (nc[cp].name);
1456:     pw = getpwuid(uid);
1457:     if (!pw)
1458:         return (0);
1459:     nc[cp].uid = uid;
1460:     SCPYN(nc[cp].name, pw->pw_name);
1461:     return (nc[cp].name);
1462: }
1463: 
1464: char *
1465: savestr(cp)
1466:     char *cp;
1467: {
1468:     register unsigned len;
1469:     register char *dp;
1470: 
1471:     len = strlen(cp);
1472:     dp = (char *)calloc(len+1, sizeof (char));
1473:     (void) strcpy(dp, cp);
1474:     return (dp);
1475: }
1476: 
1477: /*
1478:  * This routine was stolen from adb to simulate memory management
1479:  * on the VAX.
1480:  */
1481: off_t
1482: vtophys(loc)
1483: long    loc;
1484: {
1485:     register    p;
1486:     off_t   newloc;
1487: 
1488:     newloc = loc & ~0xc0000000;
1489:     p = btop(newloc);
1490:     if ((loc & 0xc0000000) == 0) {
1491:         fprintf(stderr, "Vtophys: translating non-kernel address\n");
1492:         return((off_t) -1);
1493:     }
1494:     if (p >= Syssize) {
1495:         fprintf(stderr, "Vtophys: page out of bound (%d>=%d)\n",
1496:             p, Syssize);
1497:         return((off_t) -1);
1498:     }
1499:     if (Sysmap[p].pg_v == 0
1500:     && (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
1501:         fprintf(stderr, "Vtophys: page not valid\n");
1502:         return((off_t) -1);
1503:     }
1504:     loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
1505:     return(loc);
1506: }
1507: 
1508: /*
1509:  * since we can't init unions, the cleanest way to use a.out.h instead
1510:  * of nlist.h (required since nlist() uses some defines) is to do a
1511:  * runtime copy into the nl array -- sigh
1512:  */
1513: init_nlist()
1514: {
1515:     register struct nlist *np;
1516:     register char **namep;
1517: 
1518:     nllen = sizeof nl_names / sizeof (char *);
1519:     np = nl = (struct nlist *) malloc(nllen * sizeof (struct nlist));
1520:     if (np == NULL) {
1521:         fprintf(stderr, "ps: out of memory allocating namelist\n");
1522:         exit(1);
1523:     }
1524:     namep = &nl_names[0];
1525:     while (nllen > 0) {
1526:         np->n_un.n_name = *namep;
1527:         if (**namep == '\0')
1528:             break;
1529:         namep++;
1530:         np++;
1531:     }
1532: }
1533: 
1534: /*
1535:  * nlist - retreive attributes from name list (string table version)
1536:  * 	modified to add wait channels - Charles R. LaBrec 8/85
1537:  */
1538: nlist(name, list)
1539:     char *name;
1540:     struct nlist *list;
1541: {
1542:     register struct nlist *p, *q;
1543:     register char *s1, *s2;
1544:     register n, m;
1545:     int maxlen, nreq;
1546:     FILE *f;
1547:     FILE *sf;
1548:     off_t sa;       /* symbol address */
1549:     off_t ss;       /* start of strings */
1550:     int type;
1551:     struct exec buf;
1552:     struct nlist space[BUFSIZ/sizeof (struct nlist)];
1553:     char nambuf[BUFSIZ];
1554: 
1555:     maxlen = 0;
1556:     for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0]; q++, nreq++) {
1557:         q->n_type = 0;
1558:         q->n_value = 0;
1559:         q->n_desc = 0;
1560:         q->n_other = 0;
1561:         n = strlen(q->n_un.n_name);
1562:         if (n > maxlen)
1563:             maxlen = n;
1564:     }
1565:     f = fopen(name, "r");
1566:     if (f == NULL)
1567:         return (-1);
1568:     fread((char *)&buf, sizeof buf, 1, f);
1569:     if (N_BADMAG(buf)) {
1570:         fclose(f);
1571:         return (-1);
1572:     }
1573:     sf = fopen(name, "r");
1574:     if (sf == NULL) {
1575:         /* ??? */
1576:         fclose(f);
1577:         return(-1);
1578:     }
1579:     sa = N_SYMOFF(buf);
1580:     ss = sa + buf.a_syms;
1581:     n = buf.a_syms;
1582:     fseek(f, sa, 0);
1583:     while (n) {
1584:         m = sizeof (space);
1585:         if (n < m)
1586:             m = n;
1587:         if (fread((char *)space, m, 1, f) != 1)
1588:             break;
1589:         n -= m;
1590:         for (q = space; (m -= sizeof(struct nlist)) >= 0; q++) {
1591:             if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
1592:                 continue;
1593:             /*
1594: 			 * since we know what type of symbols we will get,
1595: 			 * we can make a quick check here -- crl
1596: 			 */
1597:             type = q->n_type & (N_TYPE | N_EXT);
1598:             if ((q->n_type & N_TYPE) != N_ABS
1599:                 && type != (N_EXT | N_DATA)
1600:                 && type != (N_EXT | N_BSS))
1601:                 continue;
1602:             fseek(sf, ss+q->n_un.n_strx, 0);
1603:             fread(nambuf, maxlen+1, 1, sf);
1604:             /* if using wchans, add it to the list of channels */
1605:             if (!nflg)
1606:                 addchan(&nambuf[1], (caddr_t) q->n_value);
1607:             for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
1608:                 s1 = p->n_un.n_name;
1609:                 s2 = nambuf;
1610:                 if (strcmp(p->n_un.n_name, nambuf) == 0) {
1611:                     p->n_value = q->n_value;
1612:                     p->n_type = q->n_type;
1613:                     p->n_desc = q->n_desc;
1614:                     p->n_other = q->n_other;
1615:                     --nreq;
1616:                     break;
1617:                 }
1618:             }
1619:         }
1620:     }
1621: alldone:
1622:     fclose(f);
1623:     fclose(sf);
1624:     return (nreq);
1625: }
1626: 
1627: /*
1628:  * add the given channel to the channel list
1629:  */
1630: addchan(name, caddr)
1631: char *name;
1632: caddr_t caddr;
1633: {
1634:     static int left = 0;
1635:     register struct wchan *wp;
1636:     register char **p;
1637: 
1638:     for (p = wchan_stop_list; *p; p++) {
1639:         if (**p != *name)   /* quick check first */
1640:             continue;
1641:         if (strncmp(name, *p, WNAMESIZ) == 0)
1642:             return;     /* if found, don't add */
1643:     }
1644:     if (left == 0) {
1645:         if (wchanhd) {
1646:             left = 100;
1647:             wchanhd = (struct wchan *) realloc(wchanhd,
1648:                 (nchans + left) * sizeof (struct wchan));
1649:         } else {
1650:             left = 600;
1651:             wchanhd = (struct wchan *) malloc(left
1652:                 * sizeof (struct wchan));
1653:         }
1654:         if (wchanhd == NULL) {
1655:             fprintf(stderr, "ps: out of memory allocating wait channels\n");
1656:             nflg++;
1657:             return;
1658:         }
1659:     }
1660:     left--;
1661:     wp = &wchanhd[nchans++];
1662:     strncpy(wp->wc_name, name, WNAMESIZ);
1663:     wp->wc_name[WNAMESIZ] = '\0';
1664:     wp->wc_caddr = caddr;
1665: }
1666: 
1667: /*
1668:  * returns the symbolic wait channel corresponding to chan
1669:  */
1670: char *
1671: getchan(chan)
1672: register caddr_t chan;
1673: {
1674:     register i, iend;
1675:     register char *prevsym;
1676:     register struct wchan *wp;
1677: 
1678:     prevsym = "???";        /* nothing, to begin with */
1679:     if (chan) {
1680:         for (i = 0; i < NWCINDEX; i++)
1681:             if ((unsigned) chan < (unsigned) wchan_index[i])
1682:                 break;
1683:         iend = i--;
1684:         if (i < 0)      /* can't be found */
1685:             return prevsym;
1686:         iend *= nchans;
1687:         iend /= NWCINDEX;
1688:         i *= nchans;
1689:         i /= NWCINDEX;
1690:         wp = &wchanhd[i];
1691:         for ( ; i < iend; i++, wp++) {
1692:             if ((unsigned) wp->wc_caddr > (unsigned) chan)
1693:                 break;
1694:             prevsym = wp->wc_name;
1695:         }
1696:     }
1697:     return prevsym;
1698: }
1699: 
1700: /*
1701:  * used in sorting the wait channel array
1702:  */
1703: int
1704: wchancomp (w1, w2)
1705: struct wchan *w1, *w2;
1706: {
1707:     register unsigned c1, c2;
1708: 
1709:     c1 = (unsigned) w1->wc_caddr;
1710:     c2 = (unsigned) w2->wc_caddr;
1711:     if (c1 > c2)
1712:         return 1;
1713:     else if (c1 == c2)
1714:         return 0;
1715:     else
1716:         return -1;
1717: }

Defined functions

addchan defined in line 1630; used 2 times
cantread defined in line 729; used 6 times
getchan defined in line 1670; used 2 times
getcmd defined in line 1114; used 2 times
getdev defined in line 739; used 2 times
getkvars defined in line 566; used 1 times
getname defined in line 1439; used 2 times
gettty defined in line 902; used 2 times
getu defined in line 1060; used 1 times
getvchans defined in line 657; used 2 times
getw defined in line 409; used 7 times
init_nlist defined in line 1513; used 2 times
klseek defined in line 420; used 8 times
lpr defined in line 1200; used 1 times
main defined in line 242; never used
maybetty defined in line 772; used 1 times
min defined in line 1389; used 1 times
nlist defined in line 1538; used 2 times
openfiles defined in line 533; used 1 times
panic defined in line 1380; used 2 times
pcpu defined in line 1047; used 3 times
pmem defined in line 1028; used 3 times
printhdr defined in line 691; used 1 times
pscomp defined in line 1395; used 2 times
ptime defined in line 1228; used 4 times
ptty defined in line 1221; used 4 times
readpsdb defined in line 470; used 1 times
save defined in line 945; used 1 times
savestr defined in line 1464; used 4 times
spr defined in line 1285; used 1 times
state defined in line 1299; used 5 times
upr defined in line 1237; used 1 times
vpr defined in line 1261; used 1 times
vsize defined in line 1410; used 2 times
vstodb defined in line 1354; used 1 times
vtophys defined in line 1481; used 2 times
wchancomp defined in line 1703; used 2 times
writepsdb defined in line 437; used 1 times

Defined variables

Sysmap defined in line 180; used 7 times
Syssize defined in line 181; used 5 times
Uflg defined in line 161; used 3 times
Usrptmap defined in line 177; used 2 times
aflg defined in line 160; used 4 times
allttys defined in line 189; used 11 times
argaddr defined in line 238; used 5 times
atext defined in line 174; used 3 times
cand defined in line 190; used 10 times
ccpu defined in line 175; used 4 times
cflg defined in line 160; used 4 times
chkpid defined in line 159; used 3 times
cmdstart defined in line 230; used 3 times
copyright defined in line 8; never used
dbuf defined in line 736; used 6 times
dialbase defined in line 737; used 5 times
dmmax defined in line 179; used 2 times
dmmin defined in line 179; used 2 times
ecmx defined in line 176; used 5 times
eflg defined in line 160; used 3 times
gflg defined in line 160; used 4 times
kflg defined in line 160; used 7 times
kmem defined in line 234; used 21 times
kmemf defined in line 233; used 12 times
lallttys defined in line 195; used 6 times
lflg defined in line 160; used 6 times
lhdr defined in line 1198; used 2 times
maxslp defined in line 173; used 3 times
  • in line 620(3)
mem defined in line 234; used 9 times
memf defined in line 233; used 7 times
mproc defined in line 144; used 37 times
mytty defined in line 166; used 1 times
nc defined in line 1433; used 6 times
nchans defined in line 162; used 14 times
nflg defined in line 160; used 9 times
nl defined in line 97; used 25 times
nl_names defined in line 35; used 2 times
nlistf defined in line 233; used 6 times
nllen defined in line 98; used 10 times
npr defined in line 228; used 5 times
nproc defined in line 178; used 4 times
nswap defined in line 173; used 4 times
ntext defined in line 178; used 4 times
nttys defined in line 183; used 12 times
pcbpf defined in line 237; used 3 times
proc defined in line 143; used 2 times
psdb defined in line 156; used 4 times
rawcpu defined in line 235; used 2 times
savcom defined in line 108; used 6 times
sccsid defined in line 14; never used
sflg defined in line 160; used 6 times
shdr defined in line 1283; used 1 times
sumcpu defined in line 235; used 2 times
swap defined in line 234; used 8 times
swapf defined in line 233; used 5 times
text defined in line 145; used 5 times
thisversion defined in line 435; used 5 times
tptr defined in line 163; used 13 times
twidth defined in line 231; used 8 times
uflg defined in line 161; used 8 times
uhdr defined in line 1235; used 2 times
usrpt defined in line 177; used 1 times
utmp defined in line 1424; used 1 times
vflg defined in line 161; used 9 times
vhdr defined in line 1259; used 1 times
wchan_stop_list defined in line 221; used 1 times
wchanhd defined in line 211; used 13 times
wcwidth defined in line 123; used 8 times
win defined in line 232; used 3 times
xflg defined in line 161; used 7 times

Defined struct's

asav defined in line 110; used 23 times
lsav defined in line 124; used 9 times
lttys defined in line 192; used 14 times
ncache defined in line 1430; never used
savcom defined in line 100; used 18 times
ttys defined in line 185; used 18 times
vsav defined in line 135; used 11 times
wchan defined in line 208; used 26 times

Defined macros

NMAX defined in line 1425; used 2 times
NPROC defined in line 141; used 4 times
NUID defined in line 1428; used 5 times
NWCINDEX defined in line 213; used 8 times
SCPYN defined in line 1426; used 1 times
WNAMESIZ defined in line 204; used 6 times
WSNAMESIZ defined in line 205; used 1 times
WTSIZ defined in line 206; used 1 times
X_ARGMAP defined in line 75; used 1 times
X_BUF defined in line 89; used 1 times
X_BUFFERS defined in line 93; used 1 times
X_CALLOUT defined in line 71; used 1 times
X_CCPU defined in line 49; used 1 times
X_CFREE defined in line 69; used 1 times
X_CMAP defined in line 91; used 1 times
X_DMMAX defined in line 59; used 1 times
X_DMMIN defined in line 57; used 1 times
X_DQUOT defined in line 85; used 1 times
X_ECMX defined in line 51; used 1 times
X_FILE defined in line 67; used 1 times
X_INODE defined in line 65; used 1 times
X_KERNELMAP defined in line 77; used 1 times
X_MAXSLP defined in line 47; used 1 times
X_MBMAP defined in line 79; used 1 times
X_NCH defined in line 81; used 1 times
X_NPROC defined in line 53; used 1 times
X_NSWAP defined in line 45; used 1 times
X_NTEXT defined in line 55; used 1 times
X_PROC defined in line 37; used 2 times
X_QUOTA defined in line 83; used 2 times
X_SWAPMAP defined in line 73; used 1 times
X_SWBUF defined in line 87; used 1 times
X_SYSMAP defined in line 61; used 2 times
X_SYSSIZE defined in line 63; used 1 times
X_TEXT defined in line 43; used 2 times
X_USRPT defined in line 41; used 1 times
X_USRPTMAP defined in line 39; used 1 times
addv defined in line 664; used 18 times
e defined in line 1004; used 16 times
is defined in line 808; used 6 times
pgtok defined in line 240; used 10 times
u defined in line 151; used 19 times
Last modified: 1986-05-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7552
Valid CSS Valid XHTML 1.0 Strict