xref: /original-bsd/bin/ps/ps.c (revision d25e1985)
1 static char *sccsid = "@(#)ps.c	4.1 (Berkeley) 10/01/80";
2 /*
3  * ps; VAX 4BSD version
4  */
5 
6 #include <stdio.h>
7 #include <ctype.h>
8 #include <nlist.h>
9 #include <pwd.h>
10 #include <sys/param.h>
11 #include <sys/tty.h>
12 #include <sys/dir.h>
13 #include <sys/user.h>
14 #include <sys/proc.h>
15 #include <sys/pte.h>
16 #include <sys/vm.h>
17 #include <sys/text.h>
18 #include <sys/stat.h>
19 
20 struct nlist nl[] = {
21 	{ "_proc" },
22 #define	X_PROC		0
23 	{ "_Usrptmap" },
24 #define	X_USRPTMA	1
25 	{ "_usrpt" },
26 #define	X_USRPT		2
27 	{ "_text" },
28 #define	X_TEXT		3
29 	{ "_nswap" },
30 #define	X_NSWAP		4
31 	{ 0 },
32 };
33 
34 struct	savcom {
35 	union {
36 		struct	lsav *lp;
37 		float	u_pctcpu;
38 		struct	vsav *vp;
39 		int	s_ssiz;
40 	} sun;
41 	struct	asav *ap;
42 } savcom[NPROC];
43 
44 struct	asav {
45 	char	*a_cmdp;
46 	int	a_flag;
47 	short	a_stat, a_uid, a_pid, a_nice;
48 	size_t	a_size, a_rss;
49 	char	a_tty[DIRSIZ+1];
50 	dev_t	a_ttyd;
51 	time_t	a_time;
52 };
53 
54 char	*lhdr;
55 /*	    F S UID   PID  PPID CP PRI NICE ADDR  SZ  RSS WCHAN TTY TIME */
56 struct	lsav {
57 	short	l_ppid;
58 	char	l_cpu, l_pri;
59 	int	l_addr;
60 	caddr_t	l_wchan;
61 };
62 
63 char	*uhdr;
64 /*	 USER       PID %CPU NICE  SZ  RSS TTY TIME */
65 
66 char	*shdr;
67 /*	 SSIZ   PID TTY TIME */
68 
69 char	*vhdr;
70 /*	F     PID TTY  TIME TIM SL  MINFLT  MAJFLT SIZE  RSS  SRS TSIZ TRS PF*/
71 struct	vsav {
72 	short	v_slptime, v_pri;
73 	u_int	v_minflt, v_majflt;
74 	size_t	v_swrss, v_tsiz, v_txtrss, v_txtswrss;
75 	short	v_xccount;
76 	short	v_aveflt;
77 };
78 
79 struct	proc proc[8];		/* 8 = a few, for less syscalls */
80 struct	proc *mproc;
81 struct	text *text;
82 
83 union {
84 	struct	user user;
85 	char	upages[UPAGES][NBPG];
86 } user;
87 #define u	user.user
88 
89 #define clear(x) 	((int)x & 0x7fffffff)
90 
91 int	chkpid;
92 int	aflg, cflg, eflg, gflg, kflg, lflg, sflg, uflg, vflg, xflg;
93 char	*tptr;
94 char	*gettty(), *getcmd(), *getname(), *savestr(), *alloc();
95 int	pscomp();
96 int	nswap;
97 struct	pte *Usrptma, *usrpt;
98 
99 struct	ttys {
100 	char	name[DIRSIZ+1];
101 	dev_t	ttyd;
102 	struct	ttys *next;
103 	struct	ttys *cand;
104 } *allttys, *cand[16];
105 
106 struct	savcom savcom[NPROC];
107 int	npr;
108 
109 int	cmdstart;
110 int	twidth;
111 char	*kmemf, *memf, *swapf, *nlistf;
112 int	kmem, mem, swap;
113 
114 int	pcbpf;
115 int	argaddr;
116 extern	char _sobuf[];
117 
118 main(argc, argv)
119 	char **argv;
120 {
121 	register int i, j;
122 	register char *ap;
123 	int uid;
124 	off_t procp;
125 
126 	if (chdir("/dev") < 0) {
127 		perror("/dev");
128 		exit(1);
129 	}
130 	twidth = 80;
131 	setbuf(stdout, _sobuf);
132 	argc--, argv++;
133 	if (argc > 0) {
134 		ap = argv[0];
135 		while (*ap) switch (*ap++) {
136 
137 		case 'a':
138 			aflg++;
139 			break;
140 		case 'c':
141 			cflg = !cflg;
142 			break;
143 		case 'e':
144 			eflg++;
145 			break;
146 		case 'g':
147 			gflg++;
148 			break;
149 		case 'k':
150 			kflg++;
151 			break;
152 		case 'l':
153 			lflg++;
154 			break;
155 		case 's':
156 			sflg++;
157 			break;
158 		case 't':
159 			if (*ap)
160 				tptr = ap;
161 			aflg++;
162 			gflg++;
163 			if (*tptr == '?')
164 				xflg++;
165 			while (*ap)
166 				ap++;
167 			break;
168 		case 'u':
169 			uflg++;
170 			break;
171 		case 'v':
172 			cflg = 1;
173 			vflg++;
174 			break;
175 		case 'w':
176 			if (twidth == 80)
177 				twidth = 132;
178 			else
179 				twidth = BUFSIZ;
180 			break;
181 		case 'x':
182 			xflg++;
183 			break;
184 		default:
185 			if (!isdigit(ap[-1]))
186 				break;
187 			chkpid = atoi(--ap);
188 			*ap = 0;
189 			aflg++;
190 			xflg++;
191 			break;
192 		}
193 	}
194 	openfiles(argc, argv);
195 	getkvars(argc, argv);
196 	getdev();
197 	uid = getuid();
198 	printhdr();
199 	procp = nl[X_PROC].n_value;
200 	for (i=0; i<NPROC; i += 8) {
201 		lseek(kmem, (char *)procp, 0);
202 		j = NPROC - i;
203 		if (j > 8)
204 			j = 8;
205 		j *= sizeof (struct proc);
206 		if (read(kmem, (char *)proc, j) != j)
207 			cantread("proc table", kmemf);
208 		procp += j;
209 		for (j = j / sizeof (struct proc) - 1; j >= 0; j--) {
210 			mproc = &proc[j];
211 			if (mproc->p_stat == 0 ||
212 			    mproc->p_pgrp == 0 && xflg == 0)
213 			continue;
214 			if (tptr == 0 && gflg == 0 && xflg == 0 &&
215 			    mproc->p_ppid == 1 && (mproc->p_flag&SDETACH) == 0)
216 				continue;
217 			if (uid != mproc->p_uid && aflg==0 ||
218 			    chkpid != 0 && chkpid != mproc->p_pid)
219 				continue;
220 			if (vflg && gflg == 0 && xflg == 0) {
221 				if (mproc->p_stat == SZOMB ||
222 				    mproc->p_flag&SWEXIT)
223 					continue;
224 				if (mproc->p_slptime > MAXSLP &&
225 				    (mproc->p_stat == SSLEEP ||
226 				     mproc->p_stat == SSTOP))
227 				continue;
228 			}
229 			save();
230 		}
231 	}
232 	qsort(savcom, npr, sizeof(savcom[0]), pscomp);
233 	for (i=0; i<npr; i++) {
234 		register struct savcom *sp = &savcom[i];
235 		if (lflg)
236 			lpr(sp);
237 		else if (vflg)
238 			vpr(sp);
239 		else if (uflg)
240 			upr(sp);
241 		else
242 			spr(sp);
243 		if (sp->ap->a_flag & SWEXIT)
244 			printf(" <exiting>");
245 		else if (sp->ap->a_stat == SZOMB)
246 			printf(" <defunct>");
247 		else if (sp->ap->a_pid == 0)
248 			printf(" swapper");
249 		else if (sp->ap->a_pid == 2)
250 			printf(" pagedaemon");
251 		else
252 			printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
253 		printf("\n");
254 	}
255 	exit(npr == 0);
256 }
257 
258 openfiles(argc, argv)
259 	char **argv;
260 {
261 
262 	kmemf = "kmem";
263 	if (kflg)
264 		kmemf = argc > 1 ? argv[1] : "/vmcore";
265 	kmem = open(kmemf, 0);
266 	if (kmem < 0) {
267 		perror(kmemf);
268 		exit(1);
269 	}
270 	if (kflg)  {
271 		mem = kmem;
272 		memf = kmemf;
273 	} else {
274 		memf = "mem";
275 		mem = open(memf, 0);
276 		if (mem < 0) {
277 			perror(memf);
278 			exit(1);
279 		}
280 	}
281 	swapf = argc>2 ? argv[2]: "drum";
282 	swap = open(swapf, 0);
283 	if (swap < 0) {
284 		perror(swapf);
285 		exit(1);
286 	}
287 }
288 
289 getkvars(argc, argv)
290 	char **argv;
291 {
292 	register struct nlist *nlp;
293 
294 	nlistf = argc > 3 ? argv[3] : "/vmunix";
295 	nlist(nlistf, nl);
296 	if (nl[0].n_type == 0) {
297 		fprintf(stderr, "%s: No namelist\n", nlistf);
298 		exit(1);
299 	}
300 	if (kflg)
301 		for (nlp = nl; nlp < &nl[sizeof (nl)/sizeof (nl[0])]; nlp++)
302 			nlp->n_value = clear(nlp->n_value);
303 	Usrptma = (struct pte *)nl[X_USRPTMA].n_value;
304 	usrpt = (struct pte *)nl[X_USRPT].n_value;
305 	lseek(kmem, (long)nl[X_NSWAP].n_value, 0);
306 	if (read(kmem, &nswap, sizeof (nswap)) != sizeof (nswap)) {
307 		cantread("nswap", kmemf);
308 		exit(1);
309 	}
310 	if (vflg) {
311 		text = (struct text *)alloc(NTEXT * sizeof (struct text));
312 		if (text == 0) {
313 			fprintf(stderr, "no room for text table\n");
314 			exit(1);
315 		}
316 		lseek(kmem, (long)nl[X_TEXT].n_value, 0);
317 		if (read(kmem, (char *)text, NTEXT * sizeof (struct text))
318 		    != NTEXT * sizeof (struct text)) {
319 			cantread("text table", kmemf);
320 			exit(1);
321 		}
322 	}
323 }
324 
325 printhdr()
326 {
327 	char *hdr;
328 
329 	if (sflg+lflg+vflg+uflg > 1) {
330 		fprintf(stderr, "ps: specify only one of s,l,v and u\n");
331 		exit(1);
332 	}
333 	hdr = lflg ? lhdr : (vflg ? vhdr : (uflg ? uhdr : shdr));
334 	if (lflg+vflg+uflg+sflg == 0)
335 		hdr += strlen(" SSIZ");
336 	cmdstart = strlen(hdr);
337 	printf("%s COMMAND\n", hdr);
338 	fflush(stdout);
339 }
340 
341 cantread(what, fromwhat)
342 	char *what, *fromwhat;
343 {
344 
345 	fprintf(stderr, "ps: error reading %s from %s", what, fromwhat);
346 }
347 
348 struct	direct dbuf;
349 int	dialbase;
350 
351 getdev()
352 {
353 	register FILE *df;
354 	register struct ttys *dp;
355 
356 	dialbase = -1;
357 	if ((df = fopen(".", "r")) == NULL) {
358 		fprintf(stderr, "Can't open . in /dev\n");
359 		exit(1);
360 	}
361 	while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
362 		if (dbuf.d_ino == 0)
363 			continue;
364 		maybetty(dp);
365 	}
366 	fclose(df);
367 }
368 
369 /*
370  * Attempt to avoid stats by guessing minor device
371  * numbers from tty names.  Console is known,
372  * know that r(hp|up|mt) are unlikely as are different mem's,
373  * floppy, null, tty, etc.
374  */
375 maybetty()
376 {
377 	register char *cp = dbuf.d_name;
378 	register struct ttys *dp;
379 	int x;
380 	struct stat stb;
381 
382 	switch (cp[0]) {
383 
384 	case 'c':
385 		if (!strcmp(cp, "console")) {
386 			x = 0;
387 			goto donecand;
388 		}
389 		/* cu[la]? are possible!?! don't rule them out */
390 		break;
391 
392 	case 'd':
393 		if (!strcmp(cp, "drum"))
394 			return (0);
395 		break;
396 
397 	case 'f':
398 		if (!strcmp(cp, "floppy"))
399 			return (0);
400 		break;
401 
402 	case 'k':
403 		cp++;
404 		if (*cp == 'U')
405 			cp++;
406 		goto trymem;
407 
408 	case 'r':
409 		cp++;
410 		if (*cp == 'r' || *cp == 'u' || *cp == 'h')
411 			cp++;
412 #define is(a,b) cp[0] == 'a' && cp[1] == 'b'
413 		if (is(r,p) || is(u,p) || is(r,k) || is(r,m) || is(m,t)) {
414 			cp += 2;
415 			if (isdigit(*cp) && cp[2] == 0)
416 				return (0);
417 		}
418 		break;
419 
420 	case 'm':
421 trymem:
422 		if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
423 			return (0);
424 		break;
425 
426 	case 'n':
427 		if (!strcmp(cp, "null"))
428 			return (0);
429 		break;
430 
431 	case 'v':
432 		if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
433 		    cp[3] == 0)
434 			return (0);
435 		break;
436 	}
437 mightbe:
438 	cp = dbuf.d_name;
439 	while (cp < &dbuf.d_name[DIRSIZ] && *cp)
440 		cp++;
441 	--cp;
442 	x = 0;
443 	if (cp[-1] == 'd') {
444 		if (dialbase == -1) {
445 			if (stat("ttyd0", &stb) == 0)
446 				dialbase = stb.st_rdev & 017;
447 			else
448 				dialbase = -2;
449 		}
450 		if (dialbase == -2)
451 			x = 0;
452 		else
453 			x = 11;
454 	}
455 	if (cp > dbuf.d_name && isdigit(cp[-1]) && isdigit(*cp))
456 		x += 10 * (cp[-1] - ' ') + cp[0] - '0';
457 	else if (*cp >= 'a' && *cp <= 'f')
458 		x += 10 + *cp - 'a';
459 	else if (isdigit(*cp))
460 		x += *cp - '0';
461 	else
462 		x = -1;
463 donecand:
464 	dp = (struct ttys *)alloc(sizeof (struct ttys));
465 	strncpy(dp->name, dbuf.d_name, DIRSIZ);
466 	dp->next = allttys;
467 	dp->ttyd = -1;
468 	allttys = dp;
469 	if (x == -1)
470 		return;
471 	x &= 017;
472 	dp->cand = cand[x];
473 	cand[x] = dp;
474 }
475 
476 char *
477 gettty()
478 {
479 	register char *p;
480 	register struct ttys *dp;
481 	struct stat stb;
482 	int x;
483 
484 	if (u.u_ttyp == 0)
485 		return("?");
486 	x = u.u_ttyd & 017;
487 	for (dp = cand[x]; dp; dp = dp->cand) {
488 		if (dp->ttyd == -1) {
489 			if (stat(dp->name, &stb) == 0)
490 				dp->ttyd = stb.st_rdev;
491 			else
492 				dp->ttyd = -2;
493 		}
494 		if (dp->ttyd == u.u_ttyd)
495 			goto found;
496 	}
497 	/* ick */
498 	for (dp = allttys; dp; dp = dp->next) {
499 		if (dp->ttyd == -1) {
500 			if (stat(dp->name, &stb) == 0)
501 				dp->ttyd = stb.st_rdev;
502 			else
503 				dp->ttyd = -2;
504 		}
505 		if (dp->ttyd == u.u_ttyd)
506 			goto found;
507 	}
508 	return ("?");
509 found:
510 	p = dp->name;
511 	if (p[0]=='t' && p[1]=='t' && p[2]=='y')
512 		p += 3;
513 	return (p);
514 }
515 
516 save()
517 {
518 	register struct savcom *sp;
519 	register struct asav *ap;
520 	register char *cp;
521 	char *ttyp, *cmdp;
522 
523 	if (mproc->p_stat != SZOMB && getu() == 0)
524 		return;
525 	ttyp = gettty();
526 	if (xflg == 0 && ttyp[0] == '?' || tptr && strcmpn(tptr, ttyp, 2))
527 		return;
528 	sp = &savcom[npr];
529 	cmdp = getcmd();
530 	if (cmdp == 0)
531 		return;
532 	sp->ap = ap = (struct asav *)alloc(sizeof (struct asav));
533 	sp->ap->a_cmdp = cmdp;
534 #define e(a,b) ap->a = mproc->b
535 	e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
536 	e(a_uid, p_uid); e(a_pid, p_pid); e(a_rss, p_rssize);
537 #undef e
538 	ap->a_tty[0] = ttyp[0];
539 	ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
540 	if (ap->a_stat == SZOMB) {
541 		register struct xproc *xp = (struct xproc *)mproc;
542 
543 		ap->a_time = xp->xp_vm.vm_utime + xp->xp_vm.vm_stime;
544 	} else {
545 		ap->a_size = mproc->p_dsize + mproc->p_ssize;
546 		ap->a_ttyd = u.u_ttyd;
547 		ap->a_time = u.u_vm.vm_utime + u.u_vm.vm_stime;
548 	}
549 	ap->a_time /= HZ;
550 	if (lflg) {
551 		register struct lsav *lp;
552 
553 		sp->sun.lp = lp = (struct lsav *)alloc(sizeof (struct lsav));
554 #define e(a,b) lp->a = mproc->b
555 		e(l_ppid, p_ppid); e(l_cpu, p_cpu); e(l_pri, p_pri);
556 		if (ap->a_stat != SZOMB)
557 			e(l_wchan, p_wchan);
558 #undef e
559 		lp->l_addr = pcbpf;
560 	} else if (vflg) {
561 		register struct vsav *vp;
562 		register struct text *xp;
563 
564 		sp->sun.vp = vp = (struct vsav *)alloc(sizeof (struct vsav));
565 #define e(a,b) vp->a = mproc->b
566 		e(v_slptime, p_slptime); e(v_pri, p_pri);
567 		if (ap->a_stat != SZOMB) {
568 			e(v_swrss, p_swrss); e(v_aveflt, p_aveflt);
569 			vp->v_minflt = u.u_vm.vm_minflt;
570 			vp->v_majflt = u.u_vm.vm_majflt;
571 			if (mproc->p_textp) {
572 				xp = &text[mproc->p_textp -
573 				    (struct text *)nl[X_TEXT].n_value];
574 				vp->v_tsiz = xp->x_size;
575 				vp->v_txtrss = xp->x_rssize;
576 				vp->v_txtswrss = xp->x_swrss;
577 				vp->v_xccount = xp->x_ccount;
578 			}
579 		}
580 #undef e
581 	} else if (uflg)
582 		sp->sun.u_pctcpu = 0.0;
583 	else if (sflg) {
584 		if (ap->a_stat != SZOMB) {
585 			for (cp = (char *)u.u_stack;
586 			    cp < &user.upages[UPAGES][NBPG]; )
587 				if (*cp++)
588 					break;
589 			sp->sun.s_ssiz = (&user.upages[UPAGES][NBPG] - cp);
590 		}
591 	}
592 	npr++;
593 }
594 
595 getu()
596 {
597 	struct pte *pteaddr, apte, arguutl[UPAGES+CLSIZE];
598 	register int i;
599 	int ncl, size;
600 
601 	size = sflg ? ctob(UPAGES) : sizeof (struct user);
602 	if ((mproc->p_flag & SLOAD) == 0) {
603 		lseek(swap, ctob(mproc->p_swaddr), 0);
604 		if (read(swap, (char *)&user.user, size) != size) {
605 			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
606 			    mproc->p_pid, swapf);
607 			return (0);
608 		}
609 		pcbpf = 0;
610 		argaddr = 0;
611 		return (1);
612 	}
613 	pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
614 	lseek(kmem, kflg ? clear(pteaddr) : (int)pteaddr, 0);
615 	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
616 		printf("ps: cant read indir pte to get u for pid %d from %s\n",
617 		    mproc->p_pid, swapf);
618 		return (0);
619 	}
620 	lseek(mem,
621 	    ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte), 0);
622 	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
623 		printf("ps: cant read page table for u of pid %d from %s\n",
624 		    mproc->p_pid, swapf);
625 		return (0);
626 	}
627 	if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
628 		argaddr = ctob(arguutl[0].pg_pfnum);
629 	else
630 		argaddr = 0;
631 	pcbpf = arguutl[CLSIZE].pg_pfnum;
632 	ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
633 	while (--ncl >= 0) {
634 		i = ncl * CLSIZE;
635 		lseek(mem, ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
636 		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
637 			printf("ps: cant read page %d of u of pid %d from %s\n",
638 			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
639 			return(0);
640 		}
641 	}
642 	return (1);
643 }
644 
645 char *
646 getcmd()
647 {
648 	char cmdbuf[BUFSIZ];
649 	union {
650 		char	argc[CLSIZE*NBPG];
651 		int	argi[CLSIZE*NBPG/sizeof (int)];
652 	} argspac;
653 	register char *cp;
654 	register int *ip;
655 	char c;
656 	int nbad;
657 	struct dblock db;
658 
659 	if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
660 		return ("");
661 	if (cflg) {
662 		strncpy(cmdbuf, u.u_comm, sizeof (u.u_comm));
663 		return (savestr(cmdbuf));
664 	}
665 	if ((mproc->p_flag & SLOAD) == 0 || argaddr == 0) {
666 		vstodb(0, CLSIZE, &u.u_smap, &db, 1);
667 		lseek(swap, ctob(db.db_base), 0);
668 		if (read(swap, (char *)&argspac, sizeof(argspac))
669 		    != sizeof(argspac))
670 			goto bad;
671 	} else {
672 		lseek(mem, argaddr, 0);
673 		if (read(mem, (char *)&argspac, sizeof (argspac))
674 		    != sizeof (argspac))
675 			goto bad;
676 	}
677 	ip = &argspac.argi[CLSIZE*NBPG/sizeof (int)];
678 	ip -= 2;		/* last arg word and .long 0 */
679 	while (*--ip)
680 		if (ip == argspac.argi)
681 			goto retucomm;
682 	*(char *)ip = ' ';
683 	ip++;
684 	nbad = 0;
685 	for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG]; cp++) {
686 		c = *cp & 0177;
687 		if (c == 0)
688 			*cp = ' ';
689 		else if (c < ' ' || c > 0176) {
690 			if (++nbad >= 5*(eflg+1)) {
691 				*cp++ = ' ';
692 				break;
693 			}
694 			*cp = '?';
695 		} else if (eflg == 0 && c == '=') {
696 			while (*--cp != ' ')
697 				if (cp <= (char *)ip)
698 					break;
699 			break;
700 		}
701 	}
702 	*cp = 0;
703 	while (*--cp == ' ')
704 		*cp = 0;
705 	cp = (char *)ip;
706 	strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG] - cp);
707 	if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
708 		strcat(cmdbuf, " (");
709 		strncat(cmdbuf, u.u_comm, sizeof(u.u_comm));
710 		strcat(cmdbuf, ")");
711 	}
712 	if (xflg == 0 && gflg == 0 && tptr == 0 && cp[0] == '-')
713 		return (0);
714 	return (savestr(cmdbuf));
715 
716 bad:
717 	fprintf(stderr, "ps: error locating command name for pid %d\n",
718 	    mproc->p_pid);
719 retucomm:
720 	strcpy(cmdbuf, " (");
721 	strncat(cmdbuf, u.u_comm, sizeof (u.u_comm));
722 	strcat(cmdbuf, ")");
723 	return (savestr(cmdbuf));
724 }
725 
726 char	*lhdr =
727 "     F S UID   PID  PPID CP PRI NI ADDR  SZ  RSS WCHAN TTY TIME";
728 lpr(sp)
729 	struct savcom *sp;
730 {
731 	register struct asav *ap = sp->ap;
732 	register struct lsav *lp = sp->sun.lp;
733 
734 	printf("%6x %c%4d%6u%6u%3d%4d%2d%6x%4d%5d",
735 	    ap->a_flag, "0SWRIZT"[ap->a_stat], ap->a_uid,
736 	    ap->a_pid, lp->l_ppid, lp->l_cpu&0377, lp->l_pri-PZERO,
737 	    ap->a_nice-NZERO, lp->l_addr, ap->a_size, ap->a_rss);
738 	printf(lp->l_wchan ? " %5x" : "      ", (int)lp->l_wchan&0xfffff);
739 	ptty(ap->a_tty);
740 	ptime(ap);
741 }
742 
743 ptty(tp)
744 	char *tp;
745 {
746 
747 	printf(" %-2.2s", tp);
748 }
749 
750 ptime(ap)
751 	struct asav *ap;
752 {
753 
754 	printf("%3ld:%02ld", ap->a_time / HZ, ap->a_time % HZ);
755 }
756 
757 char	*uhdr =
758 "USER       PID %CPU NICE  SZ  RSS TTY TIME";
759 upr(sp)
760 	struct savcom *sp;
761 {
762 	register struct asav *ap = sp->ap;
763 
764 	printf("%-8.8s %5u%5.1f%5d%4d%5d",
765 	    getname(ap->a_uid), ap->a_pid, sp->sun.u_pctcpu, ap->a_nice-NZERO,
766 	    ap->a_size, ap->a_rss);
767 	ptty(ap->a_tty);
768 	ptime(ap);
769 }
770 
771 char *vhdr =
772 "F     PID TTY  TIME RES SL  MINFLT  MAJFLT SIZE  RSS  SRS TSIZ TRS PF";
773 vpr(sp)
774 	struct savcom *sp;
775 {
776 	register struct vsav *vp = sp->sun.vp;
777 	register struct asav *ap = sp->ap;
778 	char stat, nice, anom;
779 
780 	switch (ap->a_stat) {
781 
782 	case SSLEEP:
783 	case SSTOP:
784 		if ((ap->a_flag & SLOAD) == 0)
785 			stat = 'W';
786 		else if (vp->v_pri >= PZERO)
787 			stat = 'S';
788 		else if (ap->a_flag & SPAGE)
789 			stat = 'P';
790 		else
791 			stat = 'D';
792 		break;
793 
794 	case SRUN:
795 	case SIDL:
796 		stat = ap->a_flag & SLOAD ? 'R' : 'W';
797 		break;
798 	}
799 	nice = ap->a_nice > NZERO ? 'N' : ' ';
800 	anom = ap->a_flag & (SANOM|SUANOM) ? 'A' : ' ';
801 	printf("%c%c%c%6u ", stat, nice, anom, ap->a_pid);
802 	ptty(ap->a_tty);
803 	ptime(ap);
804 	printf("%4d%3d%8d%8d%5d%5d%5d%5d%4d%3d",
805 	   ap->a_time, vp->v_slptime, vp->v_minflt, vp->v_majflt,
806 	   ap->a_size, ap->a_rss / 2, vp->v_swrss / 2,
807 	   vp->v_tsiz / 2, vp->v_txtrss / 2, vp->v_aveflt);
808 }
809 
810 char	*shdr =
811 " SSIZ   PID TTY TIME";
812 spr(sp)
813 	struct savcom *sp;
814 {
815 	register struct asav *ap = sp->ap;
816 
817 	if (sflg)
818 		printf("%5d", sp->sun.s_ssiz);
819 	printf(" %5u", ap->a_pid);
820 	ptty(ap->a_tty);
821 	ptime(ap);
822 }
823 
824 /*
825  * Given a base/size pair in virtual swap area,
826  * return a physical base/size pair which is the
827  * (largest) initial, physically contiguous block.
828  */
829 vstodb(vsbase, vssize, dmp, dbp, rev)
830 	register int vsbase;
831 	int vssize;
832 	struct dmap *dmp;
833 	register struct dblock *dbp;
834 {
835 	register int blk = DMMIN;
836 	register swblk_t *ip = dmp->dm_map;
837 
838 	if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
839 		panic("vstodb");
840 	while (vsbase >= blk) {
841 		vsbase -= blk;
842 		if (blk < DMMAX)
843 			blk *= 2;
844 		ip++;
845 	}
846 	if (*ip <= 0 || *ip + blk > nswap)
847 		panic("vstodb *ip");
848 	dbp->db_size = min(vssize, blk - vsbase);
849 	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
850 }
851 
852 /*ARGSUSED*/
853 panic(cp)
854 	char *cp;
855 {
856 
857 #ifdef DEBUG
858 	printf("%s\n", cp);
859 #endif
860 }
861 
862 min(a, b)
863 {
864 
865 	return (a < b ? a : b);
866 }
867 
868 pscomp(s1, s2)
869 	struct savcom *s1, *s2;
870 {
871 	register int i;
872 
873 	if (vflg)
874 		return (vsize(s2) - vsize(s1));
875 	i = s1->ap->a_ttyd - s2->ap->a_ttyd;
876 	if (i == 0)
877 		i = s1->ap->a_pid - s2->ap->a_pid;
878 	return (i);
879 }
880 
881 vsize(sp)
882 	struct savcom *sp;
883 {
884 	register struct asav *ap = sp->ap;
885 	register struct vsav *vp = sp->sun.vp;
886 
887 	if (ap->a_flag & SLOAD)
888 		return (ap->a_rss +
889 		    vp->v_txtrss / (vp->v_xccount ? vp->v_xccount : 1));
890 	return (vp->v_swrss + (vp->v_xccount ? 0 : vp->v_txtswrss));
891 }
892 
893 #define	NMAX	8
894 #define	NUID	2048
895 
896 char	names[NUID][NMAX+1];
897 
898 /*
899  * Stolen from ls...
900  */
901 char *
902 getname(uid)
903 {
904 	register struct passwd *pw;
905 	static init;
906 	struct passwd *getpwent();
907 
908 	if (names[uid][0])
909 		return (&names[uid][0]);
910 	if (init == 2)
911 		return (0);
912 	if (init == 0)
913 		setpwent(), init = 1;
914 	while (pw = getpwent()) {
915 		if (pw->pw_uid >= NUID)
916 			continue;
917 		if (names[pw->pw_uid][0])
918 			continue;
919 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
920 		if (pw->pw_uid == uid)
921 			return (&names[uid][0]);
922 	}
923 	init = 2;
924 	endpwent();
925 	return (0);
926 }
927 
928 char	*freebase;
929 int	nleft;
930 
931 char *
932 alloc(size)
933 	int size;
934 {
935 	register char *cp;
936 	register int i;
937 
938 	if (size > nleft) {
939 		freebase = (char *)sbrk(i = size > 2048 ? size : 2048);
940 		if (freebase == 0) {
941 			fprintf(stderr, "ps: ran out of memory\n");
942 			exit(1);
943 		}
944 		nleft = i - size;
945 	} else
946 		nleft -= size;
947 	cp = freebase;
948 	for (i = size; --i >= 0; )
949 		*cp++ = 0;
950 	freebase = cp;
951 	return (cp - size);
952 }
953 
954 char *
955 savestr(cp)
956 	char *cp;
957 {
958 	register int len;
959 	register char *dp;
960 
961 	len = strlen(cp);
962 	dp = (char *)alloc(len+1);
963 	strcpy(dp, cp);
964 	return (dp);
965 }
966