xref: /original-bsd/bin/ps/ps.c (revision 6c57d260)
1 static	char *sccsid = "@(#)ps.c	4.11 (Berkeley) 05/12/81";
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(" net 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 		break;
480 
481 	case 'n':
482 		if (!strcmp(cp, "null"))
483 			return (0);
484 		break;
485 
486 	case 'v':
487 		if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
488 		    cp[3] == 0)
489 			return (0);
490 		break;
491 	}
492 mightbe:
493 	cp = dbuf.d_name;
494 	while (cp < &dbuf.d_name[DIRSIZ] && *cp)
495 		cp++;
496 	--cp;
497 	x = 0;
498 	if (cp[-1] == 'd') {
499 		if (dialbase == -1) {
500 			if (stat("ttyd0", &stb) == 0)
501 				dialbase = stb.st_rdev & 017;
502 			else
503 				dialbase = -2;
504 		}
505 		if (dialbase == -2)
506 			x = 0;
507 		else
508 			x = 11;
509 	}
510 	if (cp > dbuf.d_name && isdigit(cp[-1]) && isdigit(*cp))
511 		x += 10 * (cp[-1] - ' ') + cp[0] - '0';
512 	else if (*cp >= 'a' && *cp <= 'f')
513 		x += 10 + *cp - 'a';
514 	else if (isdigit(*cp))
515 		x += *cp - '0';
516 	else
517 		x = -1;
518 donecand:
519 	dp = (struct ttys *)alloc(sizeof (struct ttys));
520 	strncpy(dp->name, dbuf.d_name, DIRSIZ);
521 	dp->next = allttys;
522 	dp->ttyd = -1;
523 	allttys = dp;
524 	if (x == -1)
525 		return;
526 	x &= 017;
527 	dp->cand = cand[x];
528 	cand[x] = dp;
529 }
530 
531 char *
532 gettty()
533 {
534 	register char *p;
535 	register struct ttys *dp;
536 	struct stat stb;
537 	int x;
538 
539 	if (u.u_ttyp == 0)
540 		return("?");
541 	x = u.u_ttyd & 017;
542 	for (dp = cand[x]; dp; dp = dp->cand) {
543 		if (dp->ttyd == -1) {
544 			if (stat(dp->name, &stb) == 0 &&
545 			   (stb.st_mode&S_IFMT)==S_IFCHR)
546 				dp->ttyd = stb.st_rdev;
547 			else
548 				dp->ttyd = -2;
549 		}
550 		if (dp->ttyd == u.u_ttyd)
551 			goto found;
552 	}
553 	/* ick */
554 	for (dp = allttys; dp; dp = dp->next) {
555 		if (dp->ttyd == -1) {
556 			if (stat(dp->name, &stb) == 0)
557 				dp->ttyd = stb.st_rdev;
558 			else
559 				dp->ttyd = -2;
560 		}
561 		if (dp->ttyd == u.u_ttyd)
562 			goto found;
563 	}
564 	return ("?");
565 found:
566 	p = dp->name;
567 	if (p[0]=='t' && p[1]=='t' && p[2]=='y')
568 		p += 3;
569 	return (p);
570 }
571 
572 save()
573 {
574 	register struct savcom *sp;
575 	register struct asav *ap;
576 	register char *cp;
577 	register struct text *xp;
578 	char *ttyp, *cmdp;
579 
580 	if (mproc->p_stat != SZOMB && getu() == 0)
581 		return;
582 	ttyp = gettty();
583 	if (xflg == 0 && ttyp[0] == '?' || tptr && strcmpn(tptr, ttyp, 2))
584 		return;
585 	sp = &savcom[npr];
586 	cmdp = getcmd();
587 	if (cmdp == 0)
588 		return;
589 	sp->ap = ap = (struct asav *)alloc(sizeof (struct asav));
590 	sp->ap->a_cmdp = cmdp;
591 #define e(a,b) ap->a = mproc->b
592 	e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
593 	e(a_uid, p_uid); e(a_pid, p_pid); e(a_pri, p_pri);
594 	e(a_slptime, p_slptime); e(a_time, p_time);
595 	ap->a_tty[0] = ttyp[0];
596 	ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
597 	if (ap->a_stat == SZOMB) {
598 		register struct xproc *xp = (struct xproc *)mproc;
599 
600 		ap->a_cpu = xp->xp_vm.vm_utime + xp->xp_vm.vm_stime;
601 	} else {
602 		ap->a_size = mproc->p_dsize + mproc->p_ssize;
603 		e(a_rss, p_rssize);
604 		ap->a_ttyd = u.u_ttyd;
605 		ap->a_cpu = u.u_vm.vm_utime + u.u_vm.vm_stime;
606 		if (sumcpu)
607 			ap->a_cpu += u.u_cvm.vm_utime + u.u_cvm.vm_stime;
608 		if (mproc->p_textp && text) {
609 			xp = &text[mproc->p_textp - atext];
610 			ap->a_tsiz = xp->x_size;
611 			ap->a_txtrss = xp->x_rssize;
612 			ap->a_xccount = xp->x_ccount;
613 		}
614 	}
615 #undef e
616 	ap->a_cpu /= hz;
617 	ap->a_maxrss = mproc->p_maxrss;
618 	if (lflg) {
619 		register struct lsav *lp;
620 
621 		sp->sun.lp = lp = (struct lsav *)alloc(sizeof (struct lsav));
622 #define e(a,b) lp->a = mproc->b
623 		e(l_ppid, p_ppid); e(l_cpu, p_cpu);
624 		if (ap->a_stat != SZOMB)
625 			e(l_wchan, p_wchan);
626 #undef e
627 		lp->l_addr = pcbpf;
628 	} else if (vflg) {
629 		register struct vsav *vp;
630 
631 		sp->sun.vp = vp = (struct vsav *)alloc(sizeof (struct vsav));
632 #define e(a,b) vp->a = mproc->b
633 		if (ap->a_stat != SZOMB) {
634 			e(v_swrss, p_swrss);
635 			vp->v_majflt = u.u_vm.vm_majflt;
636 			if (mproc->p_textp)
637 				vp->v_txtswrss = xp->x_swrss;
638 		}
639 		vp->v_pctcpu = pcpu();
640 #undef e
641 	} else if (uflg)
642 		sp->sun.u_pctcpu = pcpu();
643 	else if (sflg) {
644 		if (ap->a_stat != SZOMB) {
645 			for (cp = (char *)u.u_stack;
646 			    cp < &user.upages[UPAGES][0]; )
647 				if (*cp++)
648 					break;
649 			sp->sun.s_ssiz = (&user.upages[UPAGES][0] - cp);
650 		}
651 	}
652 	npr++;
653 }
654 
655 double
656 pmem(ap)
657 	register struct asav *ap;
658 {
659 	double fracmem;
660 	int szptudot;
661 
662 	if ((ap->a_flag&SLOAD) == 0)
663 		fracmem = 0.0;
664 	else {
665 		szptudot = UPAGES + clrnd(ctopt(ap->a_size+ap->a_tsiz));
666 		fracmem = ((float)ap->a_rss+szptudot)/CLSIZE/ecmx;
667 		if (ap->a_xccount)
668 			fracmem += ((float)ap->a_txtrss)/CLSIZE/
669 			    ap->a_xccount/ecmx;
670 	}
671 	return (100.0 * fracmem);
672 }
673 
674 double
675 pcpu()
676 {
677 	time_t time;
678 
679 	time = mproc->p_time;
680 	if (time == 0 || (mproc->p_flag&SLOAD) == 0)
681 		return (0.0);
682 	if (rawcpu)
683 		return (100.0 * mproc->p_pctcpu);
684 	return (100.0 * mproc->p_pctcpu / (1.0 - exp(time * log(ccpu))));
685 }
686 
687 getu()
688 {
689 	struct pte *pteaddr, apte;
690 	int pad1;	/* avoid hardware botch */
691 	struct pte arguutl[UPAGES+CLSIZE];
692 	int pad2;	/* avoid hardware botch */
693 	register int i;
694 	int ncl, size;
695 
696 	size = sflg ? ctob(UPAGES) : sizeof (struct user);
697 	if ((mproc->p_flag & SLOAD) == 0) {
698 		lseek(swap, ctob(mproc->p_swaddr), 0);
699 		if (read(swap, (char *)&user.user, size) != size) {
700 			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
701 			    mproc->p_pid, swapf);
702 			return (0);
703 		}
704 		pcbpf = 0;
705 		argaddr = 0;
706 		return (1);
707 	}
708 	pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
709 	lseek(kmem, kflg ? clear(pteaddr) : (int)pteaddr, 0);
710 	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
711 		printf("ps: cant read indir pte to get u for pid %d from %s\n",
712 		    mproc->p_pid, swapf);
713 		return (0);
714 	}
715 	lseek(mem,
716 	    ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte), 0);
717 	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
718 		printf("ps: cant read page table for u of pid %d from %s\n",
719 		    mproc->p_pid, swapf);
720 		return (0);
721 	}
722 	if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
723 		argaddr = ctob(arguutl[0].pg_pfnum);
724 	else
725 		argaddr = 0;
726 	pcbpf = arguutl[CLSIZE].pg_pfnum;
727 	ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
728 	while (--ncl >= 0) {
729 		i = ncl * CLSIZE;
730 		lseek(mem, ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
731 		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
732 			printf("ps: cant read page %d of u of pid %d from %s\n",
733 			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
734 			return(0);
735 		}
736 	}
737 	return (1);
738 }
739 
740 char *
741 getcmd()
742 {
743 	char cmdbuf[BUFSIZ];
744 	int pad1;		/* avoid hardware botch */
745 	union {
746 		char	argc[CLSIZE*NBPG];
747 		int	argi[CLSIZE*NBPG/sizeof (int)];
748 	} argspac;
749 	int pad2;		/* avoid hardware botch */
750 	register char *cp;
751 	register int *ip;
752 	char c;
753 	int nbad;
754 	struct dblock db;
755 
756 	if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
757 		return ("");
758 	if (cflg) {
759 		strncpy(cmdbuf, u.u_comm, sizeof (u.u_comm));
760 		return (savestr(cmdbuf));
761 	}
762 	if ((mproc->p_flag & SLOAD) == 0 || argaddr == 0) {
763 		vstodb(0, CLSIZE, &u.u_smap, &db, 1);
764 		lseek(swap, ctob(db.db_base), 0);
765 		if (read(swap, (char *)&argspac, sizeof(argspac))
766 		    != sizeof(argspac))
767 			goto bad;
768 	} else {
769 		lseek(mem, argaddr, 0);
770 		if (read(mem, (char *)&argspac, sizeof (argspac))
771 		    != sizeof (argspac))
772 			goto bad;
773 	}
774 	ip = &argspac.argi[CLSIZE*NBPG/sizeof (int)];
775 	ip -= 2;		/* last arg word and .long 0 */
776 	while (*--ip)
777 		if (ip == argspac.argi)
778 			goto retucomm;
779 	*(char *)ip = ' ';
780 	ip++;
781 	nbad = 0;
782 	for (cp = (char *)ip; cp < &argspac.argc[CLSIZE*NBPG]; cp++) {
783 		c = *cp & 0177;
784 		if (c == 0)
785 			*cp = ' ';
786 		else if (c < ' ' || c > 0176) {
787 			if (++nbad >= 5*(eflg+1)) {
788 				*cp++ = ' ';
789 				break;
790 			}
791 			*cp = '?';
792 		} else if (eflg == 0 && c == '=') {
793 			while (*--cp != ' ')
794 				if (cp <= (char *)ip)
795 					break;
796 			break;
797 		}
798 	}
799 	*cp = 0;
800 	while (*--cp == ' ')
801 		*cp = 0;
802 	cp = (char *)ip;
803 	strncpy(cmdbuf, cp, &argspac.argc[CLSIZE*NBPG] - cp);
804 	if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
805 		strcat(cmdbuf, " (");
806 		strncat(cmdbuf, u.u_comm, sizeof(u.u_comm));
807 		strcat(cmdbuf, ")");
808 	}
809 /*
810 	if (xflg == 0 && gflg == 0 && tptr == 0 && cp[0] == '-')
811 		return (0);
812 */
813 	return (savestr(cmdbuf));
814 
815 bad:
816 	fprintf(stderr, "ps: error locating command name for pid %d\n",
817 	    mproc->p_pid);
818 retucomm:
819 	strcpy(cmdbuf, " (");
820 	strncat(cmdbuf, u.u_comm, sizeof (u.u_comm));
821 	strcat(cmdbuf, ")");
822 	return (savestr(cmdbuf));
823 }
824 
825 char	*lhdr =
826 "     F UID   PID  PPID CP PRI NI ADDR  SZ  RSS WCHAN STAT TT  TIME";
827 lpr(sp)
828 	struct savcom *sp;
829 {
830 	register struct asav *ap = sp->ap;
831 	register struct lsav *lp = sp->sun.lp;
832 
833 	printf("%6x%4d%6u%6u%3d%4d%3d%5x%4d%5d",
834 	    ap->a_flag, ap->a_uid,
835 	    ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
836 	    ap->a_nice-NZERO, lp->l_addr, ap->a_size/2, ap->a_rss/2);
837 	printf(lp->l_wchan ? " %5x" : "      ", (int)lp->l_wchan&0xfffff);
838 	printf(" %4.4s ", state(ap));
839 	ptty(ap->a_tty);
840 	ptime(ap);
841 }
842 
843 ptty(tp)
844 	char *tp;
845 {
846 
847 	printf("%-2.2s", tp);
848 }
849 
850 ptime(ap)
851 	struct asav *ap;
852 {
853 
854 	printf("%3ld:%02ld", ap->a_cpu / hz, ap->a_cpu % hz);
855 }
856 
857 char	*uhdr =
858 "USER       PID %CPU %MEM   SZ  RSS TT STAT  TIME";
859 upr(sp)
860 	struct savcom *sp;
861 {
862 	register struct asav *ap = sp->ap;
863 	int vmsize, rmsize;
864 
865 	vmsize = (ap->a_size + ap->a_tsiz)/2;
866 	rmsize = ap->a_rss/2;
867 	if (ap->a_xccount)
868 		rmsize += ap->a_txtrss/ap->a_xccount/2;
869 	printf("%-8.8s %5d%5.1f%5.1f%5d%5d",
870 	    getname(ap->a_uid), ap->a_pid, sp->sun.u_pctcpu, pmem(ap),
871 	    vmsize, rmsize);
872 	putchar(' ');
873 	ptty(ap->a_tty);
874 	printf(" %4.4s", state(ap));
875 	ptime(ap);
876 }
877 
878 char *vhdr =
879 "  PID TT STAT  TIME SL RE PAGEIN SIZE  RSS  LIM TSIZ TRS %CPU %MEM";
880 vpr(sp)
881 	struct savcom *sp;
882 {
883 	register struct vsav *vp = sp->sun.vp;
884 	register struct asav *ap = sp->ap;
885 
886 	printf("%5u ", ap->a_pid);
887 	ptty(ap->a_tty);
888 	printf(" %4.4s", state(ap));
889 	ptime(ap);
890 	printf("%3d%3d%7d%5d%5d",
891 	   ap->a_slptime > 99 ? 99 : ap-> a_slptime,
892 	   ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
893 	   ap->a_size/2, ap->a_rss/2);
894 	if (ap->a_maxrss == (INFINITY/NBPG))
895 		printf("   xx");
896 	else
897 		printf("%5d", ap->a_maxrss/2);
898 	printf("%5d%4d%5.1f%5.1f",
899 	   ap->a_tsiz/2, ap->a_txtrss/2, vp->v_pctcpu, pmem(ap));
900 }
901 
902 char	*shdr =
903 "SSIZ   PID TT STAT  TIME";
904 spr(sp)
905 	struct savcom *sp;
906 {
907 	register struct asav *ap = sp->ap;
908 
909 	if (sflg)
910 		printf("%4d ", sp->sun.s_ssiz);
911 	printf("%5u", ap->a_pid);
912 	putchar(' ');
913 	ptty(ap->a_tty);
914 	printf(" %4.4s", state(ap));
915 	ptime(ap);
916 }
917 
918 char *
919 state(ap)
920 	register struct asav *ap;
921 {
922 	char stat, load, nice, anom;
923 	static char res[5];
924 
925 	switch (ap->a_stat) {
926 
927 	case SSTOP:
928 		stat = 'T';
929 		break;
930 
931 	case SSLEEP:
932 		if (ap->a_pri >= PZERO)
933 			if (ap->a_slptime >= MAXSLP)
934 				stat = 'I';
935 			else
936 				stat = 'S';
937 		else if (ap->a_flag & SPAGE)
938 			stat = 'P';
939 		else
940 			stat = 'D';
941 		break;
942 
943 	case SWAIT:
944 	case SRUN:
945 	case SIDL:
946 		stat = 'R';
947 		break;
948 
949 	case SZOMB:
950 		stat = 'Z';
951 		break;
952 
953 	default:
954 		stat = '?';
955 	}
956 	load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
957 	if (ap->a_nice < NZERO)
958 		nice = '<';
959 	else if (ap->a_nice > NZERO)
960 		nice = 'N';
961 	else
962 		nice = ' ';
963 	anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
964 	res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
965 	return (res);
966 }
967 
968 /*
969  * Given a base/size pair in virtual swap area,
970  * return a physical base/size pair which is the
971  * (largest) initial, physically contiguous block.
972  */
973 vstodb(vsbase, vssize, dmp, dbp, rev)
974 	register int vsbase;
975 	int vssize;
976 	struct dmap *dmp;
977 	register struct dblock *dbp;
978 {
979 	register int blk = DMMIN;
980 	register swblk_t *ip = dmp->dm_map;
981 
982 	if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
983 		panic("vstodb");
984 	while (vsbase >= blk) {
985 		vsbase -= blk;
986 		if (blk < DMMAX)
987 			blk *= 2;
988 		ip++;
989 	}
990 	if (*ip <= 0 || *ip + blk > nswap)
991 		panic("vstodb *ip");
992 	dbp->db_size = min(vssize, blk - vsbase);
993 	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
994 }
995 
996 /*ARGSUSED*/
997 panic(cp)
998 	char *cp;
999 {
1000 
1001 #ifdef DEBUG
1002 	printf("%s\n", cp);
1003 #endif
1004 }
1005 
1006 min(a, b)
1007 {
1008 
1009 	return (a < b ? a : b);
1010 }
1011 
1012 pscomp(s1, s2)
1013 	struct savcom *s1, *s2;
1014 {
1015 	register int i;
1016 
1017 	if (uflg)
1018 		return (s2->sun.u_pctcpu > s1->sun.u_pctcpu ? 1 : -1);
1019 	if (vflg)
1020 		return (vsize(s2) - vsize(s1));
1021 	i = s1->ap->a_ttyd - s2->ap->a_ttyd;
1022 	if (i == 0)
1023 		i = s1->ap->a_pid - s2->ap->a_pid;
1024 	return (i);
1025 }
1026 
1027 vsize(sp)
1028 	struct savcom *sp;
1029 {
1030 	register struct asav *ap = sp->ap;
1031 	register struct vsav *vp = sp->sun.vp;
1032 
1033 	if (ap->a_flag & SLOAD)
1034 		return (ap->a_rss +
1035 		    ap->a_txtrss / (ap->a_xccount ? ap->a_xccount : 1));
1036 	return (vp->v_swrss + (ap->a_xccount ? 0 : vp->v_txtswrss));
1037 }
1038 
1039 #define	NMAX	8
1040 #define	NUID	2048
1041 
1042 char	names[NUID][NMAX+1];
1043 
1044 /*
1045  * Stolen from ls...
1046  */
1047 char *
1048 getname(uid)
1049 {
1050 	register struct passwd *pw;
1051 	static init;
1052 	struct passwd *getpwent();
1053 
1054 	if (uid >= 0 && uid < NUID && names[uid][0])
1055 		return (&names[uid][0]);
1056 	if (init == 2)
1057 		return (0);
1058 	if (init == 0)
1059 		setpwent(), init = 1;
1060 	while (pw = getpwent()) {
1061 		if (pw->pw_uid >= NUID)
1062 			continue;
1063 		if (names[pw->pw_uid][0])
1064 			continue;
1065 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
1066 		if (pw->pw_uid == uid)
1067 			return (&names[uid][0]);
1068 	}
1069 	init = 2;
1070 	endpwent();
1071 	return (0);
1072 }
1073 
1074 char	*freebase;
1075 int	nleft;
1076 
1077 char *
1078 alloc(size)
1079 	int size;
1080 {
1081 	register char *cp;
1082 	register int i;
1083 
1084 	if (size > nleft) {
1085 		freebase = (char *)sbrk(i = size > 2048 ? size : 2048);
1086 		if (freebase == 0) {
1087 			fprintf(stderr, "ps: ran out of memory\n");
1088 			exit(1);
1089 		}
1090 		nleft = i - size;
1091 	} else
1092 		nleft -= size;
1093 	cp = freebase;
1094 	for (i = size; --i >= 0; )
1095 		*cp++ = 0;
1096 	freebase = cp;
1097 	return (cp - size);
1098 }
1099 
1100 char *
1101 savestr(cp)
1102 	char *cp;
1103 {
1104 	register int len;
1105 	register char *dp;
1106 
1107 	len = strlen(cp);
1108 	dp = (char *)alloc(len+1);
1109 	strcpy(dp, cp);
1110 	return (dp);
1111 }
1112