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