xref: /netbsd-src/bin/ps/print.c (revision 4b30c543a0b21e3ba94f2c569e9a82b4fdb2075f)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 /*static char sccsid[] = "from: @(#)print.c	5.9 (Berkeley) 7/1/91";*/
36 static char rcsid[] = "$Id: print.c,v 1.9 1993/08/14 12:30:04 mycroft Exp $";
37 #endif /* not lint */
38 
39 #include <sys/param.h>
40 #include <sys/time.h>
41 #include <sys/resource.h>
42 #include <sys/proc.h>
43 #include <sys/stat.h>
44 #include <math.h>
45 #include <tzfile.h>
46 #include <stddef.h>
47 #include <string.h>
48 #include <vis.h>
49 #include "ps.h"
50 
51 #ifdef SPPWAIT
52 #define NEWVM
53 #endif
54 
55 #ifdef NEWVM
56 #include <vm/vm.h>
57 #include <sys/ucred.h>
58 #include <sys/kinfo_proc.h>
59 #else
60 #include <machine/pte.h>
61 #include <sys/vmparam.h>
62 #include <sys/vm.h>
63 #endif
64 
65 printheader()
66 {
67 	register VAR *v;
68 	register struct varent *vent;
69 
70 	for (vent = vhead; vent; vent = vent->next) {
71 		v = vent->var;
72 		if (v->flag & LJUST) {
73 			if (vent->next == NULL)	/* last one */
74 				(void) printf("%s", v->header);
75 			else
76 				(void) printf("%-*s", v->width, v->header);
77 		} else
78 			(void) printf("%*s", v->width, v->header);
79 		if (vent->next != NULL)
80 			(void) putchar(' ');
81 	}
82 	(void) putchar('\n');
83 }
84 
85 command(k, v, next)
86 	KINFO *k;
87 	VAR *v;
88 {
89 	extern int termwidth, totwidth;
90 	char *vis_env, *vis_args;
91 
92 	vis_args = (char *)malloc(strlen(k->ki_args)*4 + 1);
93 	if (vis_args == NULL)
94 		err("out of memory");
95 	strvis(vis_args, k->ki_args, VIS_TAB|VIS_NL|VIS_NOSLASH);
96 
97 	if (k->ki_env) {
98 		vis_env = (char *)malloc(strlen(k->ki_env)*4 + 1);
99 		if (vis_env == NULL)
100 			err("out of memory");
101 		strvis(vis_env, k->ki_env, VIS_TAB|VIS_NL|VIS_NOSLASH);
102 	} else {
103 		vis_env = NULL;
104 	}
105 
106 	if (next == NULL) {
107 		/* last field */
108 		if (termwidth == UNLIMITED) {
109 			if (vis_env)
110 				(void)printf("%s ", vis_env);
111 			(void) printf("%s", vis_args);
112 		} else {
113 			register int left = termwidth - (totwidth - v->width);
114 			register char *cp;
115 
116 			if (left < 1) /* already wrapped, just use std width */
117 				left = v->width;
118                         cp = vis_env;
119 			if (cp != 0) {
120 				while (--left >= 0 && *cp)
121 					(void)putchar(*cp++);
122 				if (--left >= 0)
123 					putchar(' ');
124 			}
125 			cp = vis_args;
126 			while (--left >= 0 && *cp)
127 				(void) putchar(*cp++);
128 		}
129 	} else
130 		/* XXX environment strings? */
131 		(void) printf("%-*.*s", v->width, v->width, vis_args);
132 
133 	free(vis_args);
134 	if (vis_env != NULL)
135 		free(vis_env);
136 }
137 
138 ucomm(k, v)
139 	KINFO *k;
140 	VAR *v;
141 {
142 	(void) printf("%-*s", v->width, k->ki_p->p_comm);
143 }
144 
145 logname(k, v)
146 	KINFO *k;
147 	VAR *v;
148 {
149 #ifndef NEWVM
150 	(void) printf("%-*s", v->width, k->ki_p->p_logname);
151 #else /* NEWVM */
152 	(void) printf("%-*s", v->width, k->ki_e->e_login);
153 #endif /* NEWVM */
154 }
155 
156 state(k, v)
157 	KINFO *k;
158 	VAR *v;
159 {
160 	char buf[16];
161 	register char *cp = buf;
162 	register struct proc *p = k->ki_p;
163 	register flag = p->p_flag;
164 
165 	switch (p->p_stat) {
166 
167 	case SSTOP:
168 		*cp = 'T';
169 		break;
170 
171 	case SSLEEP:
172 		if (flag & SSINTR)	/* interuptable (long) */
173 			*cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
174 		else
175 			*cp = (flag & SPAGE) ? 'P' : 'D';
176 		break;
177 
178 	case SRUN:
179 	case SIDL:
180 		*cp = 'R';
181 		break;
182 
183 	case SZOMB:
184 		*cp = 'Z';
185 		break;
186 
187 	default:
188 		*cp = '?';
189 	}
190 	cp++;
191 	if (flag & SLOAD) {
192 #ifndef NEWVM
193 		if (p->p_rssize > p->p_maxrss)
194 			*cp++ = '>';
195 #endif
196 	} else
197 		*cp++ = 'W';
198 	if (p->p_nice < NZERO)
199 		*cp++ = '<';
200 	else if (p->p_nice > NZERO)
201 		*cp++ = 'N';
202 #ifndef NEWVM
203 	if (flag & SUANOM)
204 		*cp++ = 'A';
205 	else if (flag & SSEQL)
206 		*cp++ = 'S';
207 #endif
208 	if (flag & STRC)
209 		*cp++ = 'X';
210 	if (flag & SWEXIT && p->p_stat != SZOMB)
211 		*cp++ = 'E';
212 #ifdef NEWVM
213 	if (flag & SPPWAIT)
214 #else
215 	if (flag & SVFORK)
216 #endif
217 		*cp++ = 'V';
218 #ifdef NEWVM
219 	if (flag & (SSYS|SLOCK|SKEEP|SPHYSIO))
220 #else
221 	if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO))
222 #endif
223 		*cp++ = 'L';
224 	if (k->ki_e->e_flag & EPROC_SLEADER)
225 		*cp++ = 's';
226 	if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid)
227 		*cp++ = '+';
228 	*cp = '\0';
229 	(void) printf("%-*s", v->width, buf);
230 }
231 
232 pri(k, v)
233 	KINFO *k;
234 	VAR *v;
235 {
236 	(void) printf("%*d", v->width, k->ki_p->p_pri - PZERO);
237 }
238 
239 uname(k, v)
240 	KINFO *k;
241 	VAR *v;
242 {
243 #ifndef NEWVM
244 	(void) printf("%-*s", v->width, user_from_uid(k->ki_p->p_uid, 0));
245 #else /* NEWVM */
246 	(void) printf("%-*s", v->width,
247 		user_from_uid(k->ki_e->e_ucred.cr_uid, 0));
248 #endif /* NEWVM */
249 }
250 
251 runame(k, v)
252 	KINFO *k;
253 	VAR *v;
254 {
255 #ifndef NEWVM
256 	(void) printf("%-*s", v->width, user_from_uid(k->ki_p->p_ruid, 0));
257 #else /* NEWVM */
258 	(void) printf("%-*s", v->width,
259 		user_from_uid(k->ki_e->e_pcred.p_ruid, 0));
260 #endif /* NEWVM */
261 }
262 
263 tdev(k, v)
264 	KINFO *k;
265 	VAR *v;
266 {
267 	dev_t dev = k->ki_e->e_tdev;
268 
269 	if (dev == NODEV)
270 		(void) printf("%*s", v->width, "??");
271 	else {
272 		char buff[16];
273 
274 		(void) sprintf(buff, "%d/%d", major(dev), minor(dev));
275 		(void) printf("%*s", v->width, buff);
276 	}
277 }
278 
279 tname(k, v)
280 	KINFO *k;
281 	VAR *v;
282 {
283 	dev_t dev;
284 	char *ttname, *devname();
285 
286 	dev = k->ki_e->e_tdev;
287 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
288 		(void) printf("%-*s", v->width, "??");
289 	else {
290 		if (strncmp(ttname, "tty", 3) == 0)
291 			ttname += 3;
292 		(void) printf("%*.*s%c", v->width-1, v->width-1, ttname,
293 			k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-');
294 	}
295 }
296 
297 longtname(k, v)
298 	KINFO *k;
299 	VAR *v;
300 {
301 	dev_t dev;
302 	char *ttname, *devname();
303 
304 	dev = k->ki_e->e_tdev;
305 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
306 		(void) printf("%-*s", v->width, "??");
307 	else
308 		(void) printf("%-*s", v->width, ttname);
309 }
310 
311 started(k, v)
312 	KINFO *k;
313 	VAR *v;
314 {
315 	static time_t now;
316 	struct tm *tp;
317 	char buf[100];
318 
319 	if (!k->ki_u) {
320 		(void) printf("%-*s", v->width, "-");
321 		return;
322 	}
323 
324 	tp = localtime(&k->ki_u->u_start.tv_sec);
325 	if (!now)
326 		(void)time(&now);
327 	if (now - k->ki_u->u_start.tv_sec < 24 * SECSPERHOUR) {
328 		static char fmt[] = "%l:@M%p";
329 		fmt[3] = '%';			/* I *hate* SCCS... */
330 		(void) strftime(buf, sizeof(buf) - 1, fmt, tp);
331 	} else if (now - k->ki_u->u_start.tv_sec < 7 * SECSPERDAY) {
332 		static char fmt[] = "%a@I%p";
333 		fmt[2] = '%';			/* I *hate* SCCS... */
334 		(void) strftime(buf, sizeof(buf) - 1, fmt, tp);
335 	} else
336 		(void) strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
337 	(void) printf("%-*s", v->width, buf);
338 }
339 
340 lstarted(k, v)
341 	KINFO *k;
342 	VAR *v;
343 {
344 	char buf[100];
345 
346 	if (!k->ki_u) {
347 		(void) printf("%-*s", v->width, "-");
348 		return;
349 	}
350 	(void) strftime(buf, sizeof(buf) -1, "%C",
351 	    localtime(&k->ki_u->u_start.tv_sec));
352 	(void) printf("%-*s", v->width, buf);
353 }
354 
355 wchan(k, v)
356 	KINFO *k;
357 	VAR *v;
358 {
359 	if (k->ki_p->p_wchan) {
360 		if (k->ki_p->p_wmesg)
361 			(void) printf("%-*.*s", v->width, v->width, k->ki_e->e_wmesg);
362 		else
363 			(void) printf("%-*x", v->width,
364 			    (int)k->ki_p->p_wchan &~ KERNBASE);
365 	} else
366 		(void) printf("%-*s", v->width, "-");
367 }
368 
369 #define pgtok(a)        (((a)*NBPG)/1024)
370 
371 vsize(k, v)
372 	KINFO *k;
373 	VAR *v;
374 {
375 	(void) printf("%*d", v->width,
376 #ifndef NEWVM
377 	    pgtok(k->ki_p->p_dsize + k->ki_p->p_ssize + k->ki_e->e_xsize));
378 #else /* NEWVM */
379 	    (k->ki_p->p_stat == SZOMB ? 0 :
380 		pgtok(k->ki_e->e_vm.vm_dsize + k->ki_e->e_vm.vm_ssize +
381 		      k->ki_e->e_vm.vm_tsize)));
382 #endif /* NEWVM */
383 }
384 
385 rssize(k, v)
386 	KINFO *k;
387 	VAR *v;
388 {
389 #ifndef NEWVM
390 	(void) printf("%*d", v->width,
391 	    pgtok(k->ki_p->p_rssize + (k->ki_e->e_xccount ?
392 	    (k->ki_e->e_xrssize / k->ki_e->e_xccount) : 0)));
393 #else /* NEWVM */
394 	/* XXX don't have info about shared */
395 	(void) printf("%*d", v->width, (k->ki_p->p_stat == SZOMB ? 0 :
396 		      pgtok(k->ki_e->e_vm.vm_rssize)));
397 #endif /* NEWVM */
398 }
399 
400 p_rssize(k, v)		/* doesn't account for text */
401 	KINFO *k;
402 	VAR *v;
403 {
404 #ifndef NEWVM
405 	(void) printf("%*d", v->width, pgtok(k->ki_p->p_rssize));
406 #else /* NEWVM */
407 	(void) printf("%*d", v->width, pgtok(k->ki_e->e_vm.vm_rssize));
408 #endif /* NEWVM */
409 }
410 
411 cputime(k, v)
412 	KINFO *k;
413 	VAR *v;
414 {
415 	extern int sumrusage;
416 	long secs;
417 	long psecs;	/* "parts" of a second. first micro, then centi */
418 	char obuff[128];
419 
420 	if (k->ki_p->p_stat == SZOMB || k->ki_u == NULL) {
421 		secs = 0;
422 		psecs = 0;
423 	} else {
424 		secs = k->ki_p->p_utime.tv_sec +
425 			k->ki_p->p_stime.tv_sec;
426 		psecs = k->ki_p->p_utime.tv_usec +
427 			k->ki_p->p_stime.tv_usec;
428 		if (sumrusage) {
429 			secs += k->ki_u->u_cru.ru_utime.tv_sec +
430 				k->ki_u->u_cru.ru_stime.tv_sec;
431 			psecs += k->ki_u->u_cru.ru_utime.tv_usec +
432 				k->ki_u->u_cru.ru_stime.tv_usec;
433 		}
434 		/*
435 		 * round and scale to 100's
436 		 */
437 		psecs = (psecs + 5000) / 10000;
438 		secs += psecs / 100;
439 		psecs = psecs % 100;
440 	}
441 	(void) sprintf(obuff, "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
442 	(void) printf("%*s", v->width, obuff);
443 }
444 
445 double
446 getpcpu(k)
447 	KINFO *k;
448 {
449 	extern fixpt_t ccpu;
450 	extern int fscale, nlistread, rawcpu;
451 	struct proc *p;
452 	static int failure;
453 
454 	if (!nlistread)
455 		failure = donlist();
456 	if (failure)
457 		return (0.0);
458 
459 	p = k->ki_p;
460 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
461 
462 	/* XXX - I don't like this */
463 	if (p->p_time == 0 || (p->p_stat == SZOMB) || (p->p_flag & SLOAD) == 0)
464 		return (0.0);
465 	if (rawcpu)
466 		return (100.0 * fxtofl(p->p_pctcpu));
467 	return (100.0 * fxtofl(p->p_pctcpu) /
468 		(1.0 - exp(p->p_time * log(fxtofl(ccpu)))));
469 }
470 
471 pcpu(k, v)
472 	KINFO *k;
473 	VAR *v;
474 {
475 	(void) printf("%*.1f", v->width, getpcpu(k));
476 }
477 
478 double
479 getpmem(k)
480 	KINFO *k;
481 {
482 	extern int mempages, nlistread;
483 	static int failure;
484 	struct proc *p;
485 	struct eproc *e;
486 	double fracmem;
487 	int szptudot;
488 
489 	if (!nlistread)
490 		failure = donlist();
491 	if (failure)
492 		return (0.0);
493 
494 	p = k->ki_p;
495 	e = k->ki_e;
496 	if ((p->p_flag & SLOAD) == 0 || (p->p_stat == SZOMB))
497 		return (0.0);
498 #ifndef NEWVM
499 	szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize));
500 	fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/mempages;
501 	if (p->p_textp && e->e_xccount)
502 		fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/mempages;
503 #else /* NEWVM */
504 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
505 	szptudot = UPAGES;
506 	/* XXX don't have info about shared */
507 	fracmem = ((float)e->e_vm.vm_rssize + szptudot)/CLSIZE/mempages;
508 #endif /* NEWVM */
509 	return (100.0 * fracmem);
510 }
511 
512 pmem(k, v)
513 	KINFO *k;
514 	VAR *v;
515 {
516 	(void) printf("%*.1f", v->width, getpmem(k));
517 }
518 
519 pagein(k, v)
520 	KINFO *k;
521 	VAR *v;
522 {
523 	(void) printf("%*d", v->width, k->ki_u ? k->ki_u->u_ru.ru_majflt : 0);
524 }
525 
526 maxrss(k, v)
527 	KINFO *k;
528 	VAR *v;
529 {
530 #ifndef NEWVM	/* not yet */
531 	if (k->ki_p->p_maxrss != (RLIM_INFINITY/NBPG))
532 		(void) printf("%*d", v->width, pgtok(k->ki_p->p_maxrss));
533 	else
534 #endif /* NEWVM */
535 		(void) printf("%*s", v->width, "-");
536 }
537 
538 tsize(k, v)
539 	KINFO *k;
540 	VAR *v;
541 {
542 #ifndef NEWVM
543 	(void) printf("%*d", v->width, pgtok(k->ki_e->e_xsize));
544 #else /* NEWVM */
545 	(void) printf("%*d", v->width, pgtok(k->ki_e->e_vm.vm_tsize));
546 #endif /* NEWVM */
547 }
548 
549 #ifndef NEWVM
550 trss(k, v)
551 	KINFO *k;
552 	VAR *v;
553 {
554 	(void) printf("%*d", v->width, pgtok(k->ki_e->e_xrssize));
555 }
556 #endif /* NEWVM */
557 
558 /*
559  * Generic output routines.  Print fields from various prototype
560  * structures.
561  */
562 pvar(k, v)
563 	KINFO *k;
564 	VAR *v;
565 {
566 	printval((char *)((char *)k->ki_p + v->off), v);
567 }
568 
569 evar(k, v)
570 	KINFO *k;
571 	VAR *v;
572 {
573 	printval((char *)((char *)k->ki_e + v->off), v);
574 }
575 
576 uvar(k, v)
577 	KINFO *k;
578 	VAR *v;
579 {
580 	if (k->ki_u)
581 		printval((char *)((char *)k->ki_u + v->off), v);
582 	else
583 		(void) printf("%*s", v->width, "-");
584 }
585 
586 rvar(k, v)
587 	KINFO *k;
588 	VAR *v;
589 {
590 	if (k->ki_u)
591 		printval((char *)((char *)(&k->ki_u->u_ru) + v->off), v);
592 	else
593 		(void) printf("%*s", v->width, "-");
594 }
595 
596 printval(bp, v)
597 	char *bp;
598 	VAR *v;
599 {
600 	static char ofmt[32] = "%";
601 	register char *cp = ofmt+1, *fcp = v->fmt;
602 
603 	if (v->flag & LJUST)
604 		*cp++ = '-';
605 	*cp++ = '*';
606 	while (*cp++ = *fcp++);
607 
608 	switch (v->type) {
609 	case CHAR:
610 		(void) printf(ofmt, v->width, *(char *)bp);
611 		break;
612 	case UCHAR:
613 		(void) printf(ofmt, v->width, *(u_char *)bp);
614 		break;
615 	case SHORT:
616 		(void) printf(ofmt, v->width, *(short *)bp);
617 		break;
618 	case USHORT:
619 		(void) printf(ofmt, v->width, *(u_short *)bp);
620 		break;
621 	case LONG:
622 		(void) printf(ofmt, v->width, *(long *)bp);
623 		break;
624 	case ULONG:
625 		(void) printf(ofmt, v->width, *(u_long *)bp);
626 		break;
627 	case KPTR:
628 		(void) printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
629 		break;
630 	default:
631 		err("unknown type %d", v->type);
632 	}
633 }
634