try again (better format for times >99:59)
[unix-history] / usr / src / bin / ps / ps.c
CommitLineData
761330fe
DF
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
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
3d9f6a35 13#ifndef lint
d0ba9285 14static char sccsid[] = "@(#)ps.c 5.15 (Berkeley) %G%";
761330fe 15#endif not lint
3d9f6a35 16
aafc2e2f
BJ
17#include <stdio.h>
18#include <ctype.h>
3180e1ce 19#include <a.out.h>
aafc2e2f
BJ
20#include <pwd.h>
21#include <sys/param.h>
417dadf5 22#include <sys/ioctl.h>
aafc2e2f 23#include <sys/tty.h>
b38b1b3a 24#include <sys/dir.h>
aafc2e2f
BJ
25#include <sys/user.h>
26#include <sys/proc.h>
0bc29a7d 27#include <machine/pte.h>
aafc2e2f
BJ
28#include <sys/vm.h>
29#include <sys/text.h>
30#include <sys/stat.h>
066ec2ef 31#include <sys/mbuf.h>
7f0fa372 32#include <math.h>
e8807835 33#include <errno.h>
aafc2e2f 34
3180e1ce
KM
35char *nl_names[] = {
36 "_proc",
aafc2e2f 37#define X_PROC 0
3180e1ce 38 "_Usrptmap",
e8807835 39#define X_USRPTMAP 1
3180e1ce 40 "_usrpt",
aafc2e2f 41#define X_USRPT 2
3180e1ce 42 "_text",
aafc2e2f 43#define X_TEXT 3
3180e1ce 44 "_nswap",
aafc2e2f 45#define X_NSWAP 4
3180e1ce 46 "_maxslp",
c67277e8 47#define X_MAXSLP 5
3180e1ce 48 "_ccpu",
7f0fa372 49#define X_CCPU 6
3180e1ce 50 "_ecmx",
0f0e0052 51#define X_ECMX 7
3180e1ce 52 "_nproc",
bdb1f95f 53#define X_NPROC 8
3180e1ce 54 "_ntext",
bdb1f95f 55#define X_NTEXT 9
3180e1ce 56 "_dmmin",
b38b1b3a 57#define X_DMMIN 10
3180e1ce 58 "_dmmax",
b38b1b3a 59#define X_DMMAX 11
3180e1ce 60 "_Sysmap",
e8807835 61#define X_SYSMAP 12
3180e1ce 62 "_Syssize",
e8807835 63#define X_SYSSIZE 13
3180e1ce
KM
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
db3eb2dc 80 "_namecache",
3180e1ce
KM
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 ""
aafc2e2f
BJ
95};
96
3180e1ce
KM
97struct nlist *nl; /* all because we can't init unions */
98int nllen; /* # of nlist entries */
99
aafc2e2f
BJ
100struct savcom {
101 union {
102 struct lsav *lp;
103 float u_pctcpu;
104 struct vsav *vp;
105 int s_ssiz;
066ec2ef 106 } s_un;
aafc2e2f 107 struct asav *ap;
bdb1f95f 108} *savcom;
aafc2e2f
BJ
109
110struct asav {
111 char *a_cmdp;
112 int a_flag;
c67277e8 113 short a_stat, a_uid, a_pid, a_nice, a_pri, a_slptime, a_time;
0f0e0052
BJ
114 size_t a_size, a_rss, a_tsiz, a_txtrss;
115 short a_xccount;
3d9f6a35 116 char a_tty[MAXNAMLEN+1];
aafc2e2f 117 dev_t a_ttyd;
c67277e8 118 time_t a_cpu;
79de1ed3 119 size_t a_maxrss;
aafc2e2f
BJ
120};
121
122char *lhdr;
3180e1ce 123int wcwidth; /* width of the wchan field for sprintf*/
aafc2e2f
BJ
124struct lsav {
125 short l_ppid;
ed325f47 126 u_char l_cpu;
aafc2e2f
BJ
127 int l_addr;
128 caddr_t l_wchan;
129};
130
131char *uhdr;
aafc2e2f 132char *shdr;
aafc2e2f
BJ
133
134char *vhdr;
aafc2e2f 135struct vsav {
0f0e0052
BJ
136 u_int v_majflt;
137 size_t v_swrss, v_txtswrss;
138 float v_pctcpu;
aafc2e2f
BJ
139};
140
e8807835
RC
141#define NPROC 16
142
143struct proc proc[NPROC]; /* a few, for less syscalls */
aafc2e2f
BJ
144struct proc *mproc;
145struct text *text;
146
147union {
148 struct user user;
149 char upages[UPAGES][NBPG];
150} user;
151#define u user.user
152
e8807835
RC
153#ifndef PSFILE
154char *psdb = "/etc/psdatabase";
155#else
156char *psdb = PSFILE;
157#endif
aafc2e2f 158
2e06a8e0 159int chkpid = -1;
3180e1ce 160int aflg, cflg, eflg, gflg, kflg, lflg, nflg, sflg,
e8807835 161 uflg, vflg, xflg, Uflg;
3180e1ce 162int nchans; /* total # of wait channels */
aafc2e2f 163char *tptr;
e8807835 164char *gettty(), *getcmd(), *getname(), *savestr(), *state();
3d9f6a35 165char *rindex(), *calloc(), *sbrk(), *strcpy(), *strcat(), *strncat();
963be923 166char *strncpy(), *index(), *ttyname(), mytty[MAXPATHLEN+1];
3180e1ce 167char *malloc(), *getchan();
3d9f6a35 168long lseek();
e8807835 169off_t vtophys();
0f0e0052 170double pcpu(), pmem();
3180e1ce 171int wchancomp();
aafc2e2f 172int pscomp();
c67277e8 173int nswap, maxslp;
bdb1f95f 174struct text *atext;
7f0fa372 175double ccpu;
0f0e0052 176int ecmx;
e8807835 177struct pte *Usrptmap, *usrpt;
066ec2ef 178int nproc, ntext;
b38b1b3a 179int dmmin, dmmax;
e8807835
RC
180struct pte *Sysmap;
181int Syssize;
182
e8807835 183int nttys;
aafc2e2f
BJ
184
185struct ttys {
aafc2e2f 186 dev_t ttyd;
3bc0950e 187 int cand;
e8807835 188 char name[MAXNAMLEN+1];
3bc0950e
KM
189} *allttys;
190int cand[16] = {-1, -1, -1, -1, -1, -1, -1, -1,
191 -1, -1, -1, -1, -1, -1, -1, -1};
192struct lttys {
193 struct ttys ttys;
194 struct lttys *next;
195} *lallttys;
196
3180e1ce
KM
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
208struct 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
215caddr_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 */
221char *wchan_stop_list[] = {
222 "umbabeg",
223 "umbaend",
224 "calimit",
225 NULL
226};
aafc2e2f 227
aafc2e2f
BJ
228int npr;
229
230int cmdstart;
231int twidth;
ceb20920 232struct winsize win;
aafc2e2f 233char *kmemf, *memf, *swapf, *nlistf;
25659ede 234int kmem, mem, swap = -1;
1fb6a666 235int rawcpu, sumcpu;
aafc2e2f
BJ
236
237int pcbpf;
238int argaddr;
aafc2e2f 239
72db1f59 240#define pgtok(a) ((a)/(1024/NBPG))
066ec2ef 241
aafc2e2f
BJ
242main(argc, argv)
243 char **argv;
244{
245 register int i, j;
246 register char *ap;
247 int uid;
248 off_t procp;
417dadf5 249 int width;
aafc2e2f 250
78d22f16 251 if (ioctl(1, TIOCGWINSZ, &win) == -1)
417dadf5
JB
252 twidth = 80;
253 else
254 twidth = (win.ws_col == 0 ? 80 : win.ws_col);
aafc2e2f
BJ
255 argc--, argv++;
256 if (argc > 0) {
257 ap = argv[0];
258 while (*ap) switch (*ap++) {
259
0f0e0052 260 case 'C':
066ec2ef 261 rawcpu++;
0f0e0052 262 break;
1fb6a666
BJ
263 case 'S':
264 sumcpu++;
265 break;
e8807835
RC
266
267 case 'U':
268 Uflg++;
269 break;
270
aafc2e2f
BJ
271 case 'a':
272 aflg++;
273 break;
274 case 'c':
066ec2ef 275 cflg = !cflg;
aafc2e2f
BJ
276 break;
277 case 'e':
066ec2ef 278 eflg++;
aafc2e2f
BJ
279 break;
280 case 'g':
066ec2ef 281 gflg++;
aafc2e2f
BJ
282 break;
283 case 'k':
066ec2ef 284 kflg++;
aafc2e2f
BJ
285 break;
286 case 'l':
066ec2ef 287 lflg++;
aafc2e2f 288 break;
3180e1ce
KM
289 case 'n':
290 nflg++;
291 break;
aafc2e2f 292 case 's':
066ec2ef 293 sflg++;
aafc2e2f
BJ
294 break;
295 case 't':
296 if (*ap)
297 tptr = ap;
963be923
MK
298 else if ((tptr = ttyname(0)) != 0) {
299 tptr = strcpy(mytty, tptr);
300 if (strncmp(tptr, "/dev/", 5) == 0)
301 tptr += 5;
e13b2716 302 }
963be923
MK
303 if (strncmp(tptr, "tty", 3) == 0)
304 tptr += 3;
066ec2ef 305 aflg++;
aafc2e2f 306 gflg++;
066ec2ef 307 if (tptr && *tptr == '?')
aafc2e2f
BJ
308 xflg++;
309 while (*ap)
310 ap++;
311 break;
133a0b3b 312 case 'u':
066ec2ef 313 uflg++;
aafc2e2f
BJ
314 break;
315 case 'v':
316 cflg = 1;
066ec2ef 317 vflg++;
aafc2e2f
BJ
318 break;
319 case 'w':
417dadf5 320 if (twidth < 132)
aafc2e2f
BJ
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;
066ec2ef 333 aflg++;
aafc2e2f
BJ
334 xflg++;
335 break;
336 }
337 }
338 openfiles(argc, argv);
339 getkvars(argc, argv);
aafc2e2f
BJ
340 uid = getuid();
341 printhdr();
bdb1f95f
BJ
342 procp = getw(nl[X_PROC].n_value);
343 nproc = getw(nl[X_NPROC].n_value);
e8807835
RC
344 savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
345 for (i=0; i<nproc; i += NPROC) {
3d9f6a35 346 klseek(kmem, (long)procp, 0);
bdb1f95f 347 j = nproc - i;
e8807835
RC
348 if (j > NPROC)
349 j = NPROC;
aafc2e2f 350 j *= sizeof (struct proc);
25659ede 351 if (read(kmem, (char *)proc, j) != j) {
aafc2e2f 352 cantread("proc table", kmemf);
25659ede
BJ
353 exit(1);
354 }
aafc2e2f
BJ
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)
c67277e8 360 continue;
aafc2e2f 361 if (tptr == 0 && gflg == 0 && xflg == 0 &&
6e515893 362 mproc->p_ppid == 1)
aafc2e2f 363 continue;
e8807835
RC
364 if (uid != mproc->p_uid && aflg==0)
365 continue;
2e06a8e0 366 if (chkpid != -1 && chkpid != mproc->p_pid)
aafc2e2f
BJ
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 }
417dadf5
JB
380 width = twidth - cmdstart - 2;
381 if (width < 0)
382 width = 0;
e8807835 383 qsort((char *) savcom, npr, sizeof(savcom[0]), pscomp);
aafc2e2f
BJ
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);
963be923 394 if (sp->ap->a_stat == SZOMB)
ed325f47 395 printf(" %.*s", twidth - cmdstart - 2, "<defunct>");
963be923 396 else if (sp->ap->a_flag & SWEXIT)
ed325f47 397 printf(" %.*s", twidth - cmdstart - 2, "<exiting>");
aafc2e2f 398 else if (sp->ap->a_pid == 0)
ed325f47 399 printf(" %.*s", twidth - cmdstart - 2, "swapper");
aafc2e2f 400 else if (sp->ap->a_pid == 2)
ed325f47 401 printf(" %.*s", twidth - cmdstart - 2, "pagedaemon");
aafc2e2f
BJ
402 else
403 printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
404 printf("\n");
405 }
406 exit(npr == 0);
407}
408
bdb1f95f 409getw(loc)
3d9f6a35 410 unsigned long loc;
bdb1f95f 411{
e8807835 412 int word;
bdb1f95f 413
3d9f6a35
KM
414 klseek(kmem, (long)loc, 0);
415 if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
bdb1f95f
BJ
416 printf("error reading kmem at %x\n", loc);
417 return (word);
418}
419
6e515893 420klseek(fd, loc, off)
3d9f6a35
KM
421 int fd;
422 long loc;
423 int off;
6e515893 424{
e8807835
RC
425 if (kflg) {
426 if ((loc = vtophys(loc)) == -1)
427 return;
428 }
3d9f6a35 429 (void) lseek(fd, (long)loc, off);
6e515893
BJ
430}
431
916caac0
KM
432/*
433 * Version allows change of db format w/o temporarily bombing ps's
434 */
435char thisversion[4] = "V2"; /* length must remain 4 */
436
e8807835
RC
437writepsdb(unixname)
438 char *unixname;
439{
e8807835 440 register FILE *fp;
3bc0950e 441 struct lttys *lt;
916caac0 442 struct stat stb;
e8807835 443
963be923 444 setgid(getgid());
e8807835
RC
445 setuid(getuid());
446 if ((fp = fopen(psdb, "w")) == NULL) {
447 perror(psdb);
448 exit(1);
449 } else
450 fchmod(fileno(fp), 0644);
916caac0 451
3baf21ed 452 fwrite(thisversion, sizeof thisversion, 1, fp);
916caac0
KM
453 fwrite(unixname, strlen(unixname) + 1, 1, fp);
454 if (stat(unixname, &stb) < 0)
455 stb.st_mtime = 0;
3baf21ed 456 fwrite((char *) &stb.st_mtime, sizeof stb.st_mtime, 1, fp);
916caac0 457
e8807835
RC
458 fwrite((char *) &nllen, sizeof nllen, 1, fp);
459 fwrite((char *) nl, sizeof (struct nlist), nllen, fp);
3bc0950e 460 fwrite((char *) cand, sizeof (cand), 1, fp);
e8807835 461 fwrite((char *) &nttys, sizeof nttys, 1, fp);
3bc0950e
KM
462 for (lt = lallttys ; lt ; lt = lt->next)
463 fwrite((char *)&lt->ttys, sizeof (struct ttys), 1, fp);
3180e1ce
KM
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);
e8807835
RC
467 fclose(fp);
468}
469
470readpsdb(unixname)
471 char *unixname;
472{
e8807835
RC
473 register i;
474 register FILE *fp;
475 char unamebuf[BUFSIZ];
476 char *p = unamebuf;
916caac0
KM
477 char dbversion[sizeof thisversion];
478 struct stat stb;
479 time_t dbmtime;
e8807835
RC
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
916caac0
KM
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
e8807835 505 fread((char *) &nllen, sizeof nllen, 1, fp);
3180e1ce 506 nl = (struct nlist *) malloc (nllen * sizeof (struct nlist));
e8807835 507 fread((char *) nl, sizeof (struct nlist), nllen, fp);
3bc0950e 508 fread((char *) cand, sizeof (cand), 1, fp);
e8807835 509 fread((char *) &nttys, sizeof nttys, 1, fp);
3bc0950e
KM
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 }
e8807835 515 fread((char *) allttys, sizeof (struct ttys), nttys, fp);
3180e1ce
KM
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);
916caac0
KM
525 fclose(fp);
526 return(1);
527
528bad:
529 fclose(fp);
530 return(0);
e8807835
RC
531}
532
aafc2e2f
BJ
533openfiles(argc, argv)
534 char **argv;
535{
536
25659ede 537 kmemf = "/dev/kmem";
aafc2e2f 538 if (kflg)
25659ede 539 kmemf = argc > 2 ? argv[2] : "/vmcore";
aafc2e2f
BJ
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 {
25659ede 549 memf = "/dev/mem";
aafc2e2f
BJ
550 mem = open(memf, 0);
551 if (mem < 0) {
552 perror(memf);
553 exit(1);
554 }
555 }
25659ede
BJ
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 }
aafc2e2f
BJ
563 }
564}
565
566getkvars(argc, argv)
567 char **argv;
568{
3180e1ce 569 int faildb = 0; /* true if psdatabase init failed */
916caac0 570 int i;
aafc2e2f 571
25659ede 572 nlistf = argc > 1 ? argv[1] : "/vmunix";
e8807835 573 if (Uflg) {
3180e1ce 574 init_nlist();
e8807835 575 nlist(nlistf, nl);
3180e1ce 576 getvchans();
e8807835
RC
577 getdev();
578 writepsdb(nlistf);
579 exit (0);
580 } else if (!readpsdb(nlistf)) {
3180e1ce 581 init_nlist();
e8807835 582 if (!kflg)
3180e1ce
KM
583 nl[X_SYSMAP].n_un.n_name = "";
584 faildb = 1;
e8807835 585 nlist(nlistf, nl);
963be923 586 nttys = 0;
e8807835
RC
587 getdev();
588 }
589
aafc2e2f
BJ
590 if (nl[0].n_type == 0) {
591 fprintf(stderr, "%s: No namelist\n", nlistf);
592 exit(1);
593 }
e8807835
RC
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;
f20270fc 606 addr &= ~KERNBASE;
e8807835
RC
607 (void) lseek(kmem, addr, 0);
608 read(kmem, (char *) Sysmap, Syssize * sizeof (struct pte));
609 }
3180e1ce
KM
610 if (faildb)
611 getvchans();
e8807835
RC
612 usrpt = (struct pte *)nl[X_USRPT].n_value;
613 Usrptmap = (struct pte *)nl[X_USRPTMAP].n_value;
6e515893 614 klseek(kmem, (long)nl[X_NSWAP].n_value, 0);
3d9f6a35 615 if (read(kmem, (char *)&nswap, sizeof (nswap)) != sizeof (nswap)) {
aafc2e2f
BJ
616 cantread("nswap", kmemf);
617 exit(1);
618 }
6e515893 619 klseek(kmem, (long)nl[X_MAXSLP].n_value, 0);
3d9f6a35 620 if (read(kmem, (char *)&maxslp, sizeof (maxslp)) != sizeof (maxslp)) {
c67277e8
BJ
621 cantread("maxslp", kmemf);
622 exit(1);
623 }
6e515893 624 klseek(kmem, (long)nl[X_CCPU].n_value, 0);
3d9f6a35 625 if (read(kmem, (char *)&ccpu, sizeof (ccpu)) != sizeof (ccpu)) {
7f0fa372
BJ
626 cantread("ccpu", kmemf);
627 exit(1);
628 }
6e515893 629 klseek(kmem, (long)nl[X_ECMX].n_value, 0);
3d9f6a35 630 if (read(kmem, (char *)&ecmx, sizeof (ecmx)) != sizeof (ecmx)) {
0f0e0052
BJ
631 cantread("ecmx", kmemf);
632 exit(1);
633 }
634 if (uflg || vflg) {
bdb1f95f 635 ntext = getw(nl[X_NTEXT].n_value);
e8807835
RC
636 text = (struct text *)
637 calloc((unsigned) ntext, sizeof (struct text));
aafc2e2f
BJ
638 if (text == 0) {
639 fprintf(stderr, "no room for text table\n");
640 exit(1);
641 }
bdb1f95f 642 atext = (struct text *)getw(nl[X_TEXT].n_value);
3d9f6a35 643 klseek(kmem, (long)atext, 0);
bdb1f95f
BJ
644 if (read(kmem, (char *)text, ntext * sizeof (struct text))
645 != ntext * sizeof (struct text)) {
aafc2e2f
BJ
646 cantread("text table", kmemf);
647 exit(1);
648 }
649 }
b38b1b3a
SL
650 dmmin = getw(nl[X_DMMIN].n_value);
651 dmmax = getw(nl[X_DMMAX].n_value);
aafc2e2f
BJ
652}
653
3180e1ce
KM
654/*
655 * get the valloc'ed kernel variables for symbolic wait channels
656 */
657getvchans()
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}
aafc2e2f
BJ
691printhdr()
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 }
3180e1ce
KM
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 }
6521d648 710 (void)sprintf(hdr, lhdr, wcwidth, "WCHAN");
3180e1ce
KM
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 }
6521d648 719 (void)sprintf(hdr, uhdr, nflg ? " UID" : "USER ");
3180e1ce
KM
720 } else
721 hdr = shdr;
aafc2e2f 722 if (lflg+vflg+uflg+sflg == 0)
c67277e8 723 hdr += strlen("SSIZ ");
aafc2e2f
BJ
724 cmdstart = strlen(hdr);
725 printf("%s COMMAND\n", hdr);
3d9f6a35 726 (void) fflush(stdout);
aafc2e2f
BJ
727}
728
729cantread(what, fromwhat)
730 char *what, *fromwhat;
731{
732
25659ede 733 fprintf(stderr, "ps: error reading %s from %s\n", what, fromwhat);
aafc2e2f
BJ
734}
735
3d9f6a35 736struct direct *dbuf;
aafc2e2f
BJ
737int dialbase;
738
739getdev()
740{
3d9f6a35 741 register DIR *df;
3bc0950e
KM
742 struct ttys *t;
743 struct lttys *lt;
aafc2e2f 744
e8807835
RC
745 if (chdir("/dev") < 0) {
746 perror("/dev");
747 exit(1);
748 }
aafc2e2f 749 dialbase = -1;
3d9f6a35 750 if ((df = opendir(".")) == NULL) {
aafc2e2f
BJ
751 fprintf(stderr, "Can't open . in /dev\n");
752 exit(1);
753 }
3d9f6a35
KM
754 while ((dbuf = readdir(df)) != NULL)
755 maybetty();
756 closedir(df);
3bc0950e
KM
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;
aafc2e2f
BJ
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 */
772maybetty()
773{
3d9f6a35 774 register char *cp = dbuf->d_name;
3bc0950e
KM
775 static struct lttys *dp;
776 struct lttys *olddp;
aafc2e2f
BJ
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"))
3d9f6a35 792 return;
aafc2e2f
BJ
793 break;
794
795 case 'f':
796 if (!strcmp(cp, "floppy"))
3d9f6a35 797 return;
aafc2e2f
BJ
798 break;
799
800 case 'k':
801 cp++;
802 if (*cp == 'U')
803 cp++;
804 goto trymem;
805
806 case 'r':
807 cp++;
aafc2e2f 808#define is(a,b) cp[0] == 'a' && cp[1] == 'b'
ceb20920
MK
809 if (is(h,p) || is(r,a) || is(u,p) || is(h,k)
810 || is(r,b) || is(m,t)) {
aafc2e2f
BJ
811 cp += 2;
812 if (isdigit(*cp) && cp[2] == 0)
3d9f6a35 813 return;
aafc2e2f
BJ
814 }
815 break;
816
817 case 'm':
818trymem:
819 if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
3d9f6a35 820 return;
3bbec3da 821 if (cp[0] == 'm' && cp[1] == 't')
3d9f6a35 822 return;
aafc2e2f
BJ
823 break;
824
825 case 'n':
826 if (!strcmp(cp, "null"))
3d9f6a35 827 return;
ceb20920
MK
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;
aafc2e2f
BJ
835 break;
836
837 case 'v':
838 if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
839 cp[3] == 0)
3d9f6a35 840 return;
aafc2e2f
BJ
841 break;
842 }
3d9f6a35 843 cp = dbuf->d_name + dbuf->d_namlen - 1;
aafc2e2f
BJ
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 }
3d9f6a35 857 if (cp > dbuf->d_name && isdigit(cp[-1]) && isdigit(*cp))
aafc2e2f
BJ
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;
865donecand:
3bc0950e
KM
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");
e8807835
RC
870 exit(1);
871 }
3bc0950e
KM
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);
e8807835 879 if (Uflg) {
3bc0950e 880 if (stat(dp->ttys.name, &stb) == 0 &&
e8807835 881 (stb.st_mode&S_IFMT)==S_IFCHR)
3bc0950e 882 dp->ttys.ttyd = x = stb.st_rdev;
e8807835
RC
883 else {
884 nttys--;
3bc0950e
KM
885 if (lallttys == dp)
886 lallttys = NULL;
887 free(dp);
888 dp = olddp;
889 if (dp)
890 dp->next = NULL;
e8807835
RC
891 return;
892 }
893 } else
3bc0950e 894 dp->ttys.ttyd = -1;
aafc2e2f
BJ
895 if (x == -1)
896 return;
897 x &= 017;
3bc0950e
KM
898 dp->ttys.cand = cand[x];
899 cand[x] = nttys-1;
aafc2e2f
BJ
900}
901
902char *
903gettty()
904{
905 register char *p;
906 register struct ttys *dp;
907 struct stat stb;
908 int x;
909
910 if (u.u_ttyp == 0)
d0ba9285 911 return(" ?");
aafc2e2f 912 x = u.u_ttyd & 017;
3bc0950e
KM
913 for (dp = &allttys[cand[x]]; dp != &allttys[-1];
914 dp = &allttys[dp->cand]) {
aafc2e2f 915 if (dp->ttyd == -1) {
c67277e8
BJ
916 if (stat(dp->name, &stb) == 0 &&
917 (stb.st_mode&S_IFMT)==S_IFCHR)
aafc2e2f
BJ
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 */
e8807835 926 for (dp = allttys; dp < &allttys[nttys]; dp++) {
aafc2e2f 927 if (dp->ttyd == -1) {
3bbec3da
BJ
928 if (stat(dp->name, &stb) == 0 &&
929 (stb.st_mode&S_IFMT)==S_IFCHR)
aafc2e2f
BJ
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 ("?");
938found:
939 p = dp->name;
940 if (p[0]=='t' && p[1]=='t' && p[2]=='y')
941 p += 3;
942 return (p);
943}
944
945save()
946{
947 register struct savcom *sp;
948 register struct asav *ap;
949 register char *cp;
0f0e0052 950 register struct text *xp;
aafc2e2f
BJ
951 char *ttyp, *cmdp;
952
953 if (mproc->p_stat != SZOMB && getu() == 0)
954 return;
955 ttyp = gettty();
133a0b3b 956 if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
aafc2e2f
BJ
957 return;
958 sp = &savcom[npr];
959 cmdp = getcmd();
960 if (cmdp == 0)
961 return;
e8807835 962 sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
aafc2e2f
BJ
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);
0f0e0052 966 e(a_uid, p_uid); e(a_pid, p_pid); e(a_pri, p_pri);
c67277e8 967 e(a_slptime, p_slptime); e(a_time, p_time);
aafc2e2f
BJ
968 ap->a_tty[0] = ttyp[0];
969 ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
970 if (ap->a_stat == SZOMB) {
b1198826 971 ap->a_cpu = 0;
aafc2e2f
BJ
972 } else {
973 ap->a_size = mproc->p_dsize + mproc->p_ssize;
0f0e0052 974 e(a_rss, p_rssize);
aafc2e2f 975 ap->a_ttyd = u.u_ttyd;
b1198826 976 ap->a_cpu = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
1fb6a666 977 if (sumcpu)
b1198826 978 ap->a_cpu += u.u_cru.ru_utime.tv_sec + u.u_cru.ru_stime.tv_sec;
b2867a35 979 if (mproc->p_textp && text) {
bdb1f95f 980 xp = &text[mproc->p_textp - atext];
0f0e0052
BJ
981 ap->a_tsiz = xp->x_size;
982 ap->a_txtrss = xp->x_rssize;
983 ap->a_xccount = xp->x_ccount;
984 }
aafc2e2f 985 }
0f0e0052 986#undef e
79de1ed3 987 ap->a_maxrss = mproc->p_maxrss;
aafc2e2f
BJ
988 if (lflg) {
989 register struct lsav *lp;
990
e8807835
RC
991 sp->s_un.lp = lp = (struct lsav *)
992 calloc(1, sizeof (struct lsav));
aafc2e2f 993#define e(a,b) lp->a = mproc->b
c67277e8 994 e(l_ppid, p_ppid); e(l_cpu, p_cpu);
aafc2e2f
BJ
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;
aafc2e2f 1001
e8807835
RC
1002 sp->s_un.vp = vp = (struct vsav *)
1003 calloc(1, sizeof (struct vsav));
aafc2e2f 1004#define e(a,b) vp->a = mproc->b
aafc2e2f 1005 if (ap->a_stat != SZOMB) {
7f0fa372 1006 e(v_swrss, p_swrss);
b1198826 1007 vp->v_majflt = u.u_ru.ru_majflt;
0f0e0052 1008 if (mproc->p_textp)
aafc2e2f 1009 vp->v_txtswrss = xp->x_swrss;
aafc2e2f 1010 }
7f0fa372 1011 vp->v_pctcpu = pcpu();
aafc2e2f 1012#undef e
066ec2ef
SL
1013 } else if (uflg)
1014 sp->s_un.u_pctcpu = pcpu();
1015 else if (sflg) {
aafc2e2f
BJ
1016 if (ap->a_stat != SZOMB) {
1017 for (cp = (char *)u.u_stack;
bdb1f95f 1018 cp < &user.upages[UPAGES][0]; )
aafc2e2f
BJ
1019 if (*cp++)
1020 break;
066ec2ef 1021 sp->s_un.s_ssiz = (&user.upages[UPAGES][0] - cp);
aafc2e2f
BJ
1022 }
1023 }
133a0b3b 1024
aafc2e2f
BJ
1025 npr++;
1026}
1027
0f0e0052
BJ
1028double
1029pmem(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
7f0fa372
BJ
1047double
1048pcpu()
1049{
0f0e0052 1050 time_t time;
7f0fa372 1051
0f0e0052
BJ
1052 time = mproc->p_time;
1053 if (time == 0 || (mproc->p_flag&SLOAD) == 0)
7f0fa372 1054 return (0.0);
0f0e0052
BJ
1055 if (rawcpu)
1056 return (100.0 * mproc->p_pctcpu);
1057 return (100.0 * mproc->p_pctcpu / (1.0 - exp(time * log(ccpu))));
7f0fa372
BJ
1058}
1059
aafc2e2f
BJ
1060getu()
1061{
f700a7ee 1062 struct pte *pteaddr, apte;
f700a7ee 1063 struct pte arguutl[UPAGES+CLSIZE];
aafc2e2f
BJ
1064 register int i;
1065 int ncl, size;
1066
1067 size = sflg ? ctob(UPAGES) : sizeof (struct user);
1068 if ((mproc->p_flag & SLOAD) == 0) {
25659ede
BJ
1069 if (swap < 0)
1070 return (0);
066ec2ef 1071 (void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
aafc2e2f
BJ
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 }
e8807835 1081 pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
3d9f6a35 1082 klseek(kmem, (long)pteaddr, 0);
aafc2e2f
BJ
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",
e8807835 1085 mproc->p_pid, kmemf);
aafc2e2f
BJ
1086 return (0);
1087 }
e8807835 1088 lseek(mem,
3d9f6a35
KM
1089 (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
1090 0);
aafc2e2f
BJ
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",
e8807835 1093 mproc->p_pid, memf);
aafc2e2f
BJ
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;
e8807835 1104 lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
aafc2e2f
BJ
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
1114char *
1115getcmd()
1116{
066ec2ef 1117 char cmdbuf[CLSIZE*NBPG];
aafc2e2f
BJ
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;
25659ede 1127 char *file;
aafc2e2f
BJ
1128
1129 if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
1130 return ("");
1131 if (cflg) {
3d9f6a35 1132 (void) strncpy(cmdbuf, u.u_comm, sizeof (u.u_comm));
aafc2e2f
BJ
1133 return (savestr(cmdbuf));
1134 }
1135 if ((mproc->p_flag & SLOAD) == 0 || argaddr == 0) {
25659ede
BJ
1136 if (swap < 0)
1137 goto retucomm;
aafc2e2f 1138 vstodb(0, CLSIZE, &u.u_smap, &db, 1);
066ec2ef 1139 (void) lseek(swap, (long)dtob(db.db_base), 0);
aafc2e2f
BJ
1140 if (read(swap, (char *)&argspac, sizeof(argspac))
1141 != sizeof(argspac))
1142 goto bad;
25659ede 1143 file = swapf;
aafc2e2f 1144 } else {
e8807835 1145 lseek(mem, (long)argaddr, 0);
aafc2e2f
BJ
1146 if (read(mem, (char *)&argspac, sizeof (argspac))
1147 != sizeof (argspac))
1148 goto bad;
25659ede 1149 file = memf;
aafc2e2f
BJ
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;
3d9f6a35 1180 (void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG] - cp);
aafc2e2f 1181 if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
3d9f6a35
KM
1182 (void) strcat(cmdbuf, " (");
1183 (void) strncat(cmdbuf, u.u_comm, sizeof(u.u_comm));
1184 (void) strcat(cmdbuf, ")");
aafc2e2f 1185 }
aafc2e2f
BJ
1186 return (savestr(cmdbuf));
1187
1188bad:
25659ede
BJ
1189 fprintf(stderr, "ps: error locating command name for pid %d from %s\n",
1190 mproc->p_pid, file);
aafc2e2f 1191retucomm:
3d9f6a35
KM
1192 (void) strcpy(cmdbuf, " (");
1193 (void) strncat(cmdbuf, u.u_comm, sizeof (u.u_comm));
1194 (void) strcat(cmdbuf, ")");
aafc2e2f
BJ
1195 return (savestr(cmdbuf));
1196}
1197
1198char *lhdr =
ed325f47 1199" F UID PID PPID CP PRI NI ADDR SZ RSS %*sSTAT TT TIME";
aafc2e2f
BJ
1200lpr(sp)
1201 struct savcom *sp;
1202{
1203 register struct asav *ap = sp->ap;
066ec2ef 1204 register struct lsav *lp = sp->s_un.lp;
aafc2e2f 1205
ed325f47
MK
1206 printf("%6x %4d %5u %5u %2d %3d %2d %4x %5d %4d",
1207 (ap->a_flag &~ SPTECHG), /* XXX */
1208 ap->a_uid, ap->a_pid, lp->l_ppid,
1209 lp->l_cpu > 99 ? 99 : lp->l_cpu, ap->a_pri-PZERO,
1210 ap->a_nice, lp->l_addr, pgtok(ap->a_size), pgtok(ap->a_rss));
3180e1ce
KM
1211 if (lp->l_wchan == 0)
1212 printf(" %*s", wcwidth, "");
1213 else if (nflg)
1c9d8eec 1214 printf(" %*x", wcwidth, (int)lp->l_wchan&~KERNBASE);
3180e1ce
KM
1215 else
1216 printf(" %*.*s", wcwidth, abs(wcwidth), getchan(lp->l_wchan));
d0ba9285 1217 printf(" %-2.3s ", state(ap));
aafc2e2f
BJ
1218 ptty(ap->a_tty);
1219 ptime(ap);
1220}
1221
1222ptty(tp)
1223 char *tp;
1224{
1225
c67277e8 1226 printf("%-2.2s", tp);
aafc2e2f
BJ
1227}
1228
1229ptime(ap)
1230 struct asav *ap;
1231{
1232
d0ba9285 1233 printf(" %3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
aafc2e2f
BJ
1234}
1235
1236char *uhdr =
1c9d8eec 1237"%s PID %%CPU %%MEM SZ RSS TT STAT TIME";
aafc2e2f
BJ
1238upr(sp)
1239 struct savcom *sp;
1240{
1241 register struct asav *ap = sp->ap;
0f0e0052
BJ
1242 int vmsize, rmsize;
1243
066ec2ef
SL
1244 vmsize = pgtok((ap->a_size + ap->a_tsiz));
1245 rmsize = pgtok(ap->a_rss);
0f0e0052 1246 if (ap->a_xccount)
066ec2ef 1247 rmsize += pgtok(ap->a_txtrss/ap->a_xccount);
3180e1ce
KM
1248 if (nflg)
1249 printf("%4d ", ap->a_uid);
1250 else
1251 printf("%-8.8s ", getname(ap->a_uid));
1c9d8eec 1252 printf("%5d %4.1f %4.1f %5d %5d",
3180e1ce 1253 ap->a_pid, sp->s_un.u_pctcpu, pmem(ap), vmsize, rmsize);
c67277e8 1254 putchar(' ');
aafc2e2f 1255 ptty(ap->a_tty);
d0ba9285 1256 printf(" %-2.3s", state(ap));
aafc2e2f
BJ
1257 ptime(ap);
1258}
1259
1260char *vhdr =
1c9d8eec 1261" SIZE PID TT STAT TIME SL RE PAGEIN SIZE RSS LIM TSIZ TRS %CPU %MEM"+5;
aafc2e2f
BJ
1262vpr(sp)
1263 struct savcom *sp;
1264{
066ec2ef 1265 register struct vsav *vp = sp->s_un.vp;
aafc2e2f 1266 register struct asav *ap = sp->ap;
c67277e8 1267
0f0e0052 1268 printf("%5u ", ap->a_pid);
c67277e8 1269 ptty(ap->a_tty);
d0ba9285 1270 printf(" %-2.3s", state(ap));
c67277e8 1271 ptime(ap);
1c9d8eec 1272 printf(" %2d %2d %6d %5d %5d",
79de1ed3
BJ
1273 ap->a_slptime > 99 ? 99 : ap-> a_slptime,
1274 ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
066ec2ef
SL
1275 pgtok(ap->a_size), pgtok(ap->a_rss));
1276 if (ap->a_maxrss == (RLIM_INFINITY/NBPG))
3baf21ed 1277 printf(" xx");
79de1ed3 1278 else
1c9d8eec
MK
1279 printf(" %5d", pgtok(ap->a_maxrss));
1280 printf(" %4d %3d %4.1f %4.1f",
066ec2ef 1281 pgtok(ap->a_tsiz), pgtok(ap->a_txtrss), vp->v_pctcpu, pmem(ap));
c67277e8
BJ
1282}
1283
1284char *shdr =
0f0e0052 1285"SSIZ PID TT STAT TIME";
c67277e8
BJ
1286spr(sp)
1287 struct savcom *sp;
1288{
1289 register struct asav *ap = sp->ap;
1290
1291 if (sflg)
066ec2ef 1292 printf("%4d ", sp->s_un.s_ssiz);
c67277e8
BJ
1293 printf("%5u", ap->a_pid);
1294 putchar(' ');
1295 ptty(ap->a_tty);
d0ba9285 1296 printf(" %-2.3s", state(ap));
c67277e8
BJ
1297 ptime(ap);
1298}
1299
1300char *
1301state(ap)
1302 register struct asav *ap;
1303{
c67277e8 1304 static char res[5];
1c9d8eec 1305 char *cp = res;
aafc2e2f
BJ
1306
1307 switch (ap->a_stat) {
1308
aafc2e2f 1309 case SSTOP:
1c9d8eec 1310 *cp = 'T';
c67277e8
BJ
1311 break;
1312
1313 case SSLEEP:
1314 if (ap->a_pri >= PZERO)
1315 if (ap->a_slptime >= MAXSLP)
1c9d8eec 1316 *cp = 'I';
c67277e8 1317 else
1c9d8eec 1318 *cp = 'S';
aafc2e2f 1319 else if (ap->a_flag & SPAGE)
1c9d8eec 1320 *cp = 'P';
aafc2e2f 1321 else
1c9d8eec 1322 *cp = 'D';
aafc2e2f
BJ
1323 break;
1324
c67277e8 1325 case SWAIT:
aafc2e2f
BJ
1326 case SRUN:
1327 case SIDL:
1c9d8eec 1328 *cp = 'R';
c67277e8
BJ
1329 break;
1330
1331 case SZOMB:
1c9d8eec 1332 *cp = 'Z';
aafc2e2f 1333 break;
c67277e8
BJ
1334
1335 default:
1c9d8eec 1336 *cp = '?';
aafc2e2f 1337 }
1c9d8eec
MK
1338 cp++;
1339 if (ap->a_flag & SLOAD) {
1340 if (ap->a_rss > ap->a_maxrss)
1341 *cp++ = '>';
1342 } else
1343 *cp++ = 'W';
0f0e0052 1344 if (ap->a_nice < NZERO)
1c9d8eec 1345 *cp++ = '<';
0f0e0052 1346 else if (ap->a_nice > NZERO)
1c9d8eec
MK
1347 *cp++ = 'N';
1348 if (ap->a_flag & SUANOM)
1349 *cp++ = 'A';
1350 else if (ap->a_flag & SSEQL)
1351 *cp++ = 'S';
6d66a7a5 1352 *cp = '\0';
c67277e8 1353 return (res);
aafc2e2f
BJ
1354}
1355
1356/*
1357 * Given a base/size pair in virtual swap area,
1358 * return a physical base/size pair which is the
1359 * (largest) initial, physically contiguous block.
1360 */
1361vstodb(vsbase, vssize, dmp, dbp, rev)
1362 register int vsbase;
1363 int vssize;
1364 struct dmap *dmp;
1365 register struct dblock *dbp;
1366{
b38b1b3a 1367 register int blk = dmmin;
aafc2e2f
BJ
1368 register swblk_t *ip = dmp->dm_map;
1369
066ec2ef
SL
1370 vsbase = ctod(vsbase);
1371 vssize = ctod(vssize);
aafc2e2f
BJ
1372 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
1373 panic("vstodb");
1374 while (vsbase >= blk) {
1375 vsbase -= blk;
b38b1b3a 1376 if (blk < dmmax)
aafc2e2f
BJ
1377 blk *= 2;
1378 ip++;
1379 }
1380 if (*ip <= 0 || *ip + blk > nswap)
1381 panic("vstodb *ip");
1382 dbp->db_size = min(vssize, blk - vsbase);
1383 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
1384}
1385
1386/*ARGSUSED*/
1387panic(cp)
1388 char *cp;
1389{
1390
1391#ifdef DEBUG
1392 printf("%s\n", cp);
1393#endif
1394}
1395
1396min(a, b)
1397{
1398
1399 return (a < b ? a : b);
1400}
1401
1402pscomp(s1, s2)
1403 struct savcom *s1, *s2;
1404{
1405 register int i;
1406
066ec2ef
SL
1407 if (uflg)
1408 return (s2->s_un.u_pctcpu > s1->s_un.u_pctcpu ? 1 : -1);
aafc2e2f
BJ
1409 if (vflg)
1410 return (vsize(s2) - vsize(s1));
1411 i = s1->ap->a_ttyd - s2->ap->a_ttyd;
1412 if (i == 0)
1413 i = s1->ap->a_pid - s2->ap->a_pid;
1414 return (i);
1415}
1416
1417vsize(sp)
1418 struct savcom *sp;
1419{
1420 register struct asav *ap = sp->ap;
066ec2ef 1421 register struct vsav *vp = sp->s_un.vp;
aafc2e2f
BJ
1422
1423 if (ap->a_flag & SLOAD)
1424 return (ap->a_rss +
0f0e0052
BJ
1425 ap->a_txtrss / (ap->a_xccount ? ap->a_xccount : 1));
1426 return (vp->v_swrss + (ap->a_xccount ? 0 : vp->v_txtswrss));
aafc2e2f
BJ
1427}
1428
c223880f 1429#include <utmp.h>
aafc2e2f 1430
c223880f
JB
1431struct utmp utmp;
1432#define NMAX (sizeof (utmp.ut_name))
1433#define SCPYN(a, b) strncpy(a, b, NMAX)
60b23435 1434
c223880f
JB
1435#define NUID 64
1436
1437struct ncache {
1438 int uid;
1439 char name[NMAX+1];
1440} nc[NUID];
aafc2e2f 1441
c223880f
JB
1442/*
1443 * This function assumes that the password file is hashed
1444 * (or some such) to allow fast access based on a uid key.
1445 */
aafc2e2f
BJ
1446char *
1447getname(uid)
1448{
c223880f
JB
1449 register struct passwd *pw;
1450 struct passwd *getpwent();
1451 register int cp;
1452 extern int _pw_stayopen;
1453
1454 _pw_stayopen = 1;
1455
1456#if (((NUID) & ((NUID) - 1)) != 0)
1457 cp = uid % (NUID);
1458#else
1459 cp = uid & ((NUID) - 1);
1460#endif
1461 if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
1462 return (nc[cp].name);
1463 pw = getpwuid(uid);
1464 if (!pw)
1465 return (0);
1466 nc[cp].uid = uid;
1467 SCPYN(nc[cp].name, pw->pw_name);
1468 return (nc[cp].name);
aafc2e2f
BJ
1469}
1470
1471char *
1472savestr(cp)
1473 char *cp;
1474{
e8807835 1475 register unsigned len;
aafc2e2f
BJ
1476 register char *dp;
1477
1478 len = strlen(cp);
e8807835 1479 dp = (char *)calloc(len+1, sizeof (char));
3d9f6a35 1480 (void) strcpy(dp, cp);
aafc2e2f
BJ
1481 return (dp);
1482}
e8807835
RC
1483
1484/*
1485 * This routine was stolen from adb to simulate memory management
1486 * on the VAX.
1487 */
1488off_t
1489vtophys(loc)
1490long loc;
1491{
1492 register p;
1493 off_t newloc;
1494
f20270fc 1495 newloc = loc & ~KERNBASE;
e8807835 1496 p = btop(newloc);
f20270fc 1497 if ((loc & KERNBASE) == 0) {
e8807835
RC
1498 fprintf(stderr, "Vtophys: translating non-kernel address\n");
1499 return((off_t) -1);
1500 }
1501 if (p >= Syssize) {
1502 fprintf(stderr, "Vtophys: page out of bound (%d>=%d)\n",
1503 p, Syssize);
1504 return((off_t) -1);
1505 }
1506 if (Sysmap[p].pg_v == 0
1507 && (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
1508 fprintf(stderr, "Vtophys: page not valid\n");
1509 return((off_t) -1);
1510 }
1511 loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
1512 return(loc);
1513}
3180e1ce
KM
1514
1515/*
1516 * since we can't init unions, the cleanest way to use a.out.h instead
1517 * of nlist.h (required since nlist() uses some defines) is to do a
1518 * runtime copy into the nl array -- sigh
1519 */
1520init_nlist()
1521{
1522 register struct nlist *np;
1523 register char **namep;
1524
1525 nllen = sizeof nl_names / sizeof (char *);
1526 np = nl = (struct nlist *) malloc(nllen * sizeof (struct nlist));
1527 if (np == NULL) {
1528 fprintf(stderr, "ps: out of memory allocating namelist\n");
1529 exit(1);
1530 }
1531 namep = &nl_names[0];
1532 while (nllen > 0) {
1533 np->n_un.n_name = *namep;
1534 if (**namep == '\0')
1535 break;
1536 namep++;
1537 np++;
1538 }
1539}
1540
1541/*
1542 * nlist - retreive attributes from name list (string table version)
1543 * modified to add wait channels - Charles R. LaBrec 8/85
1544 */
1545nlist(name, list)
1546 char *name;
1547 struct nlist *list;
1548{
1549 register struct nlist *p, *q;
1550 register char *s1, *s2;
1551 register n, m;
1552 int maxlen, nreq;
1553 FILE *f;
1554 FILE *sf;
1555 off_t sa; /* symbol address */
1556 off_t ss; /* start of strings */
1557 int type;
1558 struct exec buf;
1559 struct nlist space[BUFSIZ/sizeof (struct nlist)];
1560 char nambuf[BUFSIZ];
1561
1562 maxlen = 0;
1563 for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0]; q++, nreq++) {
1564 q->n_type = 0;
1565 q->n_value = 0;
1566 q->n_desc = 0;
1567 q->n_other = 0;
1568 n = strlen(q->n_un.n_name);
1569 if (n > maxlen)
1570 maxlen = n;
1571 }
1572 f = fopen(name, "r");
1573 if (f == NULL)
1574 return (-1);
1575 fread((char *)&buf, sizeof buf, 1, f);
1576 if (N_BADMAG(buf)) {
1577 fclose(f);
1578 return (-1);
1579 }
1580 sf = fopen(name, "r");
1581 if (sf == NULL) {
1582 /* ??? */
1583 fclose(f);
1584 return(-1);
1585 }
1586 sa = N_SYMOFF(buf);
1587 ss = sa + buf.a_syms;
1588 n = buf.a_syms;
1589 fseek(f, sa, 0);
1590 while (n) {
1591 m = sizeof (space);
1592 if (n < m)
1593 m = n;
1594 if (fread((char *)space, m, 1, f) != 1)
1595 break;
1596 n -= m;
1597 for (q = space; (m -= sizeof(struct nlist)) >= 0; q++) {
1598 if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
1599 continue;
1600 /*
1601 * since we know what type of symbols we will get,
1602 * we can make a quick check here -- crl
1603 */
1604 type = q->n_type & (N_TYPE | N_EXT);
1605 if ((q->n_type & N_TYPE) != N_ABS
1606 && type != (N_EXT | N_DATA)
1607 && type != (N_EXT | N_BSS))
1608 continue;
1609 fseek(sf, ss+q->n_un.n_strx, 0);
1610 fread(nambuf, maxlen+1, 1, sf);
1611 /* if using wchans, add it to the list of channels */
1612 if (!nflg)
1613 addchan(&nambuf[1], (caddr_t) q->n_value);
1614 for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
1615 s1 = p->n_un.n_name;
1616 s2 = nambuf;
1617 if (strcmp(p->n_un.n_name, nambuf) == 0) {
1618 p->n_value = q->n_value;
1619 p->n_type = q->n_type;
1620 p->n_desc = q->n_desc;
1621 p->n_other = q->n_other;
1622 --nreq;
1623 break;
1624 }
1625 }
1626 }
1627 }
1628alldone:
1629 fclose(f);
1630 fclose(sf);
1631 return (nreq);
1632}
1633
1634/*
1635 * add the given channel to the channel list
1636 */
1637addchan(name, caddr)
1638char *name;
1639caddr_t caddr;
1640{
1641 static int left = 0;
1642 register struct wchan *wp;
1643 register char **p;
1644
1645 for (p = wchan_stop_list; *p; p++) {
1646 if (**p != *name) /* quick check first */
1647 continue;
1648 if (strncmp(name, *p, WNAMESIZ) == 0)
1649 return; /* if found, don't add */
1650 }
1651 if (left == 0) {
1652 if (wchanhd) {
1653 left = 100;
1654 wchanhd = (struct wchan *) realloc(wchanhd,
1655 (nchans + left) * sizeof (struct wchan));
1656 } else {
1657 left = 600;
1658 wchanhd = (struct wchan *) malloc(left
1659 * sizeof (struct wchan));
1660 }
1661 if (wchanhd == NULL) {
1662 fprintf(stderr, "ps: out of memory allocating wait channels\n");
1663 nflg++;
1664 return;
1665 }
1666 }
1667 left--;
1668 wp = &wchanhd[nchans++];
1669 strncpy(wp->wc_name, name, WNAMESIZ);
1670 wp->wc_name[WNAMESIZ] = '\0';
1671 wp->wc_caddr = caddr;
1672}
1673
1674/*
1675 * returns the symbolic wait channel corresponding to chan
1676 */
1677char *
1678getchan(chan)
1679register caddr_t chan;
1680{
1681 register i, iend;
1682 register char *prevsym;
1683 register struct wchan *wp;
1684
1685 prevsym = "???"; /* nothing, to begin with */
1686 if (chan) {
1687 for (i = 0; i < NWCINDEX; i++)
1688 if ((unsigned) chan < (unsigned) wchan_index[i])
1689 break;
1690 iend = i--;
1691 if (i < 0) /* can't be found */
1692 return prevsym;
1693 iend *= nchans;
1694 iend /= NWCINDEX;
1695 i *= nchans;
1696 i /= NWCINDEX;
1697 wp = &wchanhd[i];
1698 for ( ; i < iend; i++, wp++) {
1699 if ((unsigned) wp->wc_caddr > (unsigned) chan)
1700 break;
1701 prevsym = wp->wc_name;
1702 }
1703 }
1704 return prevsym;
1705}
1706
1707/*
1708 * used in sorting the wait channel array
1709 */
1710int
1711wchancomp (w1, w2)
1712struct wchan *w1, *w2;
1713{
1714 register unsigned c1, c2;
1715
1716 c1 = (unsigned) w1->wc_caddr;
1717 c2 = (unsigned) w2->wc_caddr;
1718 if (c1 > c2)
1719 return 1;
1720 else if (c1 == c2)
1721 return 0;
1722 else
1723 return -1;
1724}