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