xref: /original-bsd/bin/ps/ps.c (revision f0fd5f8a)
1 #ifndef lint
2 static	char *sccsid = "@(#)ps.c	4.19 (Berkeley) 11/14/82";
3 #endif
4 
5 /*
6  * ps
7  */
8 
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <nlist.h>
12 #include <pwd.h>
13 #include <sys/param.h>
14 #include <sys/tty.h>
15 #include <dir.h>
16 #include <sys/user.h>
17 #include <sys/proc.h>
18 #include <sys/pte.h>
19 #include <sys/vm.h>
20 #include <sys/text.h>
21 #include <sys/stat.h>
22 #include <math.h>
23 #include <sys/vlimit.h>
24 
25 struct nlist nl[] = {
26 	{ "_proc" },
27 #define	X_PROC		0
28 	{ "_Usrptmap" },
29 #define	X_USRPTMA	1
30 	{ "_usrpt" },
31 #define	X_USRPT		2
32 	{ "_text" },
33 #define	X_TEXT		3
34 	{ "_nswap" },
35 #define	X_NSWAP		4
36 	{ "_maxslp" },
37 #define	X_MAXSLP	5
38 	{ "_ccpu" },
39 #define	X_CCPU		6
40 	{ "_ecmx" },
41 #define	X_ECMX		7
42 	{ "_nproc" },
43 #define	X_NPROC		8
44 	{ "_ntext" },
45 #define	X_NTEXT		9
46 	{ 0 },
47 };
48 
49 struct	savcom {
50 	union {
51 		struct	lsav *lp;
52 		float	u_pctcpu;
53 		struct	vsav *vp;
54 		int	s_ssiz;
55 		struct	sssav *ssp;
56 	} sun;
57 	struct	asav *ap;
58 } *savcom;
59 
60 struct	asav {
61 	char	*a_cmdp;
62 	int	a_flag;
63 	short	a_stat, a_uid, a_pid, a_nice, a_pri, a_slptime, a_time;
64 	size_t	a_size, a_rss, a_tsiz, a_txtrss;
65 	short	a_xccount;
66 	char	a_tty[MAXNAMLEN+1];
67 	dev_t	a_ttyd;
68 	time_t	a_cpu;
69 	size_t	a_maxrss;
70 };
71 
72 char	*lhdr;
73 struct	lsav {
74 	short	l_ppid;
75 	char	l_cpu;
76 	int	l_addr;
77 	caddr_t	l_wchan;
78 };
79 
80 char	*sshdr;
81 struct	sssav {
82 	short 	ss_ppid;
83 	short	ss_brother;
84 	short	ss_sons;
85 };
86 
87 char	*uhdr;
88 char	*shdr;
89 
90 char	*vhdr;
91 struct	vsav {
92 	u_int	v_majflt;
93 	size_t	v_swrss, v_txtswrss;
94 	float	v_pctcpu;
95 };
96 
97 struct	proc proc[8];		/* 8 = a few, for less syscalls */
98 struct	proc *mproc;
99 struct	text *text;
100 
101 union {
102 	struct	user user;
103 	char	upages[UPAGES][NBPG];
104 } user;
105 #define u	user.user
106 
107 #define clear(x) 	((int)x & 0x7fffffff)
108 
109 int	chkpid;
110 int	aflg, cflg, eflg, gflg, kflg, lflg, sflg, ssflg,
111 	nonssflg, uflg, vflg, xflg;
112 char	*tptr;
113 char	*gettty(), *getcmd(), *getname(), *savestr(), *alloc(), *state();
114 char	*rindex(), *calloc(), *sbrk(), *strcpy(), *strcat(), *strncat();
115 long	lseek();
116 double	pcpu(), pmem();
117 int	pscomp();
118 int	nswap, maxslp;
119 struct	text *atext;
120 double	ccpu;
121 int	ecmx;
122 struct	pte *Usrptma, *usrpt;
123 int	nproc, ntext, hz;
124 
125 struct	ttys {
126 	char	name[MAXNAMLEN+1];
127 	dev_t	ttyd;
128 	struct	ttys *next;
129 	struct	ttys *cand;
130 } *allttys, *cand[16];
131 
132 int	npr;
133 
134 int	cmdstart;
135 int	twidth;
136 char	*kmemf, *memf, *swapf, *nlistf;
137 int	kmem, mem, swap = -1;
138 int	rawcpu, sumcpu;
139 
140 int	pcbpf;
141 int	argaddr;
142 extern	char _sobuf[];
143 
144 main(argc, argv)
145 	char **argv;
146 {
147 	register int i, j;
148 	register char *ap;
149 	int uid;
150 	off_t procp;
151 
152 	twidth = 80;
153 	if (ap = rindex(argv[0], '/'))
154 		ap++;
155 	else
156 		ap = argv[0];
157 	if (*ap == 's')				/* If name starts with 's' */
158 		ssflg++;
159 
160 	argc--, argv++;
161 	if (argc > 0) {
162 		ap = argv[0];
163 		while (*ap) switch (*ap++) {
164 
165 		case 'C':
166 			rawcpu++; nonssflg++;
167 			break;
168 		case 'S':
169 			sumcpu++;
170 			break;
171 		case 'a':
172 			aflg++;
173 			break;
174 		case 'c':
175 			cflg = !cflg; nonssflg++;
176 			break;
177 		case 'e':
178 			eflg++; nonssflg++;
179 			break;
180 		case 'g':
181 			gflg++; nonssflg++;
182 			break;
183 		case 'k':
184 			kflg++; nonssflg++;
185 			break;
186 		case 'l':
187 			lflg++; nonssflg++;
188 			break;
189 		case 's':
190 			sflg++; nonssflg++;
191 			break;
192 		case 't':
193 			if (*ap)
194 				tptr = ap;
195 			aflg++; nonssflg++;
196 			gflg++;
197 			if (*tptr == '?')
198 				xflg++;
199 			while (*ap)
200 				ap++;
201 			break;
202 		case 'u':
203 			uflg++; nonssflg++;
204 			break;
205 		case 'v':
206 			cflg = 1;
207 			vflg++; nonssflg++;
208 			break;
209 		case 'w':
210 			if (twidth == 80)
211 				twidth = 132;
212 			else
213 				twidth = BUFSIZ;
214 			break;
215 		case 'x':
216 			xflg++;
217 			break;
218 		case 'y':		/* Rand 2/81 */
219 			ssflg++;
220 			break;
221 		default:
222 			if (!isdigit(ap[-1]))
223 				break;
224 			chkpid = atoi(--ap);
225 			*ap = 0;
226 			aflg++;	nonssflg++;
227 			xflg++;
228 			break;
229 		}
230 	}
231 	if (ssflg) {
232 		if (nonssflg) {
233 			fprintf (stderr, "Usage: ss [axwS]\n");
234 			exit(1);
235 		}
236 		uflg++;
237 		gflg++;
238 	}
239 	openfiles(argc, argv);
240 	getkvars(argc, argv);
241 	if (chdir("/dev") < 0) {
242 		perror("/dev");
243 		exit(1);
244 	}
245 	getdev();
246 	uid = getuid();
247 	printhdr();
248 	procp = getw(nl[X_PROC].n_value);
249 	nproc = getw(nl[X_NPROC].n_value);
250 	savcom = (struct savcom *)calloc(nproc, sizeof (*savcom));
251 	for (i=0; i<nproc; i += 8) {
252 		klseek(kmem, (long)procp, 0);
253 		j = nproc - i;
254 		if (j > 8)
255 			j = 8;
256 		j *= sizeof (struct proc);
257 		if (read(kmem, (char *)proc, j) != j) {
258 			cantread("proc table", kmemf);
259 			exit(1);
260 		}
261 		procp += j;
262 		for (j = j / sizeof (struct proc) - 1; j >= 0; j--) {
263 			mproc = &proc[j];
264 			if (mproc->p_stat == 0 ||
265 			    mproc->p_pgrp == 0 && xflg == 0)
266 				continue;
267 			if (tptr == 0 && gflg == 0 && xflg == 0 &&
268 			    mproc->p_ppid == 1)
269 				continue;
270 			if (uid != mproc->p_uid && aflg==0 ||
271 			    chkpid != 0 && chkpid != mproc->p_pid)
272 				continue;
273 			if (vflg && gflg == 0 && xflg == 0) {
274 				if (mproc->p_stat == SZOMB ||
275 				    mproc->p_flag&SWEXIT)
276 					continue;
277 				if (mproc->p_slptime > MAXSLP &&
278 				    (mproc->p_stat == SSLEEP ||
279 				     mproc->p_stat == SSTOP))
280 				continue;
281 			}
282 			save();
283 		}
284 	}
285 	qsort(savcom, npr, sizeof(savcom[0]), pscomp);
286 	if (ssflg) {
287 		walk(npr);
288 		exit (npr == 0);
289 	}
290 	for (i=0; i<npr; i++) {
291 		register struct savcom *sp = &savcom[i];
292 		if (lflg)
293 			lpr(sp);
294 		else if (vflg)
295 			vpr(sp);
296 		else if (uflg)
297 			upr(sp);
298 		else
299 			spr(sp);
300 		if (sp->ap->a_flag & SWEXIT)
301 			printf(" <exiting>");
302 		else if (sp->ap->a_stat == SZOMB)
303 			printf(" <defunct>");
304 		else if (sp->ap->a_pid == 0)
305 			printf(" swapper");
306 		else if (sp->ap->a_pid == 2)
307 			printf(" pagedaemon");
308 		else if (sp->ap->a_pid == 3 && sp->ap->a_flag & SSYS)
309 			printf(" ip input");
310 		else
311 			printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
312 		printf("\n");
313 	}
314 	exit(npr == 0);
315 }
316 
317 getw(loc)
318 	unsigned long loc;
319 {
320 	long word;
321 
322 	klseek(kmem, (long)loc, 0);
323 	if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
324 		printf("error reading kmem at %x\n", loc);
325 	return (word);
326 }
327 
328 klseek(fd, loc, off)
329 	int fd;
330 	long loc;
331 	int off;
332 {
333 
334 	if (kflg)
335 		loc &= 0x7fffffff;
336 	(void) lseek(fd, (long)loc, off);
337 }
338 
339 openfiles(argc, argv)
340 	char **argv;
341 {
342 
343 	kmemf = "/dev/kmem";
344 	if (kflg)
345 		kmemf = argc > 2 ? argv[2] : "/vmcore";
346 	kmem = open(kmemf, 0);
347 	if (kmem < 0) {
348 		perror(kmemf);
349 		exit(1);
350 	}
351 	if (kflg)  {
352 		mem = kmem;
353 		memf = kmemf;
354 	} else {
355 		memf = "/dev/mem";
356 		mem = open(memf, 0);
357 		if (mem < 0) {
358 			perror(memf);
359 			exit(1);
360 		}
361 	}
362 	if (kflg == 0 || argc > 3) {
363 		swapf = argc>3 ? argv[3]: "/dev/drum";
364 		swap = open(swapf, 0);
365 		if (swap < 0) {
366 			perror(swapf);
367 			exit(1);
368 		}
369 	}
370 }
371 
372 getkvars(argc, argv)
373 	char **argv;
374 {
375 	register struct nlist *nlp;
376 
377 	nlistf = argc > 1 ? argv[1] : "/vmunix";
378 	nlist(nlistf, nl);
379 	if (nl[0].n_type == 0) {
380 		fprintf(stderr, "%s: No namelist\n", nlistf);
381 		exit(1);
382 	}
383 	if (kflg)
384 		for (nlp = nl; nlp < &nl[sizeof (nl)/sizeof (nl[0])]; nlp++)
385 			nlp->n_value = clear(nlp->n_value);
386 	usrpt = (struct pte *)nl[X_USRPT].n_value;	/* don't clear!! */
387 	Usrptma = (struct pte *)nl[X_USRPTMA].n_value;
388 	klseek(kmem, (long)nl[X_NSWAP].n_value, 0);
389 	if (read(kmem, (char *)&nswap, sizeof (nswap)) != sizeof (nswap)) {
390 		cantread("nswap", kmemf);
391 		exit(1);
392 	}
393 	klseek(kmem, (long)nl[X_MAXSLP].n_value, 0);
394 	if (read(kmem, (char *)&maxslp, sizeof (maxslp)) != sizeof (maxslp)) {
395 		cantread("maxslp", kmemf);
396 		exit(1);
397 	}
398 	klseek(kmem, (long)nl[X_CCPU].n_value, 0);
399 	if (read(kmem, (char *)&ccpu, sizeof (ccpu)) != sizeof (ccpu)) {
400 		cantread("ccpu", kmemf);
401 		exit(1);
402 	}
403 	klseek(kmem, (long)nl[X_ECMX].n_value, 0);
404 	if (read(kmem, (char *)&ecmx, sizeof (ecmx)) != sizeof (ecmx)) {
405 		cantread("ecmx", kmemf);
406 		exit(1);
407 	}
408 	if (uflg || vflg) {
409 		ntext = getw(nl[X_NTEXT].n_value);
410 		text = (struct text *)alloc(ntext * sizeof (struct text));
411 		if (text == 0) {
412 			fprintf(stderr, "no room for text table\n");
413 			exit(1);
414 		}
415 		atext = (struct text *)getw(nl[X_TEXT].n_value);
416 		klseek(kmem, (long)atext, 0);
417 		if (read(kmem, (char *)text, ntext * sizeof (struct text))
418 		    != ntext * sizeof (struct text)) {
419 			cantread("text table", kmemf);
420 			exit(1);
421 		}
422 	}
423 }
424 
425 printhdr()
426 {
427 	char *hdr;
428 
429 	if (sflg+lflg+vflg+uflg > 1) {
430 		fprintf(stderr, "ps: specify only one of s,l,v and u\n");
431 		exit(1);
432 	}
433 	hdr = ssflg ? sshdr :
434 		(lflg ? lhdr :
435 			(vflg ? vhdr :
436 				(uflg ? uhdr : shdr)));
437 	if (lflg+vflg+uflg+sflg == 0)
438 		hdr += strlen("SSIZ ");
439 	cmdstart = strlen(hdr);
440 	printf("%s COMMAND\n", hdr);
441 	(void) fflush(stdout);
442 }
443 
444 cantread(what, fromwhat)
445 	char *what, *fromwhat;
446 {
447 
448 	fprintf(stderr, "ps: error reading %s from %s\n", what, fromwhat);
449 }
450 
451 struct	direct *dbuf;
452 int	dialbase;
453 
454 getdev()
455 {
456 	register DIR *df;
457 
458 	dialbase = -1;
459 	if ((df = opendir(".")) == NULL) {
460 		fprintf(stderr, "Can't open . in /dev\n");
461 		exit(1);
462 	}
463 	while ((dbuf = readdir(df)) != NULL)
464 		maybetty();
465 	closedir(df);
466 }
467 
468 /*
469  * Attempt to avoid stats by guessing minor device
470  * numbers from tty names.  Console is known,
471  * know that r(hp|up|mt) are unlikely as are different mem's,
472  * floppy, null, tty, etc.
473  */
474 maybetty()
475 {
476 	register char *cp = dbuf->d_name;
477 	register struct ttys *dp;
478 	int x;
479 	struct stat stb;
480 
481 	switch (cp[0]) {
482 
483 	case 'c':
484 		if (!strcmp(cp, "console")) {
485 			x = 0;
486 			goto donecand;
487 		}
488 		/* cu[la]? are possible!?! don't rule them out */
489 		break;
490 
491 	case 'd':
492 		if (!strcmp(cp, "drum"))
493 			return;
494 		break;
495 
496 	case 'f':
497 		if (!strcmp(cp, "floppy"))
498 			return;
499 		break;
500 
501 	case 'k':
502 		cp++;
503 		if (*cp == 'U')
504 			cp++;
505 		goto trymem;
506 
507 	case 'r':
508 		cp++;
509 		if (*cp == 'r' || *cp == 'u' || *cp == 'h')
510 			cp++;
511 #define is(a,b) cp[0] == 'a' && cp[1] == 'b'
512 		if (is(r,p) || is(u,p) || is(r,k) || is(r,m) || is(m,t)) {
513 			cp += 2;
514 			if (isdigit(*cp) && cp[2] == 0)
515 				return;
516 		}
517 		break;
518 
519 	case 'm':
520 trymem:
521 		if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
522 			return;
523 		if (cp[0] == 'm' && cp[1] == 't')
524 			return;
525 		break;
526 
527 	case 'n':
528 		if (!strcmp(cp, "null"))
529 			return;
530 		break;
531 
532 	case 'v':
533 		if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
534 		    cp[3] == 0)
535 			return;
536 		break;
537 	}
538 	cp = dbuf->d_name + dbuf->d_namlen - 1;
539 	x = 0;
540 	if (cp[-1] == 'd') {
541 		if (dialbase == -1) {
542 			if (stat("ttyd0", &stb) == 0)
543 				dialbase = stb.st_rdev & 017;
544 			else
545 				dialbase = -2;
546 		}
547 		if (dialbase == -2)
548 			x = 0;
549 		else
550 			x = 11;
551 	}
552 	if (cp > dbuf->d_name && isdigit(cp[-1]) && isdigit(*cp))
553 		x += 10 * (cp[-1] - ' ') + cp[0] - '0';
554 	else if (*cp >= 'a' && *cp <= 'f')
555 		x += 10 + *cp - 'a';
556 	else if (isdigit(*cp))
557 		x += *cp - '0';
558 	else
559 		x = -1;
560 donecand:
561 	dp = (struct ttys *)alloc(sizeof (struct ttys));
562 	(void) strcpy(dp->name, dbuf->d_name);
563 	dp->next = allttys;
564 	dp->ttyd = -1;
565 	allttys = dp;
566 	if (x == -1)
567 		return;
568 	x &= 017;
569 	dp->cand = cand[x];
570 	cand[x] = dp;
571 }
572 
573 char *
574 gettty()
575 {
576 	register char *p;
577 	register struct ttys *dp;
578 	struct stat stb;
579 	int x;
580 
581 	if (u.u_ttyp == 0)
582 		return("?");
583 	x = u.u_ttyd & 017;
584 	for (dp = cand[x]; dp; dp = dp->cand) {
585 		if (dp->ttyd == -1) {
586 			if (stat(dp->name, &stb) == 0 &&
587 			   (stb.st_mode&S_IFMT)==S_IFCHR)
588 				dp->ttyd = stb.st_rdev;
589 			else
590 				dp->ttyd = -2;
591 		}
592 		if (dp->ttyd == u.u_ttyd)
593 			goto found;
594 	}
595 	/* ick */
596 	for (dp = allttys; dp; dp = dp->next) {
597 		if (dp->ttyd == -1) {
598 			if (stat(dp->name, &stb) == 0 &&
599 			   (stb.st_mode&S_IFMT)==S_IFCHR)
600 				dp->ttyd = stb.st_rdev;
601 			else
602 				dp->ttyd = -2;
603 		}
604 		if (dp->ttyd == u.u_ttyd)
605 			goto found;
606 	}
607 	return ("?");
608 found:
609 	p = dp->name;
610 	if (p[0]=='t' && p[1]=='t' && p[2]=='y')
611 		p += 3;
612 	return (p);
613 }
614 
615 save()
616 {
617 	register struct savcom *sp;
618 	register struct asav *ap;
619 	register char *cp;
620 	register struct text *xp;
621 	char *ttyp, *cmdp;
622 
623 	if (mproc->p_stat != SZOMB && getu() == 0)
624 		return;
625 	ttyp = gettty();
626 	if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
627 		return;
628 	sp = &savcom[npr];
629 	cmdp = getcmd();
630 	if (cmdp == 0)
631 		return;
632 	sp->ap = ap = (struct asav *)alloc(sizeof (struct asav));
633 	sp->ap->a_cmdp = cmdp;
634 #define e(a,b) ap->a = mproc->b
635 	e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
636 	e(a_uid, p_uid); e(a_pid, p_pid); e(a_pri, p_pri);
637 	e(a_slptime, p_slptime); e(a_time, p_time);
638 	ap->a_tty[0] = ttyp[0];
639 	ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
640 	if (ap->a_stat == SZOMB) {
641 		register struct xproc *xp = (struct xproc *)mproc;
642 
643 		ap->a_cpu = 0;
644 	} else {
645 		ap->a_size = mproc->p_dsize + mproc->p_ssize;
646 		e(a_rss, p_rssize);
647 		ap->a_ttyd = u.u_ttyd;
648 		ap->a_cpu = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
649 		if (sumcpu)
650 			ap->a_cpu += u.u_cru.ru_utime.tv_sec + u.u_cru.ru_stime.tv_sec;
651 		if (mproc->p_textp && text) {
652 			xp = &text[mproc->p_textp - atext];
653 			ap->a_tsiz = xp->x_size;
654 			ap->a_txtrss = xp->x_rssize;
655 			ap->a_xccount = xp->x_ccount;
656 		}
657 	}
658 #undef e
659 	ap->a_maxrss = mproc->p_maxrss;
660 	if (lflg) {
661 		register struct lsav *lp;
662 
663 		sp->sun.lp = lp = (struct lsav *)alloc(sizeof (struct lsav));
664 #define e(a,b) lp->a = mproc->b
665 		e(l_ppid, p_ppid); e(l_cpu, p_cpu);
666 		if (ap->a_stat != SZOMB)
667 			e(l_wchan, p_wchan);
668 #undef e
669 		lp->l_addr = pcbpf;
670 	} else if (vflg) {
671 		register struct vsav *vp;
672 
673 		sp->sun.vp = vp = (struct vsav *)alloc(sizeof (struct vsav));
674 #define e(a,b) vp->a = mproc->b
675 		if (ap->a_stat != SZOMB) {
676 			e(v_swrss, p_swrss);
677 			vp->v_majflt = u.u_ru.ru_majflt;
678 			if (mproc->p_textp)
679 				vp->v_txtswrss = xp->x_swrss;
680 		}
681 		vp->v_pctcpu = pcpu();
682 #undef e
683 	} else if (uflg) {
684 		if (!ssflg)
685 			sp->sun.u_pctcpu = pcpu();
686 		else {
687 			register struct sssav *ssp;
688 
689 			sp->sun.ssp =ssp= (struct sssav *)alloc(sizeof (struct sssav));
690 			ssp->ss_ppid = mproc->p_ppid;
691 		}
692 	} else if (sflg) {
693 		if (ap->a_stat != SZOMB) {
694 			for (cp = (char *)u.u_stack;
695 			    cp < &user.upages[UPAGES][0]; )
696 				if (*cp++)
697 					break;
698 			sp->sun.s_ssiz = (&user.upages[UPAGES][0] - cp);
699 		}
700 	}
701 
702 	npr++;
703 }
704 
705 double
706 pmem(ap)
707 	register struct asav *ap;
708 {
709 	double fracmem;
710 	int szptudot;
711 
712 	if ((ap->a_flag&SLOAD) == 0)
713 		fracmem = 0.0;
714 	else {
715 		szptudot = UPAGES + clrnd(ctopt(ap->a_size+ap->a_tsiz));
716 		fracmem = ((float)ap->a_rss+szptudot)/CLSIZE/ecmx;
717 		if (ap->a_xccount)
718 			fracmem += ((float)ap->a_txtrss)/CLSIZE/
719 			    ap->a_xccount/ecmx;
720 	}
721 	return (100.0 * fracmem);
722 }
723 
724 double
725 pcpu()
726 {
727 	time_t time;
728 
729 	time = mproc->p_time;
730 	if (time == 0 || (mproc->p_flag&SLOAD) == 0)
731 		return (0.0);
732 	if (rawcpu)
733 		return (100.0 * mproc->p_pctcpu);
734 	return (100.0 * mproc->p_pctcpu / (1.0 - exp(time * log(ccpu))));
735 }
736 
737 getu()
738 {
739 	struct pte *pteaddr, apte;
740 	struct pte arguutl[UPAGES+CLSIZE];
741 	register int i;
742 	int ncl, size;
743 
744 	size = sflg ? ctob(UPAGES) : sizeof (struct user);
745 	if ((mproc->p_flag & SLOAD) == 0) {
746 		if (swap < 0)
747 			return (0);
748 		(void) lseek(swap, (long)ctob(mproc->p_swaddr), 0);
749 		if (read(swap, (char *)&user.user, size) != size) {
750 			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
751 			    mproc->p_pid, swapf);
752 			return (0);
753 		}
754 		pcbpf = 0;
755 		argaddr = 0;
756 		return (1);
757 	}
758 	if (kflg)
759 		mproc->p_p0br = (struct pte *)clear(mproc->p_p0br);
760 	pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
761 	klseek(kmem, (long)pteaddr, 0);
762 	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
763 		printf("ps: cant read indir pte to get u for pid %d from %s\n",
764 		    mproc->p_pid, swapf);
765 		return (0);
766 	}
767 	klseek(mem,
768 	    (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
769 		0);
770 	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
771 		printf("ps: cant read page table for u of pid %d from %s\n",
772 		    mproc->p_pid, kmemf);
773 		return (0);
774 	}
775 	if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
776 		argaddr = ctob(arguutl[0].pg_pfnum);
777 	else
778 		argaddr = 0;
779 	pcbpf = arguutl[CLSIZE].pg_pfnum;
780 	ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
781 	while (--ncl >= 0) {
782 		i = ncl * CLSIZE;
783 		klseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
784 		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
785 			printf("ps: cant read page %d of u of pid %d from %s\n",
786 			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
787 			return(0);
788 		}
789 	}
790 	return (1);
791 }
792 
793 char *
794 getcmd()
795 {
796 	char cmdbuf[BUFSIZ];
797 	union {
798 		char	argc[CLSIZE*NBPG];
799 		int	argi[CLSIZE*NBPG/sizeof (int)];
800 	} argspac;
801 	register char *cp;
802 	register int *ip;
803 	char c;
804 	int nbad;
805 	struct dblock db;
806 	char *file;
807 
808 	if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
809 		return ("");
810 	if (cflg) {
811 		(void) strncpy(cmdbuf, u.u_comm, sizeof (u.u_comm));
812 		return (savestr(cmdbuf));
813 	}
814 	if ((mproc->p_flag & SLOAD) == 0 || argaddr == 0) {
815 		if (swap < 0)
816 			goto retucomm;
817 		vstodb(0, CLSIZE, &u.u_smap, &db, 1);
818 		(void) lseek(swap, (long)ctob(db.db_base), 0);
819 		if (read(swap, (char *)&argspac, sizeof(argspac))
820 		    != sizeof(argspac))
821 			goto bad;
822 		file = swapf;
823 	} else {
824 		klseek(mem, (long)argaddr, 0);
825 		if (read(mem, (char *)&argspac, sizeof (argspac))
826 		    != sizeof (argspac))
827 			goto bad;
828 		file = memf;
829 	}
830 	ip = &argspac.argi[CLSIZE*NBPG/sizeof (int)];
831 	ip -= 2;		/* last arg word and .long 0 */
832 	while (*--ip)
833 		if (ip == argspac.argi)
834 			goto retucomm;
835 	*(char *)ip = ' ';
836 	ip++;
837 	nbad = 0;
838 	for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG]; cp++) {
839 		c = *cp & 0177;
840 		if (c == 0)
841 			*cp = ' ';
842 		else if (c < ' ' || c > 0176) {
843 			if (++nbad >= 5*(eflg+1)) {
844 				*cp++ = ' ';
845 				break;
846 			}
847 			*cp = '?';
848 		} else if (eflg == 0 && c == '=') {
849 			while (*--cp != ' ')
850 				if (cp <= (char *)ip)
851 					break;
852 			break;
853 		}
854 	}
855 	*cp = 0;
856 	while (*--cp == ' ')
857 		*cp = 0;
858 	cp = (char *)ip;
859 	(void) strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG] - cp);
860 	if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
861 		(void) strcat(cmdbuf, " (");
862 		(void) strncat(cmdbuf, u.u_comm, sizeof(u.u_comm));
863 		(void) strcat(cmdbuf, ")");
864 	}
865 /*
866 	if (xflg == 0 && gflg == 0 && tptr == 0 && cp[0] == '-')
867 		return (0);
868 */
869 	return (savestr(cmdbuf));
870 
871 bad:
872 	fprintf(stderr, "ps: error locating command name for pid %d from %s\n",
873 	    mproc->p_pid, file);
874 retucomm:
875 	(void) strcpy(cmdbuf, " (");
876 	(void) strncat(cmdbuf, u.u_comm, sizeof (u.u_comm));
877 	(void) strcat(cmdbuf, ")");
878 	return (savestr(cmdbuf));
879 }
880 
881 char	*lhdr =
882 "     F UID   PID  PPID CP PRI NI ADDR  SZ  RSS WCHAN STAT TT  TIME";
883 lpr(sp)
884 	struct savcom *sp;
885 {
886 	register struct asav *ap = sp->ap;
887 	register struct lsav *lp = sp->sun.lp;
888 
889 	printf("%6x%4d%6u%6u%3d%4d%3d%5x%4d%5d",
890 	    ap->a_flag, ap->a_uid,
891 	    ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
892 	    ap->a_nice-NZERO, lp->l_addr, ap->a_size/2, ap->a_rss/2);
893 	printf(lp->l_wchan ? " %5x" : "      ", (int)lp->l_wchan&0xfffff);
894 	printf(" %4.4s ", state(ap));
895 	ptty(ap->a_tty);
896 	ptime(ap);
897 }
898 
899 ptty(tp)
900 	char *tp;
901 {
902 
903 	printf("%-2.2s", tp);
904 }
905 
906 ptime(ap)
907 	struct asav *ap;
908 {
909 
910 	printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
911 }
912 
913 char	*uhdr =
914 "USER       PID %CPU %MEM   SZ  RSS TT STAT  TIME";
915 upr(sp)
916 	struct savcom *sp;
917 {
918 	register struct asav *ap = sp->ap;
919 	int vmsize, rmsize;
920 
921 	vmsize = (ap->a_size + ap->a_tsiz)/2;
922 	rmsize = ap->a_rss/2;
923 	if (ap->a_xccount)
924 		rmsize += ap->a_txtrss/ap->a_xccount/2;
925 	printf("%-8.8s %5d%5.1f%5.1f%5d%5d",
926 	    getname(ap->a_uid), ap->a_pid, sp->sun.u_pctcpu, pmem(ap),
927 	    vmsize, rmsize);
928 	putchar(' ');
929 	ptty(ap->a_tty);
930 	printf(" %4.4s", state(ap));
931 	ptime(ap);
932 }
933 
934 char *vhdr =
935 "  PID TT STAT  TIME SL RE PAGEIN SIZE  RSS  LIM TSIZ TRS %CPU %MEM";
936 vpr(sp)
937 	struct savcom *sp;
938 {
939 	register struct vsav *vp = sp->sun.vp;
940 	register struct asav *ap = sp->ap;
941 
942 	printf("%5u ", ap->a_pid);
943 	ptty(ap->a_tty);
944 	printf(" %4.4s", state(ap));
945 	ptime(ap);
946 	printf("%3d%3d%7d%5d%5d",
947 	   ap->a_slptime > 99 ? 99 : ap-> a_slptime,
948 	   ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
949 	   ap->a_size/2, ap->a_rss/2);
950 	if (ap->a_maxrss == (INFINITY/NBPG))
951 		printf("   xx");
952 	else
953 		printf("%5d", ap->a_maxrss/2);
954 	printf("%5d%4d%5.1f%5.1f",
955 	   ap->a_tsiz/2, ap->a_txtrss/2, vp->v_pctcpu, pmem(ap));
956 }
957 
958 char	*shdr =
959 "SSIZ   PID TT STAT  TIME";
960 spr(sp)
961 	struct savcom *sp;
962 {
963 	register struct asav *ap = sp->ap;
964 
965 	if (sflg)
966 		printf("%4d ", sp->sun.s_ssiz);
967 	printf("%5u", ap->a_pid);
968 	putchar(' ');
969 	ptty(ap->a_tty);
970 	printf(" %4.4s", state(ap));
971 	ptime(ap);
972 }
973 
974 char *
975 state(ap)
976 	register struct asav *ap;
977 {
978 	char stat, load, nice, anom;
979 	static char res[5];
980 
981 	switch (ap->a_stat) {
982 
983 	case SSTOP:
984 		stat = 'T';
985 		break;
986 
987 	case SSLEEP:
988 		if (ap->a_pri >= PZERO)
989 			if (ap->a_slptime >= MAXSLP)
990 				stat = 'I';
991 			else
992 				stat = 'S';
993 		else if (ap->a_flag & SPAGE)
994 			stat = 'P';
995 		else
996 			stat = 'D';
997 		break;
998 
999 	case SWAIT:
1000 	case SRUN:
1001 	case SIDL:
1002 		stat = 'R';
1003 		break;
1004 
1005 	case SZOMB:
1006 		stat = 'Z';
1007 		break;
1008 
1009 	default:
1010 		stat = '?';
1011 	}
1012 	load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
1013 	if (ap->a_nice < NZERO)
1014 		nice = '<';
1015 	else if (ap->a_nice > NZERO)
1016 		nice = 'N';
1017 	else
1018 		nice = ' ';
1019 	anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
1020 	res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
1021 	return (res);
1022 }
1023 
1024 /*
1025  * Given a base/size pair in virtual swap area,
1026  * return a physical base/size pair which is the
1027  * (largest) initial, physically contiguous block.
1028  */
1029 vstodb(vsbase, vssize, dmp, dbp, rev)
1030 	register int vsbase;
1031 	int vssize;
1032 	struct dmap *dmp;
1033 	register struct dblock *dbp;
1034 {
1035 	register int blk = DMMIN;
1036 	register swblk_t *ip = dmp->dm_map;
1037 
1038 	if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
1039 		panic("vstodb");
1040 	while (vsbase >= blk) {
1041 		vsbase -= blk;
1042 		if (blk < DMMAX)
1043 			blk *= 2;
1044 		ip++;
1045 	}
1046 	if (*ip <= 0 || *ip + blk > nswap)
1047 		panic("vstodb *ip");
1048 	dbp->db_size = min(vssize, blk - vsbase);
1049 	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
1050 }
1051 
1052 /*ARGSUSED*/
1053 panic(cp)
1054 	char *cp;
1055 {
1056 
1057 #ifdef DEBUG
1058 	printf("%s\n", cp);
1059 #endif
1060 }
1061 
1062 min(a, b)
1063 {
1064 
1065 	return (a < b ? a : b);
1066 }
1067 
1068 pscomp(s1, s2)
1069 	struct savcom *s1, *s2;
1070 {
1071 	register int i;
1072 
1073 	if (uflg && !ssflg)
1074 		return (s2->sun.u_pctcpu > s1->sun.u_pctcpu ? 1 : -1);
1075 	if (vflg)
1076 		return (vsize(s2) - vsize(s1));
1077 	i = s1->ap->a_ttyd - s2->ap->a_ttyd;
1078 	if (i == 0)
1079 		i = s1->ap->a_pid - s2->ap->a_pid;
1080 	return (i);
1081 }
1082 
1083 vsize(sp)
1084 	struct savcom *sp;
1085 {
1086 	register struct asav *ap = sp->ap;
1087 	register struct vsav *vp = sp->sun.vp;
1088 
1089 	if (ap->a_flag & SLOAD)
1090 		return (ap->a_rss +
1091 		    ap->a_txtrss / (ap->a_xccount ? ap->a_xccount : 1));
1092 	return (vp->v_swrss + (ap->a_xccount ? 0 : vp->v_txtswrss));
1093 }
1094 
1095 #define	NMAX	8
1096 #define	NUID	2048
1097 
1098 char	names[NUID][NMAX+1];
1099 
1100 /*
1101  * Stolen from ls...
1102  */
1103 char *
1104 getname(uid)
1105 {
1106 	register struct passwd *pw;
1107 	static init;
1108 	struct passwd *getpwent();
1109 
1110 	if (uid >= 0 && uid < NUID && names[uid][0])
1111 		return (&names[uid][0]);
1112 	if (init == 2)
1113 		return (0);
1114 	if (init == 0)
1115 		setpwent(), init = 1;
1116 	while (pw = getpwent()) {
1117 		if (pw->pw_uid >= NUID)
1118 			continue;
1119 		if (names[pw->pw_uid][0])
1120 			continue;
1121 		(void) strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
1122 		if (pw->pw_uid == uid)
1123 			return (&names[uid][0]);
1124 	}
1125 	init = 2;
1126 	endpwent();
1127 	return (0);
1128 }
1129 
1130 char	*freebase;
1131 int	nleft;
1132 
1133 char *
1134 alloc(size)
1135 	int size;
1136 {
1137 	register char *cp;
1138 	register int i;
1139 
1140 	if (size > nleft) {
1141 		freebase = (char *)sbrk((int)(i = size > 2048 ? size : 2048));
1142 		if (freebase == 0) {
1143 			fprintf(stderr, "ps: ran out of memory\n");
1144 			exit(1);
1145 		}
1146 		nleft = i - size;
1147 	} else
1148 		nleft -= size;
1149 	cp = freebase;
1150 	for (i = size; --i >= 0; )
1151 		*cp++ = 0;
1152 	freebase = cp;
1153 	return (cp - size);
1154 }
1155 
1156 char *
1157 savestr(cp)
1158 	char *cp;
1159 {
1160 	register int len;
1161 	register char *dp;
1162 
1163 	len = strlen(cp);
1164 	dp = (char *)alloc(len+1);
1165 	(void) strcpy(dp, cp);
1166 	return (dp);
1167 }
1168 
1169 walk(np)
1170 	int np;
1171 {
1172 	register int i, j, k, l, m;
1173 #undef afl
1174 #undef sfl
1175 #define afl(i,f) savcom[i].ap -> f
1176 #define sfl(i,f) savcom[i].sun.ssp -> f
1177 
1178 	for(i = 0; i < np; i = j) {
1179 		for(j = i; afl(j,a_ttyd) == afl(i,a_ttyd); j++) {
1180 			sfl(j,ss_brother) = -1;
1181 			sfl(j,ss_sons) = -1;
1182 		}
1183 		for(k = i+1; k < j; k++) {
1184 			if(sfl(k,ss_ppid) == sfl(i,ss_ppid)) {
1185 				for(l=i; sfl(l,ss_brother) != -1;
1186 					l=sfl(l,ss_brother)) ;
1187 				sfl(l,ss_brother) = k;
1188 				goto next;
1189 			}
1190 			for(l = i; l < j; l++) {
1191 				if(l == k) continue;
1192 				if(sfl(k,ss_ppid) == afl(l,a_pid)) {
1193 					if(sfl(l,ss_sons) == -1)
1194 					    sfl(l,ss_sons) = k;
1195 					else {
1196 					    for(m = sfl(l,ss_sons);
1197 						sfl(m,ss_brother) != -1;
1198 						m = sfl(m,ss_brother)) ;
1199 					    sfl(m,ss_brother) = k;
1200 					}
1201 					goto next;
1202 				}
1203 			}
1204 			for(l = i; l < j; l++) {
1205 				if(l == k) continue;
1206 				if(sfl(k,ss_ppid) == sfl(l,ss_ppid)) {
1207 					for(m = k; sfl(m,ss_brother) != -1;
1208 					    m = sfl(m,ss_brother)) ;
1209 					sfl(m,ss_brother) = l;
1210 				}
1211 			}
1212 		next: ;
1213 		}
1214 		walk1(i, 0);
1215 	}
1216 }
1217 
1218 walk1(pno, depth)
1219 	int pno, depth;
1220 {
1221 	if(pno == -1)
1222 		return;
1223 /***    printf("%5d, %d\n",outargs[pno].o_pid, depth);  ***/
1224 	walkpr(&savcom[pno], depth);
1225 	walk1(sfl(pno,ss_sons), depth+1);
1226 	walk1(sfl(pno,ss_brother), depth);
1227 }
1228 
1229 char *sshdr =
1230 "TTY User     SZ RSS  CPU  S      PID  ";
1231 
1232 walkpr(a, depth)
1233 	register struct savcom *a;
1234 	int depth;
1235 {
1236 
1237 	if(!depth) {
1238 		printf("%-2.2s", a->ap->a_tty);
1239 		printf(" %-8.8s", getname(a->ap->a_uid));
1240 	} else
1241 		printf("   %-8s", &".......*"[8-(depth<=8?depth:8)]);
1242 	printf("%4d%4d", a->ap->a_size/2, a->ap->a_rss/2);
1243 	ptime(a->ap);
1244 	/* Once there was a "CCPU" field here.  Subsumed by -S now. */
1245 	printf(" %4.4s", state(a->ap));
1246 	printf("%6u ", a->ap->a_pid);
1247 	if (a->ap->a_pid == 0)
1248 		printf(" swapper");
1249 	else if (a->ap->a_pid == 2)
1250 		printf(" pagedaemon");
1251 	else
1252 		printf(" %.*s", twidth - cmdstart - 2, a->ap->a_cmdp);
1253 	putchar('\n');
1254 }
1255