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