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