sprintf returns an int, now
[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
f20270fc 14static char sccsid[] = "@(#)ps.c 5.10 (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;
c67277e8 126 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)
aafc2e2f 395 printf(" <defunct>");
963be923
MK
396 else if (sp->ap->a_flag & SWEXIT)
397 printf(" <exiting>");
aafc2e2f
BJ
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
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 }
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;
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)
911 return("?");
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 =
3180e1ce 1199" F UID PID PPID CP PRI NI ADDR SZ RSS %*s STAT 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
066ec2ef 1206 printf("%7x%4d%6u%6u%3d%4d%3d%5x%4d%5d",
c67277e8
BJ
1207 ap->a_flag, ap->a_uid,
1208 ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
066ec2ef 1209 ap->a_nice-NZERO, lp->l_addr, pgtok(ap->a_size), pgtok(ap->a_rss));
3180e1ce
KM
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));
0f0e0052 1216 printf(" %4.4s ", state(ap));
aafc2e2f
BJ
1217 ptty(ap->a_tty);
1218 ptime(ap);
1219}
1220
1221ptty(tp)
1222 char *tp;
1223{
1224
c67277e8 1225 printf("%-2.2s", tp);
aafc2e2f
BJ
1226}
1227
1228ptime(ap)
1229 struct asav *ap;
1230{
1231
b1198826 1232 printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
aafc2e2f
BJ
1233}
1234
1235char *uhdr =
3180e1ce 1236"%s PID %%CPU %%MEM SZ RSS TT STAT TIME";
aafc2e2f
BJ
1237upr(sp)
1238 struct savcom *sp;
1239{
1240 register struct asav *ap = sp->ap;
0f0e0052
BJ
1241 int vmsize, rmsize;
1242
066ec2ef
SL
1243 vmsize = pgtok((ap->a_size + ap->a_tsiz));
1244 rmsize = pgtok(ap->a_rss);
0f0e0052 1245 if (ap->a_xccount)
066ec2ef 1246 rmsize += pgtok(ap->a_txtrss/ap->a_xccount);
3180e1ce
KM
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);
c67277e8 1253 putchar(' ');
aafc2e2f 1254 ptty(ap->a_tty);
0f0e0052 1255 printf(" %4.4s", state(ap));
aafc2e2f
BJ
1256 ptime(ap);
1257}
1258
1259char *vhdr =
3baf21ed 1260" SIZE PID TT STAT TIME SL RE PAGEIN SIZE RSS LIM TSIZ TRS %CPU %MEM"+5;
aafc2e2f
BJ
1261vpr(sp)
1262 struct savcom *sp;
1263{
066ec2ef 1264 register struct vsav *vp = sp->s_un.vp;
aafc2e2f 1265 register struct asav *ap = sp->ap;
c67277e8 1266
0f0e0052 1267 printf("%5u ", ap->a_pid);
c67277e8 1268 ptty(ap->a_tty);
0f0e0052 1269 printf(" %4.4s", state(ap));
c67277e8 1270 ptime(ap);
79de1ed3
BJ
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,
066ec2ef
SL
1274 pgtok(ap->a_size), pgtok(ap->a_rss));
1275 if (ap->a_maxrss == (RLIM_INFINITY/NBPG))
3baf21ed 1276 printf(" xx");
79de1ed3 1277 else
3baf21ed 1278 printf("%6d", pgtok(ap->a_maxrss));
79de1ed3 1279 printf("%5d%4d%5.1f%5.1f",
066ec2ef 1280 pgtok(ap->a_tsiz), pgtok(ap->a_txtrss), vp->v_pctcpu, pmem(ap));
c67277e8
BJ
1281}
1282
1283char *shdr =
0f0e0052 1284"SSIZ PID TT STAT TIME";
c67277e8
BJ
1285spr(sp)
1286 struct savcom *sp;
1287{
1288 register struct asav *ap = sp->ap;
1289
1290 if (sflg)
066ec2ef 1291 printf("%4d ", sp->s_un.s_ssiz);
c67277e8
BJ
1292 printf("%5u", ap->a_pid);
1293 putchar(' ');
1294 ptty(ap->a_tty);
0f0e0052 1295 printf(" %4.4s", state(ap));
c67277e8
BJ
1296 ptime(ap);
1297}
1298
1299char *
1300state(ap)
1301 register struct asav *ap;
1302{
1303 char stat, load, nice, anom;
1304 static char res[5];
aafc2e2f
BJ
1305
1306 switch (ap->a_stat) {
1307
aafc2e2f 1308 case SSTOP:
c67277e8
BJ
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';
aafc2e2f
BJ
1318 else if (ap->a_flag & SPAGE)
1319 stat = 'P';
1320 else
1321 stat = 'D';
1322 break;
1323
c67277e8 1324 case SWAIT:
aafc2e2f
BJ
1325 case SRUN:
1326 case SIDL:
c67277e8
BJ
1327 stat = 'R';
1328 break;
1329
1330 case SZOMB:
1331 stat = 'Z';
aafc2e2f 1332 break;
c67277e8
BJ
1333
1334 default:
1335 stat = '?';
aafc2e2f 1336 }
79de1ed3 1337 load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
0f0e0052
BJ
1338 if (ap->a_nice < NZERO)
1339 nice = '<';
1340 else if (ap->a_nice > NZERO)
1341 nice = 'N';
1342 else
1343 nice = ' ';
8fb17030 1344 anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
c67277e8
BJ
1345 res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
1346 return (res);
aafc2e2f
BJ
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 */
1354vstodb(vsbase, vssize, dmp, dbp, rev)
1355 register int vsbase;
1356 int vssize;
1357 struct dmap *dmp;
1358 register struct dblock *dbp;
1359{
b38b1b3a 1360 register int blk = dmmin;
aafc2e2f
BJ
1361 register swblk_t *ip = dmp->dm_map;
1362
066ec2ef
SL
1363 vsbase = ctod(vsbase);
1364 vssize = ctod(vssize);
aafc2e2f
BJ
1365 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
1366 panic("vstodb");
1367 while (vsbase >= blk) {
1368 vsbase -= blk;
b38b1b3a 1369 if (blk < dmmax)
aafc2e2f
BJ
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*/
1380panic(cp)
1381 char *cp;
1382{
1383
1384#ifdef DEBUG
1385 printf("%s\n", cp);
1386#endif
1387}
1388
1389min(a, b)
1390{
1391
1392 return (a < b ? a : b);
1393}
1394
1395pscomp(s1, s2)
1396 struct savcom *s1, *s2;
1397{
1398 register int i;
1399
066ec2ef
SL
1400 if (uflg)
1401 return (s2->s_un.u_pctcpu > s1->s_un.u_pctcpu ? 1 : -1);
aafc2e2f
BJ
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
1410vsize(sp)
1411 struct savcom *sp;
1412{
1413 register struct asav *ap = sp->ap;
066ec2ef 1414 register struct vsav *vp = sp->s_un.vp;
aafc2e2f
BJ
1415
1416 if (ap->a_flag & SLOAD)
1417 return (ap->a_rss +
0f0e0052
BJ
1418 ap->a_txtrss / (ap->a_xccount ? ap->a_xccount : 1));
1419 return (vp->v_swrss + (ap->a_xccount ? 0 : vp->v_txtswrss));
aafc2e2f
BJ
1420}
1421
c223880f 1422#include <utmp.h>
aafc2e2f 1423
c223880f
JB
1424struct utmp utmp;
1425#define NMAX (sizeof (utmp.ut_name))
1426#define SCPYN(a, b) strncpy(a, b, NMAX)
60b23435 1427
c223880f
JB
1428#define NUID 64
1429
1430struct ncache {
1431 int uid;
1432 char name[NMAX+1];
1433} nc[NUID];
aafc2e2f 1434
c223880f
JB
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 */
aafc2e2f
BJ
1439char *
1440getname(uid)
1441{
c223880f
JB
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);
aafc2e2f
BJ
1462}
1463
1464char *
1465savestr(cp)
1466 char *cp;
1467{
e8807835 1468 register unsigned len;
aafc2e2f
BJ
1469 register char *dp;
1470
1471 len = strlen(cp);
e8807835 1472 dp = (char *)calloc(len+1, sizeof (char));
3d9f6a35 1473 (void) strcpy(dp, cp);
aafc2e2f
BJ
1474 return (dp);
1475}
e8807835
RC
1476
1477/*
1478 * This routine was stolen from adb to simulate memory management
1479 * on the VAX.
1480 */
1481off_t
1482vtophys(loc)
1483long loc;
1484{
1485 register p;
1486 off_t newloc;
1487
f20270fc 1488 newloc = loc & ~KERNBASE;
e8807835 1489 p = btop(newloc);
f20270fc 1490 if ((loc & KERNBASE) == 0) {
e8807835
RC
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}
3180e1ce
KM
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 */
1513init_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 */
1538nlist(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 }
1621alldone:
1622 fclose(f);
1623 fclose(sf);
1624 return (nreq);
1625}
1626
1627/*
1628 * add the given channel to the channel list
1629 */
1630addchan(name, caddr)
1631char *name;
1632caddr_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 */
1670char *
1671getchan(chan)
1672register 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 */
1703int
1704wchancomp (w1, w2)
1705struct 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}