1: # 2: /* 3: ps - show process status - iiasa version (jek) 4: originally from harvard and/or CULC 5: 6: flags are single letters 7: multiple flags can occur in one argument 8: dashes are optional but are needed to delimit lists of things 9: multiple lists are present(???) 10: flags that imply other arguments read the following arguments 11: until the end of the list or until an argument starts with dash 12: certain flags read exactly one argument 13: initialization (i flag) should be done for: 14: new users, 15: new kernel 16: parameters here must change to indicate: 17: new tty devices, max tty lines, tty letter changes 18: max users 19: new things to wait for 20: this program should be changed if: 21: proc structure makes this obsolete 22: etc 23: recompilation should occur if: 24: kernel structures and or paramters (nproc etc.) change 25: any above changes of course 26: 27: flags are: 28: a - show all processes that have pgrps except shells 29: b - show background (not detached) 30: c - show child times instead of process times 31: d - show detached processes inherited by init 32: e - show the environment with the args 33: f - show foreground jobs, connected to tty 34: g - show processes in given pgrps 35: h - unused 36: i - perform initialization (implies 'n') 37: j,k - unused 38: l - print long format. includes most good stuff 39: m - specify different memory file (file is next arg) 40: n - show no processes 41: o - unused 42: p - show only processes whose id's are in list (following args) 43: q - unused 44: r - repeat indefinitely (number of r's = seconds or r#) 45: s - show stopped processes 46: t - show only processes associated with ttys in list (following) 47: u - show only processes (or ancestors of) for users in list 48: v - be verbose - show the most information 49: w - wide format, show entire argument list (up to 512 chars) 50: x - show unattached processes - no pgrp. a+x gives shells also 51: y - unused 52: z - show zombies 53: A - show ALL information possible 54: B - show busy processes 55: F - go fast, avoid swap space. 56: G - print pgrp 57: U - use different UNIX file (next arg) 58: S - show size 59: T - show tty information 60: W - print wait channels in hex 61: */ 62: 63: #include <signal.h> 64: #include <h/param.h> 65: #include <h/dir.h> 66: #include <h/user.h> 67: #include <h/proc.h> 68: #include <h/pte.h> 69: #include <h/vm.h> 70: #include <h/inode.h> 71: #include <h/file.h> 72: #include <h/buf.h> 73: #include <h/text.h> 74: #include <h/tty.h> 75: #include <h/conf.h> 76: #include <nlist.h> 77: #include <sys/stat.h> 78: #include <stdio.h> 79: #include <pwd.h> 80: 81: 82: #define TRUE 1 83: #define FALSE 0 84: #define INTPPG (NBPG/sizeof(int)) 85: #define MAXARGPG 5 86: 87: #define Usrptmap ((struct pte *)info.kaddr[ausrptmap]) 88: #define usrpt ((struct pte *)info.kaddr[ausrpt]) 89: #define cswitch ((struct cdevsw *)info.kaddr[acdevsw]) 90: struct proc *proc, *kproc; 91: struct text *text, *ktext; 92: struct buf *buf, *swbuf; 93: struct inode *inode; 94: int nproc, ntext, hz, nbuf, ninode, nfile, nswbuf; 95: union { 96: struct user user; 97: char upages[UPAGES][NBPG]; 98: } user; 99: int pad1; /* supposedly to aviod hardware problem reading /dev/mem */ 100: struct pte pagetable[UPAGES + MAXARGPG]; /* for users page table */ 101: int pad2; /* supposedly to aviod hardware problem reading /dev/mem */ 102: 103: #define u user.user 104: #define MSPID 2 /* max system pid, not to considered BUSY */ 105: 106: #define MAXUSERS 256 /* total different users */ 107: #define UNAMELENGTH 8 /* length of a user name */ 108: #define NSPEC 15 /* number of specified things (proc, user, tty */ 109: #define MAXTTYS 100 110: 111: /* definitions to reuse uninteresting proc table entries for linked lists */ 112: 113: struct procinfo { /* structure to use for */ 114: char *pi_cmd; /* attaching a time */ 115: struct ttyline *pi_tty; 116: long pi_time; /* and an arg string to a proc */ 117: }; 118: 119: #define p_next p_link /* pointer to next proc in global list */ 120: #define p_bro p_rlink /* next process with same parent */ 121: #define p_son p_xlink /* first child of this process */ 122: #define pinfo(p) (*((struct procinfo **)&p->p_sig)) 123: #define procsize(p) ((p)->p_tsize + (p)->p_dsize + (p)->p_ssize) 124: /* size of process */ 125: #define ABS(x) ((int)(x) & ~0x80000000) /* clear top bit - type int */ 126: #define K 1024 127: #define KSHIFT 10 128: 129: #define msize(x) (x >> (KSHIFT-PGSHIFT)) 130: 131: #define USERPAGE 0 /* flag for pread - read user page */ 132: #define TOPMEM 1 /* flag for pread - read top of mem */ 133: 134: struct proc *plist; 135: int mypid; /* pid of this process */ 136: 137: char Aflag, aflag, Bflag, bflag, cflag, dflag, eflag, fflag, Fflag; 138: char Gflag, iflag, lflag, mflag, nflag, rflag, Sflag, sflag, Tflag; 139: char Uflag, uflag, vflag, wflag, xflag, nxflag, Wflag, zflag; 140: int select; /* flag indicating process selection */ 141: 142: int ntotal, nbusy, nloaded, nswapped; 143: int ktotal, kbusy, kloaded, kswapped; 144: 145: /* specified users, ttys, pids, pgrps */ 146: union numptr { 147: int nm_int; 148: char *nm_ptr; 149: }; 150: 151: union ttyptr { 152: struct ttyline *ty_line; 153: char *ty_ptr; 154: }; 155: 156: union numptr pids[NSPEC], *ppids = pids; /* specified process ids */ 157: union numptr grps[NSPEC], *pgrps = grps; /* specified groups */ 158: union numptr uids[NSPEC], *puids = uids; /* specified user ids */ 159: union ttyptr ttys[NSPEC], *pttys = ttys; /* specified ttys */ 160: 161: /* files needed by ps */ 162: 163: char *memf = "/dev/mem"; /* default memory file */ 164: int mem; /* memory file descriptor */ 165: char *kmemf = "/dev/kmem"; /* virtual memory file */ 166: int kmem; /* virtual memory file descriptor */ 167: char *symf = "/vmunix"; /* default symbol file */ 168: char *swapf = "/dev/swap"; /* default swap file */ 169: int swap; /* swap area file descriptor */ 170: char *infof = "/etc/spsinfo"; /* default info save file */ 171: int infofd; /* info file descriptor */ 172: 173: /* variables read from the kernel */ 174: 175: struct nlist namelist[] = { 176: #define aproc 0 177: {"_proc"}, 178: #define aswapdev 1 179: {"_swapdev"}, 180: #define aswplo 2 181: {"_swplo"}, 182: #define answbuf 3 183: {"_nswbuf"}, 184: #define atext 4 185: {"_text"}, 186: #define abuf 5 187: {"_buf"}, 188: #define abfreeli 6 189: {"_bfreelist"}, 190: #define akl11 7 191: {"_kl11"}, 192: #define adh11 8 193: {"_dh11"}, 194: #define alpdt 9 195: {"_lp_softc"}, 196: #define albolt 10 197: {"_lbolt"}, 198: #define atout 11 199: {"_tout"}, 200: #define arunin 12 201: {"_runin"}, 202: #define arunout 13 203: {"_runout"}, 204: #define aipc 14 205: {"_ipc"}, 206: #define afile 15 207: {"_file"}, 208: #define ainode 16 209: {"_inode"}, 210: #define amaplock 17 211: {"_maplock"}, 212: #define acoremap 18 213: {"_coremap"}, 214: #define aswapmap 19 215: {"_swapmap"}, 216: #define au 20 217: {"_u"}, 218: #define adz11 21 219: {"_dz_tty"}, 220: #define aetext 22 221: {"_etext"}, 222: #define ausrptmap 23 223: {"_Usrptmap"}, 224: #define ausrpt 24 225: {"_usrpt"}, 226: #define achtbuf 25 227: {"_chtbuf"}, 228: #define arhtbuf 26 229: {"_rhtbuf"}, 230: #define ahpbuf 27 231: {"_hpbuf"}, 232: #define aswbuf 28 233: {"_swbuf"}, 234: #define arswbuf 29 235: {"_rswbuf"}, 236: #define acons 30 237: {"_cons"}, 238: #define ark7 31 239: {"_rrk7buf"}, 240: #define achrfclist 32 241: {"_Chrfclist"}, 242: #define anproc 33 243: {"_nproc"}, 244: #define antext 34 245: {"_ntext"}, 246: #define anbuf 35 247: {"_nbuf"}, 248: #define ahz 36 249: {"_hz"}, 250: #define aninode 37 251: {"_ninode"}, 252: #define anfile 38 253: {"_nfile"}, 254: #define answap 39 255: {"_nswap"}, 256: #define acdevsw 40 257: {"_cdevsw"}, 258: #define aChconntab 41 259: {"_Chconntab"}, 260: #define MAXSYMBOLS 42 261: {"", 0, 0}, 262: }; 263: 264: /* this structure is read from info file or initialized (iflag) */ 265: 266: struct { 267: caddr_t kaddr[MAXSYMBOLS]; /* useful kernel addresses */ 268: char unames[MAXUSERS][UNAMELENGTH]; /* user names */ 269: struct ttyline { 270: struct tty *l_addr; /* address of ttystruct */ 271: unsigned l_pgrp; /* process group */ 272: char l_name[2]; /* name */ 273: dev_t l_dev; /* device number */ 274: } ttyline[MAXTTYS]; 275: 276: } info; 277: int swapdev; /* major, minor of swap device */ 278: int swplo; /* unix swap disk offset */ 279: int nswap; /* unix swap space size */ 280: 281: struct ttyline notty = {0, 0, {"- "}}; 282: 283: /* flags for once only activities (once per repeat) */ 284: 285: int heading; 286: int coreinit, core; 287: char *topmem; 288: int arglength; 289: char *getcore(), *store(), *waitingfor(), *getcmd(), *strcat(), *brk(); 290: 291: main(argc,argv) 292: char *argv[]; 293: { 294: register char *cp, **ap; 295: register int i; 296: int myuid; 297: extern char _sobuf[]; 298: 299: if ((myuid = getuid()) == 0) 300: nice(-100); 301: 302: setbuf(stdout, _sobuf); 303: select = 0; 304: for (ap = &argv[1]; --argc; ap++) { 305: for (cp = *ap; *cp;) { 306: switch (*cp++) { 307: case '-': 308: continue; 309: case 'A': /* EVERYTHING */ 310: Aflag++; 311: continue; 312: case 'a': /* all procs attached to ttys */ 313: bflag++; /* include background */ 314: fflag++; /* include foreground */ 315: dflag++; /* include detached */ 316: aflag++; /* include shells */ 317: select++; 318: continue; 319: case 'b': /* all background processes */ 320: bflag++; 321: select++; 322: continue; 323: case 'B': /* all busy processes */ 324: Bflag++; 325: select++; 326: lflag++; 327: continue; 328: case 'c': 329: cflag++; 330: lflag++; 331: continue; 332: case 'd': /* detached processes */ 333: dflag++; 334: select++; 335: continue; 336: case 'e': 337: eflag++; 338: continue; 339: case 'f': /* foreground only */ 340: fflag++; 341: select++; 342: continue; 343: case 'F': /* go fast, don't touch swap */ 344: Fflag++; 345: continue; 346: case 'G': /* print pgrp */ 347: Gflag++; 348: continue; 349: case 'g': /* specify process gourp */ 350: select++; 351: while (argc > 1) { 352: if (**++ap == '-') { 353: ap--; 354: break; 355: } 356: --argc; 357: if (pgrps >= &grps[NSPEC]) 358: prexit("%a: too many groups\n"); 359: (pgrps++)->nm_int = atoi(*ap); 360: } 361: if (pgrps == grps) 362: (pgrps++)->nm_int = getpgrp(); 363: continue; 364: case 'i': /* initialize info file */ 365: if (myuid != 0) /* must be super user */ 366: goto def; 367: iflag++; 368: nflag++; 369: Uflag++; 370: continue; 371: case 'l': /* long output */ 372: lflag++; 373: continue; 374: case 'm': /* use designated memory file */ 375: if (myuid != 0) /* must be super user */ 376: goto def; 377: if (argc-- < 2 || **++ap == '-') 378: prexit("%a: missing memory file\n"); 379: memf = *ap; 380: mflag++; 381: continue; 382: case 'n': 383: select++; 384: nflag++; 385: continue; 386: case 'p': /* only designated processes */ 387: select++; 388: while (argc > 1) { 389: if (**++ap == '-') { 390: ap--; 391: break; 392: } 393: --argc; 394: if (ppids >= &pids[NSPEC]) 395: prexit("%a: too many pids\n"); 396: (ppids++)->nm_int = atoi(*ap); 397: } 398: continue; 399: case 'r': /* repeat every <number> seconds */ 400: if (myuid != 0) 401: goto def; 402: rflag++; 403: for (i = 0; *cp >= '0' && *cp <= '9'; cp++) 404: i = i * 10 + *cp - '0'; 405: if (i) 406: rflag = i; 407: continue; 408: case 'U': /* use designated symbol file */ 409: if (myuid != 0) 410: goto def; 411: if (argc-- < 2 || **++ap == '-') 412: prexit("%a: missing symbol file\n"); 413: symf = *ap; 414: Uflag++; 415: continue; 416: case 's': 417: sflag++; 418: select++; 419: continue; 420: case 'S': 421: Sflag++; 422: continue; 423: case 'T': 424: Tflag++; 425: continue; 426: case 't': /* on designated tty(s) */ 427: select++; 428: while (argc > 1) { 429: if (**++ap == '-') { 430: ap--; 431: break; 432: } 433: --argc; 434: if (pttys >= &ttys[NSPEC]) 435: prexit("%a: too many ttys\n"); 436: (pttys++)->ty_ptr = *ap; 437: } 438: if (pttys == ttys) { 439: char *ttyname(); 440: 441: if ( (pttys->ty_ptr = ttyname(2)) == 0) 442: prexit("%a: unknown tty\n"); 443: else if (strcmp("/dev/console", pttys->ty_ptr) == 0) 444: (pttys++)->ty_ptr = "co"; 445: else 446: (pttys++)->ty_ptr += 447: sizeof("/dev/tty") - 1; 448: } 449: continue; 450: case 'u': /* specific user name */ 451: aflag++; 452: select++; 453: puids = &uids[0]; 454: while (argc > 1) { 455: if (**++ap == '-') { 456: ap--; 457: break; 458: } 459: --argc; 460: if (puids >= &uids[NSPEC]) 461: prexit("%a: too many users\n"); 462: (puids++)->nm_ptr = *ap; 463: } 464: if (puids == &uids[0]) 465: (puids++)->nm_int = myuid; 466: continue; 467: case 'v': /* most verbose output */ 468: vflag++; 469: lflag++; 470: continue; 471: case 'W': 472: Wflag++; 473: continue; 474: case 'w': /* wide form (all arguments) */ 475: wflag++; 476: continue; 477: case 'x': /* include un-owned procs */ 478: xflag++; 479: select++; 480: continue; 481: case 'z': /* include only zombies */ 482: zflag++; 483: select++; 484: continue; 485: def: 486: default: 487: prexit("%a: unknown switch: %c\n", *--cp); 488: } 489: break; 490: } 491: } 492: 493: /* these lengths are kludgely tuned to make things not exceed 79 columns */ 494: arglength = 60; 495: if (lflag) 496: arglength -= 28; 497: if (vflag) 498: arglength -= 14; 499: if ((mem = open(memf, 0)) < 0) 500: prexit("%a: cannot read system memory: %s\n", memf); 501: if ((kmem = open(kmemf, 0)) < 0) 502: prexit("%a: cannot read system virtural memory: %s\n", kmemf); 503: if (!Fflag && (swap = open(swapf, 0)) <0) 504: prexit("%a: cannot read swap device: %s\n", swapf); 505: 506: if (!iflag) 507: if ((i = open(infof, 0)) < 0) 508: prexit("%a: cannot open info file\n"); 509: else if (read(i, &info, sizeof info) != sizeof info) 510: prexit("%a: cannot read info file\n"); 511: else 512: close(i); 513: if (Uflag) { 514: struct nlist *np; 515: if ((i = open(symf, 0)) < 0) 516: prexit("%a: can't read symbol file\n"); 517: close(i); 518: nlist(symf, namelist); 519: for (np = namelist; np < &namelist[MAXSYMBOLS]; np++) 520: if (np->n_value == 0) 521: fprintf(stderr, "%a: can't find symbol: %s\n", 522: np->n_name); 523: if (namelist[0].n_value == -1) 524: prexit("%a: cannot read symbol file: %s\n", symf); 525: for (i = 0; i < MAXSYMBOLS; i++) 526: info.kaddr[i] = (caddr_t)namelist[i].n_value; 527: info.kaddr[aetext] = (caddr_t)( ((unsigned)info.kaddr[aetext] + 63) & ~63); 528: } 529: if (iflag) { 530: readusers(); 531: ttyinit(); 532: if ((infofd = creat(infof, 0600)) < 0) 533: prexit("%a: cannot create info file\n"); 534: if ((i = write(infofd, &info, sizeof info)) != sizeof info) { 535: if (i == -1) 536: perror(0); 537: prexit("%a: cannot write info file: %d\n", i); 538: } 539: close(infofd); 540: } 541: lseek(kmem, (long)info.kaddr[aswapdev], 0); 542: read(kmem, &swapdev, sizeof(swapdev) ); 543: lseek(kmem, (long)info.kaddr[aswplo], 0); 544: read(kmem, &swplo, sizeof(swplo) ); 545: lseek(kmem, (long)info.kaddr[answap], 0); 546: read(kmem, &nswap, sizeof(nswap) ); 547: lseek(kmem, (long)info.kaddr[anproc], 0); 548: read(kmem, &nproc, sizeof(nproc) ); 549: lseek(kmem, (long)info.kaddr[antext], 0); 550: read(kmem, &ntext, sizeof(ntext) ); 551: lseek(kmem, (long)info.kaddr[anbuf], 0); 552: read(kmem, &nbuf, sizeof(nbuf) ); 553: lseek(kmem, (long)info.kaddr[abuf], 0); 554: read(kmem, &buf, sizeof(buf) ); 555: lseek(kmem, (long)info.kaddr[answbuf], 0); 556: read(kmem, &nswbuf, sizeof(nswbuf) ); 557: lseek(kmem, (long)info.kaddr[aswbuf], 0); 558: read(kmem, &swbuf, sizeof(swbuf) ); 559: lseek(kmem, (long)info.kaddr[aninode], 0); 560: read(kmem, &ninode, sizeof(ninode) ); 561: lseek(kmem, (long)info.kaddr[ainode], 0); 562: read(kmem, &inode, sizeof(inode) ); 563: lseek(kmem, (long)info.kaddr[ahz], 0); 564: read(kmem, &hz, sizeof(hz) ); 565: lseek(kmem, (long)info.kaddr[aproc], 0); 566: read(kmem, &kproc, sizeof(kproc)); 567: lseek(kmem, (long)info.kaddr[atext], 0); 568: read(kmem, &ktext, sizeof(ktext)); 569: proc = (struct proc *)getcore(nproc * sizeof(struct proc)); 570: text = (struct text *)getcore(ntext * sizeof(struct text)); 571: if (puids != &uids[0] && uids[0].nm_int != myuid) 572: usersetup(); 573: if (!select) { 574: mypid = getpid(); 575: (puids++)->nm_int = myuid; 576: nxflag++; 577: select++; 578: } 579: ttysetup(); 580: topmem = 0; 581: do { 582: heading = 0; /* reset heading flag (for repeat) */ 583: core = coreinit = 0; /* reset core flag (for repeat) */ 584: lseek(kmem, (long)kproc, 0); 585: read(kmem, proc, nproc * sizeof(struct proc)); 586: lseek(kmem, (long)ktext, 0); 587: read(kmem, text, ntext * sizeof(struct text)); 588: needed(); 589: mktree(); 590: action (plist, 0); 591: printf("%d processes (%dkb), %d busy (%dkb), %d loaded (%dkb)\n", 592: ntotal, (ctob(ktotal) + 1023) / 1024, 593: nbusy, (ctob(kbusy) + 1023) / 1024, 594: nloaded, (ctob(kloaded) + 1023) / 1024); 595: fflush(stdout); 596: } while (rflag && sleep(rflag) == 0); 597: exit(0); 598: } 599: 600: /* read the passwd file and fill in the user name arrays */ 601: readusers() 602: { 603: register struct passwd *pw; 604: struct passwd *getpwent(); 605: 606: while((pw = getpwent()) != 0) { 607: if(info.unames[pw->pw_uid][0] == '\0') 608: strcpyn(info.unames[pw->pw_uid], pw->pw_name, UNAMELENGTH); 609: } 610: endpwent(); 611: } 612: 613: /* check for specified user names */ 614: 615: usersetup() 616: { 617: register int i; 618: register union numptr *ip; 619: 620: for (ip = uids; ip < puids; ip++) { 621: for (i = 0; i < MAXUSERS; i++) 622: if (equalu(ip->nm_ptr, info.unames[i])) 623: goto cont2; 624: prexit("%a: unknown user: %s\n", ip->nm_ptr); 625: cont2: 626: ip->nm_int = i; 627: } 628: } 629: 630: /* compare a fixed length user name */ 631: 632: equalu(u1, u2) 633: register char *u1, *u2; 634: { 635: register int i = 0; 636: 637: while (*u1++ == *u2) 638: if (!*u2++ || ++i == UNAMELENGTH) 639: return 1; 640: return 0; 641: } 642: 643: /* 644: * Initialize the tty part of the info structure 645: */ 646: ttyinit() 647: { 648: struct direct dir; 649: struct stat sbuf; 650: int fd; 651: register struct ttyline *lp = info.ttyline; 652: 653: if ((fd = open("/dev", 0)) < 0) 654: prexit("%a: can't open /dev\n"); 655: chdir("/dev"); 656: while (read(fd, (char *)&dir, sizeof(dir)) == sizeof(dir)) { 657: if (dir.d_ino == 0 || 658: strncmp("tty", dir.d_name, 3) != 0 && 659: strcmp("console", dir.d_name) != 0) 660: continue; 661: if (dir.d_name[sizeof("tty") - 1] == 'C') 662: continue; 663: if (lp >= &info.ttyline[MAXTTYS]) 664: prexit("%a: too many ttys in /dev\n"); 665: if (dir.d_name[0] == 'c') { 666: lp->l_name[0] = 'c'; 667: lp->l_name[1] = 'o'; 668: } else { 669: lp->l_name[0] = dir.d_name[3]; 670: lp->l_name[1] = dir.d_name[4]; 671: } 672: stat(dir.d_name, &sbuf); 673: lp->l_dev = sbuf.st_rdev; 674: lseek(kmem, (long)&cswitch[major(sbuf.st_rdev)].d_ttys, 0); 675: read(kmem, (char *)&lp->l_addr, sizeof(lp->l_addr)); 676: lp->l_addr += minor(sbuf.st_rdev); 677: lp++; 678: } 679: close(fd); 680: } 681: ttysetup() 682: { 683: register struct ttyline *lp; 684: register char *cp; 685: union ttyptr *tp; 686: struct tty tty; 687: 688: for (lp = info.ttyline; lp->l_name[0]; lp++) { 689: lseek(kmem, (long)lp->l_addr, 0); 690: if (read(kmem, &tty, sizeof tty) != sizeof tty) 691: prexit("%a: read error in kmem\n"); 692: lp->l_pgrp = tty.t_pgrp; 693: if (Tflag) 694: printf("tty%-.2s: dev:%2d,%2d addr:%6x, rawq:%4d, canq:%d, outq:%4d, pgrp:%5d\n", 695: lp->l_name, major(lp->l_dev), minor(lp->l_dev), 696: ABS(lp->l_addr), tty.t_rawq.c_cc, 697: tty.t_canq.c_cc, tty.t_outq.c_cc, 698: tty.t_pgrp); 699: } 700: #ifdef CHAOS 701: mkchttys(lp); 702: #endif 703: /* now fix up specified ttys */ 704: 705: for (tp = &ttys[0]; tp < pttys; tp++) { 706: for (lp = info.ttyline; lp->l_name[0]; lp++) 707: if (strcmpn(tp->ty_ptr, lp->l_name, 2) == 0) { 708: tp->ty_line = lp; 709: goto cont2; 710: } 711: prexit("%a: unknown tty name: %c\n", tp->ty_ptr); 712: cont2:; 713: } 714: } 715: 716: /* 717: * Determine which procs are needed for the printout 718: * and add these to a list of needed processes (plist) 719: */ 720: needed() 721: { 722: register struct proc *p, *pp; 723: register struct text *tp; 724: struct ttyline *lp; 725: int ok; 726: 727: plist = 0; 728: nswapped = ntotal = nbusy = nloaded = 0; 729: kswapped = ktotal = kbusy = kloaded = 0; 730: 731: for (tp = text; tp < text + ntext; tp++) 732: if (tp->x_count) { 733: ktotal += tp->x_size; 734: if (!(tp->x_ccount)) 735: kswapped += tp->x_size; 736: } 737: 738: for (p = proc; p < proc + nproc; p++) { 739: if (!p->p_stat) 740: continue; 741: if (p->p_textp) 742: p->p_textp = &text[p->p_textp - ktext]; 743: if (p->p_pptr) { 744: p->p_pptr = &proc[p->p_pptr - kproc]; 745: if (p->p_pptr < proc || p->p_pptr >= &proc[nproc]) { 746: fprintf(stderr, "proc %d bad pptr\n", p->p_pid); 747: p->p_pptr = proc; 748: } 749: } else 750: p->p_pptr = proc; 751: } 752: for (p = &proc[0]; p < &proc[nproc]; p++) { 753: if (!p->p_stat) 754: continue; 755: ntotal++; 756: ktotal += procsize(p); 757: if (p->p_flag != SZOMB) 758: if (p->p_flag & SLOAD) { 759: nloaded++; 760: kloaded += procsize(p); 761: if ((tp = p->p_textp) && tp->x_count) { 762: tp->x_count = 0; 763: kloaded += tp->x_size; 764: } 765: } else { 766: nswapped++; 767: kswapped += procsize(p); 768: } 769: ok = FALSE; 770: if (p->p_stat == SRUN || 771: p->p_stat == SSLEEP && (p->p_pri < PZERO && p->p_pid > MSPID)) { 772: nbusy++; 773: kbusy += procsize(p); 774: if ((tp = p->p_textp) && tp->x_ccount) { 775: tp->x_ccount = 0; 776: kbusy += tp->x_size; 777: } 778: if (Bflag) 779: ok = TRUE; 780: } 781: if (nflag) 782: continue; 783: if (zflag && p->p_stat == SZOMB) 784: ok = TRUE; 785: if (sflag && p->p_stat == SSTOP) 786: ok = TRUE; 787: if (select == 0 && mypid && p->p_pid == mypid) 788: continue; 789: if (p->p_pgrp == 0) 790: if (xflag) 791: ok = TRUE; 792: else if (nxflag) 793: continue; 794: if (dflag && p->p_pgrp != 0 && (p->p_flag & SDETACH) != 0) 795: ok = TRUE; 796: if (aflag && xflag && p->p_pgrp != 0 && (p->p_flag & SDETACH) == 0 && 797: p->p_pptr == &proc[1]) 798: ok = TRUE; 799: if (puids != uids) { 800: register union numptr *ip; 801: 802: for (pp = p; pp > &proc[1]; pp = pp->p_pptr) 803: for (ip = uids; ip < puids; ip++) 804: if ((pp->p_uid & 0377) == ip->nm_int){ 805: ok = TRUE; 806: goto uidok; 807: } 808: } 809: uidok: 810: if (pgrps != grps) { 811: register union numptr *ip; 812: 813: for (pp = p; pp > &proc[1]; pp = pp->p_pptr) 814: for (ip = grps; ip < pgrps; ip++) 815: if (pp->p_pgrp == ip->nm_int) { 816: ok = TRUE; 817: goto pgrpok; 818: } 819: } 820: pgrpok: 821: if (ppids != pids) { 822: register union numptr *ip; 823: 824: for (ip = pids; ip < ppids; ip++) 825: if (ip->nm_int == p->p_pid) { 826: ok = TRUE; 827: goto procok; 828: } 829: } 830: procok: 831: if (select && pttys == ttys && !fflag && !bflag && !ok) 832: continue; 833: if (getu(p) == 0) { 834: static struct procinfo fakep = {"--no upage--", ¬ty, 0}; 835: 836: if (select && !ok) 837: continue; 838: pinfo(p) = &fakep; 839: goto putonlist; 840: } 841: if (pttys != ttys && p->p_pgrp != 0) { 842: union ttyptr *ip; 843: 844: for (ip = ttys; ip < pttys; ip++) 845: if (p->p_pgrp && p->p_pgrp == ip->ty_line->l_pgrp || 846: p->p_stat == SSLEEP && 847: p->p_wchan >= (char *)ip->ty_line->l_addr && 848: p->p_wchan < (char *)ip->ty_line->l_addr + 849: sizeof (struct tty) || 850: u.u_ttyd == ip->ty_line->l_dev) { 851: ok = TRUE; 852: break; 853: } 854: } 855: if (p->p_pgrp == 0) 856: lp = ¬ty; 857: else { 858: for (lp = info.ttyline; lp->l_name[0] != 0; lp++) 859: if (lp->l_dev == u.u_ttyd) 860: break; 861: if (lp->l_name[0] == 0) 862: lp = ¬ty; 863: else if (p->p_pptr != &proc[1]) { 864: if (fflag && p->p_pgrp == lp->l_pgrp) 865: ok = TRUE; 866: if (bflag && p->p_pgrp != lp->l_pgrp && 867: (p->p_flag & SDETACH) == 0 && 868: p->p_stat != SSTOP) 869: ok = TRUE; 870: } 871: } 872: if (select && !ok) 873: continue; 874: pinfo(p) = (struct procinfo *)getcore(sizeof (struct procinfo)); 875: pinfo(p)->pi_time = u.u_vm.vm_utime + u.u_vm.vm_stime; 876: pinfo(p)->pi_tty = lp; 877: pinfo(p)->pi_cmd = getcmd(p); 878: putonlist: 879: /* we have a needed proc! */ 880: 881: p->p_next = plist; 882: plist = p; 883: p->p_son = p->p_bro = 0; 884: } 885: } 886: /* 887: * mktree - sort the needed processes by subtree and at the top by user 888: */ 889: mktree() 890: { 891: register struct proc *p, *pp, *lp; 892: struct proc *op; 893: struct proc proot; 894: 895: proot.p_bro = 0; 896: 897: for (p = plist; p; p = p->p_next) { /* for all needed processes */ 898: if (p->p_pptr > &proc[1]) { 899: for (pp = plist; pp; pp = pp->p_next) 900: if (pp == p->p_pptr) { /* if my parent */ 901: if (lp = pp->p_son) { /* if siblings */ 902: for (op = 0; lp && lp->p_pid < 903: p->p_pid; 904: lp = (op = lp)->p_bro) 905: ; 906: if (op) { 907: p->p_bro = lp; 908: op->p_bro = p; 909: break; 910: } 911: } 912: p->p_bro = lp; /* here if first or only */ 913: pp->p_son = p; 914: break; 915: } 916: if (pp) /* if we found the parent */ 917: continue; 918: } 919: 920: /* we have a top level process, sort into top level list */ 921: 922: for (pp = (lp = &proot)->p_bro; pp; pp = (lp = pp)->p_bro) 923: if ((p->p_uid & 0377) < (pp->p_uid & 0377) || 924: (p->p_uid & 0377) == (pp->p_uid & 0377) && 925: p->p_pid < pp->p_pid) 926: break; 927: p->p_bro = lp->p_bro; 928: lp->p_bro = p; 929: } 930: plist = proot.p_bro; 931: } 932: 933: action(p, md) 934: register struct proc *p; 935: register int md; 936: { 937: 938: if (p) { 939: printp(p, md); 940: if (p->p_son) 941: action(p->p_son, md+1); 942: if (p->p_bro) 943: action(p->p_bro, md); 944: } 945: } 946: 947: /* 948: * Pretty print the output according to the switches. 949: */ 950: printp(p, md) 951: register struct proc *p; 952: { 953: register char *cp, *cp1; 954: char stat[10]; 955: static int lastuid; 956: static char *statnames[] = {"Unk ", "Wait", "Wait", "Run ", 957: "Init", "Exit", "Stop"}; 958: 959: if (!heading) { 960: heading++; 961: printf("Ty User "); 962: if (lflag) { 963: printf("Stat"); 964: if (vflag) printf(" Flgs Nice Pri "); 965: else printf(" "); 966: printf("Memory-kb Time Wait? "); 967: } 968: if (Aflag) 969: printf("Address Proc. Clock Alarm "); 970: if (Sflag) 971: printf("Size "); 972: if (Gflag) 973: printf("Group "); 974: printf("Proc# Command\n"); 975: } 976: printf("%.2s%c", pinfo(p)->pi_tty->l_name, 977: p->p_pgrp == 0 ? ' ' : 978: p->p_flag & SDETACH ? '_' : 979: p->p_pgrp == pinfo(p)->pi_tty->l_pgrp ? '.' : 980: ' '); 981: 982: if (md == 0) { 983: lastuid = p->p_uid & 0377; 984: cp = info.unames[lastuid]; 985: if (*cp) 986: printf("%-8.8s ", cp); 987: else 988: printf("user%-4.4d ", lastuid); 989: } else { 990: if (md > 8) 991: md = 8; 992: printf("%*s*", md, ""); 993: if ((p->p_uid & 0377) != lastuid) { /* setuid process! */ 994: lastuid = p->p_uid & 0377; 995: cp = info.unames[lastuid]; 996: } else 997: cp = ""; 998: md = 8 - md; 999: printf("%-*.*s", md, md, cp); 1000: } 1001: if (lflag) { 1002: cp = statnames[p->p_stat]; 1003: if (p->p_flag&SLOAD) { 1004: for (cp1 = stat; *cp1 = *cp; cp1++, cp++) 1005: if (*cp >= 'a' && *cp <= 'z') 1006: *cp1 -= 'a' - 'A'; 1007: cp = stat; 1008: } 1009: printf("%-4.4s ", cp); 1010: if (vflag) { 1011: cp = stat; 1012: if (p->p_flag & SSYS) *cp++ = 'U'; 1013: if (p->p_flag&SLOCK) *cp++ = 'L'; 1014: if (p->p_flag&STRC) *cp++ = 'T'; 1015: if (p->p_flag&SWTED) *cp++ = 'W'; 1016: if (p->p_flag&SSWAP) *cp++ = 'S'; 1017: while(cp < &stat[5]) *cp++ = ' '; 1018: *cp = 0; 1019: printf("%-4.4s ",stat); 1020: if (p->p_nice != NZERO) 1021: printf("%4d", p->p_nice - NZERO); 1022: else 1023: printf(" "); 1024: if (p->p_stat != SZOMB) 1025: printf("%4d ", p->p_pri); 1026: else 1027: printf(" "); 1028: } 1029: if (p->p_stat != SZOMB) { 1030: printf("%4d", msize(procsize(p)) ); 1031: if (p->p_textp) 1032: printf("+%4d ", msize(p->p_textp->x_size)); 1033: else 1034: printf(" "); 1035: prcpu(pinfo(p)->pi_time); 1036: } else 1037: printf(" "); 1038: if (p->p_stat != SZOMB && p->p_stat != SRUN && p->p_stat != SSTOP) 1039: if (!Wflag && (cp = waitingfor(p))) 1040: printf("%-6.6s ", cp); 1041: else printf("%6x ", ABS((int)p->p_wchan)); 1042: else printf(" "); 1043: } 1044: if (Aflag) 1045: printf("%6x %6x %6d%6d ", p->p_addr, 1046: (p - proc) * sizeof (struct proc) + info.kaddr[aproc], 1047: p->p_time, p->p_clktim); 1048: if (Sflag) 1049: printf("%5x ", procsize(p) ); 1050: if (Gflag) 1051: printf("%5D ", p->p_pgrp); 1052: printf("%5D ", p->p_pid); 1053: if (wflag) 1054: printf("%s\n", pinfo(p)->pi_cmd); 1055: else 1056: printf("%-.*s\n", arglength, pinfo(p)->pi_cmd); 1057: } 1058: 1059: /* print cpu time */ 1060: 1061: prcpu(time) 1062: long time; 1063: { 1064: register unsigned i; 1065: 1066: if (time < 0) 1067: printf(" ---- "); 1068: else if (time < (long)hz * 60 * 10) /* less than 10 minutes */ 1069: printf("%3d.%1d ", 1070: (int)(time / hz), 1071: (int)(time % hz / (hz / 10))); 1072: else if (time < (long)hz * 60 * 60 * 10)/* less than 10 hours */ 1073: printf("%3d M ", 1074: (int)((time + (hz * 60) / 2) / (hz * 60))); 1075: else { 1076: i = (time + ((long)hz * 60 * 60) / 2) / 1077: ((long)hz * 60 * 60); 1078: if (i < 1000) 1079: printf("%3d H ", i); 1080: else 1081: printf(" ---- "); 1082: } 1083: } 1084: /* Determine what a process is waiting for and describe it. */ 1085: 1086: char * 1087: waitingfor(p) 1088: register struct proc *p; 1089: { 1090: register caddr_t w; 1091: register struct ttyline *lp; 1092: register char *cp; 1093: 1094: w = p->p_wchan; 1095: if (w == (caddr_t)0) 1096: return "null"; 1097: if (w >= (char *)kproc && w < (char *)(kproc + nproc)) 1098: return "child"; 1099: if (w >= (char *)swbuf && w < (char *)(swbuf + nswbuf)) 1100: return "swap"; 1101: if (w == info.kaddr[arswbuf]) 1102: return "rswap"; 1103: if (w >= (char *)buf && w < (char *)(buf + nbuf)) 1104: return "diskio"; 1105: if (w >= info.kaddr[afile] && w < info.kaddr[afile] + sizeof(struct file) * nfile) 1106: return "file"; 1107: if (w >= (char *)inode && w < (char *)(inode + ninode)) 1108: switch((w - (char *)inode) % sizeof(struct inode)) { 1109: case 1: 1110: return "wpipe"; 1111: case 2: 1112: return "rpipe"; 1113: case 3: 1114: return "mutex"; 1115: case (int)&((struct inode *)0)->i_un.i_group.g_datq: 1116: return "rmux"; 1117: default: 1118: return "inode"; 1119: } 1120: if (w == info.kaddr[achtbuf]) 1121: return "tapecn"; 1122: if (w == info.kaddr[ahpbuf]) 1123: return "rpdisk"; 1124: if (w == info.kaddr[ark7]) 1125: return "rkdisk"; 1126: if (w == info.kaddr[arhtbuf]) 1127: return "tapeio"; 1128: if (w == info.kaddr[alpdt]) 1129: return "printr"; 1130: if (w == info.kaddr[albolt]) 1131: return "lbolt"; 1132: if (w == info.kaddr[arunin]) 1133: return "runin"; 1134: if (w == info.kaddr[arunout]) 1135: return "runout"; 1136: if (w == info.kaddr[atout]) 1137: return "sleep"; 1138: if (w == info.kaddr[aipc]) 1139: return "ptrace"; 1140: if (w == info.kaddr[abfreeli]) 1141: return "buffer"; 1142: if (w == info.kaddr[amaplock]) 1143: return "ubmap"; 1144: if (w == info.kaddr[au]) 1145: return "pause"; 1146: if (w == info.kaddr[achrfclist]) 1147: return "chrfc"; 1148: for (lp = info.ttyline; lp->l_name[0]; lp++) 1149: if (w >= (char *)lp->l_addr && w < (char *)lp->l_addr + sizeof (struct tty)) { 1150: #define TTY0 ((struct tty *)0) 1151: switch(w - (char *)lp->l_addr) { 1152: case (int)&TTY0->t_rawq: 1153: cp = "rtty??"; 1154: break; 1155: case (int)&TTY0->t_outq: 1156: cp = "wtty??"; 1157: break; 1158: case (int)&TTY0->t_state: 1159: cp = "otty??"; 1160: break; 1161: default: 1162: cp = "?tty??"; 1163: } 1164: cp[4] = lp->l_name[0]; 1165: cp[5] = lp->l_name[1]; 1166: return cp; 1167: } 1168: return 0; 1169: } 1170: 1171: getu(mproc) 1172: register struct proc *mproc; 1173: { 1174: struct pte *pteaddr, apte; 1175: register int i; 1176: int ncl, size; 1177: 1178: size = Sflag ? ctob(UPAGES) : sizeof (struct user); 1179: if ((mproc->p_flag & SLOAD) == 0) { 1180: lseek(swap, (long)ctob(mproc->p_swaddr), 0); 1181: if (read(swap, (char *)&user.user, size) != size) { 1182: fprintf(stderr, "%a: cant read u for pid %d from %s\n", 1183: mproc->p_pid, swapf); 1184: return (0); 1185: } 1186: return (1); 1187: } 1188: pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1]; 1189: lseek(kmem, (long)(mflag ? ABS(pteaddr) : (int)pteaddr), 0); 1190: if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { 1191: printf("%a: cant read indir pte to get u for pid %d from %s\n", 1192: mproc->p_pid, swapf); 1193: return (0); 1194: } 1195: lseek(mem, (long) 1196: (ctob(apte.pg_pfnum+1) - (UPAGES+MAXARGPG) * sizeof (struct pte)), 1197: 0); 1198: if (read(mem, (char *)pagetable, sizeof(pagetable)) != sizeof(pagetable)) { 1199: printf("%a: cant read page table for u of pid %d from %s\n", 1200: mproc->p_pid, swapf); 1201: return (0); 1202: } 1203: ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); 1204: while (--ncl >= 0) { 1205: i = ncl * CLSIZE; 1206: lseek(mem, (long)ctob(pagetable[MAXARGPG+i].pg_pfnum), 0); 1207: if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) { 1208: printf("%a: cant read page %d of u of pid %d from %s\n", 1209: pagetable[MAXARGPG+i].pg_pfnum, mproc->p_pid, memf); 1210: return(0); 1211: } 1212: } 1213: return (1); 1214: } 1215: char * 1216: getcmd(p) 1217: register struct proc *p; 1218: { 1219: struct pte apte; 1220: char argbuf[MAXARGPG * NBPG], *argptr; 1221: register int *ip; 1222: register char *cp, *cp1; 1223: int cc, nbad, i; 1224: 1225: if (p->p_stat == SZOMB) 1226: return "--Defunct--"; 1227: if ((p->p_flag&SLOAD) == 0 && Fflag) 1228: return "--Swapped--"; 1229: if (p->p_flag & SSYS) 1230: return p->p_pid == 0 ? "UNIX Swapper" : 1231: p->p_pid == 2 ? "UNIX Pager" : "UNIX"; 1232: for (i = 0; i < MAXARGPG; i++) { 1233: argptr = &argbuf[(MAXARGPG - 1 - i) * NBPG]; 1234: apte = pagetable[MAXARGPG - 1 - i]; 1235: if ((p->p_flag & SLOAD) && apte.pg_fod == 0 && apte.pg_pfnum ) { 1236: lseek(mem, (long)ctob(apte.pg_pfnum), 0); 1237: if (read(mem, argptr, NBPG) != NBPG) 1238: return "---Mem read error (args)---"; 1239: } else if (Fflag) 1240: goto cheap; 1241: else { 1242: lseek(swap, (long)ctob(u.u_smap.dm_map[0] + DMMIN - 1 - i), 0); 1243: if (read(swap, argptr, NBPG) != NBPG) 1244: return "---Swap read error (args)---"; 1245: } 1246: /* Here block of stack is at argptr */ 1247: ip = (int *)&argptr[NBPG]; 1248: if (i == 0) { 1249: *--ip = 0; 1250: ip--; 1251: } 1252: while (ip > (int *)argptr && *--ip != 0) 1253: ; 1254: if (ip > (int *)argptr || *ip == 0) 1255: break; 1256: } 1257: if (i >= MAXARGPG) { 1258: cheap: 1259: argbuf[0] = '('; 1260: strncpy(&argbuf[1], u.u_comm, sizeof(u.u_comm)); 1261: strcat(argbuf, ")"); 1262: return store(argbuf); 1263: } 1264: cp = (char *)(ip + 1); 1265: if (*cp == '\0') 1266: cp++; 1267: nbad = 0; 1268: for (cp1 = cp; cp1 < &argbuf[MAXARGPG*NBPG]; cp1++) { 1269: cc = *cp1 & 0177; 1270: if (cc == 0) 1271: *cp1 = ' '; 1272: else if (cc < ' ' || cc == 0177) { 1273: if (++nbad >= 5) { 1274: *cp1++ = ' '; 1275: break; 1276: } 1277: *cp1 = '?'; 1278: } else if (!eflag && cc == '=') { 1279: *cp1 = 0; 1280: while (cp1 > cp && *--cp1 != ' ') 1281: *cp1 = 0; 1282: break; 1283: } 1284: } 1285: while (*--cp1 == ' ') 1286: *cp1 = 0; 1287: if (!wflag && &cp[arglength] < (char *)&argbuf[MAXARGPG*NBPG - 1]) 1288: cp[arglength] = 0; 1289: return store(cp); 1290: } 1291: 1292: /* 1293: * Store a string in core for later use. 1294: */ 1295: char * 1296: store(cp) 1297: char *cp; 1298: { 1299: register char *src, *dst, *svdst; 1300: 1301: src = cp; 1302: while (*src++); 1303: svdst = getcore(src - cp); 1304: dst = svdst; 1305: src = cp; 1306: while (*dst++ = *src++); 1307: return(svdst); 1308: } 1309: 1310: /* 1311: * Allocate and return a pointer to the asked for amount of core 1312: */ 1313: char * 1314: getcore(cnt) 1315: register int cnt; 1316: { 1317: static char *corep; 1318: register char *ip; 1319: register int incr; 1320: char *sbrk(); 1321: 1322: if (cnt > core) { 1323: if (coreinit == 0) { 1324: coreinit++; 1325: if (topmem) 1326: brk(topmem); /* after repeat!! */ 1327: else 1328: topmem = sbrk(0); 1329: corep = topmem; 1330: } 1331: incr = cnt > 4096 ? cnt : 4096; 1332: if (sbrk(incr) == 0) 1333: prexit("%a: out of memory!\n"); 1334: core += incr; 1335: } 1336: ip = corep; 1337: core -= cnt; 1338: corep += cnt; 1339: return(ip); 1340: } 1341: #ifdef CHAOS 1342: #include "chunix/chsys.h" 1343: #include <chaos/chaos.h> 1344: 1345: mkchttys(lp) 1346: register struct ttyline *lp; 1347: { 1348: register struct connection **cnp; 1349: register int i; 1350: struct tty tty; 1351: struct connection *Chconntab[CHNCONNS]; 1352: struct connection conn; 1353: 1354: lseek(kmem, (long)info.kaddr[aChconntab], 0); 1355: read(kmem, (char *)Chconntab, sizeof(Chconntab)); 1356: for (i = 0, cnp = Chconntab; cnp < &Chconntab[CHNCONNS]; i++, cnp++) { 1357: if (!*cnp) 1358: continue; 1359: lseek(kmem, (long)*cnp, 0); 1360: read(kmem, (char *)&conn, sizeof(conn)); 1361: if ((conn.cn_flags & CHTTY) == 0) 1362: continue; 1363: lseek(kmem, (long)conn.cn_ttyp, 0); 1364: read(kmem, (char *)&tty, sizeof(tty)); 1365: if (lp >= &info.ttyline[MAXTTYS]) 1366: prexit("%a: too many ttys\n"); 1367: lp->l_addr = conn.cn_ttyp; 1368: lp->l_pgrp = tty.t_pgrp; 1369: lp->l_dev = tty.t_dev; 1370: lp->l_name[0] = 'C'; 1371: lp->l_name[1] = i < 10 ? '0' + i : 1372: i - 10 <= 'z' - 'a' ? i - 10 + 'a' : 1373: i - 10 - ('z' - 'a') + 'A'; 1374: if (Tflag) 1375: printf("tty%-.2s: dev:%2d,%2d addr:%6x, rawq:%4d, canq:%d, outq:%4d, pgrp:%5d\n", 1376: lp->l_name, major(lp->l_dev), minor(lp->l_dev), 1377: ABS(lp->l_addr), tty.t_rawq.c_cc, 1378: tty.t_canq.c_cc, tty.t_outq.c_cc, 1379: tty.t_pgrp); 1380: lp++; 1381: } 1382: } 1383: #endif