xref: /freebsd/bin/ps/print.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*-
2  * Copyright (c) 1990, 1993, 1994
3  *	The Regents of the University of California.  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  *	$Id: print.c,v 1.4 1994/10/02 08:33:30 davidg Exp $
34  */
35 
36 #ifndef lint
37 static char sccsid[] = "@(#)print.c	8.6 (Berkeley) 4/16/94";
38 #endif /* not lint */
39 
40 #include <sys/param.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #include <sys/proc.h>
44 #include <sys/stat.h>
45 
46 #ifdef P_PPWAIT
47 #define NEWVM
48 #endif
49 
50 #ifdef NEWVM
51 #include <sys/ucred.h>
52 #include <sys/sysctl.h>
53 #include <vm/vm.h>
54 #else
55 #include <machine/pte.h>
56 #include <sys/vmparam.h>
57 #include <sys/vm.h>
58 #endif
59 
60 #include <err.h>
61 #include <math.h>
62 #include <nlist.h>
63 #include <stddef.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <vis.h>
68 #include <tzfile.h>
69 
70 #include "ps.h"
71 
72 void
73 printheader()
74 {
75 	VAR *v;
76 	struct varent *vent;
77 
78 	for (vent = vhead; vent; vent = vent->next) {
79 		v = vent->var;
80 		if (v->flag & LJUST) {
81 			if (vent->next == NULL)	/* last one */
82 				(void)printf("%s", v->header);
83 			else
84 				(void)printf("%-*s", v->width, v->header);
85 		} else
86 			(void)printf("%*s", v->width, v->header);
87 		if (vent->next != NULL)
88 			(void)putchar(' ');
89 	}
90 	(void)putchar('\n');
91 }
92 
93 void
94 command(k, ve)
95 	KINFO *k;
96 	VARENT *ve;
97 {
98 	VAR *v;
99 	int left;
100 	char *cp, *vis_env, *vis_args;
101 
102 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
103 		err(1, NULL);
104 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
105 	if (k->ki_env) {
106 		if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
107 			err(1, NULL);
108 		strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
109 	} else
110 		vis_env = NULL;
111 
112 	v = ve->var;
113 	if (ve->next == NULL) {
114 		/* last field */
115 		if (termwidth == UNLIMITED) {
116 			if (vis_env)
117 				(void)printf("%s ", vis_env);
118 			(void)printf("%s", vis_args);
119 		} else {
120 			left = termwidth - (totwidth - v->width);
121 			if (left < 1) /* already wrapped, just use std width */
122 				left = v->width;
123 			if ((cp = vis_env) != NULL) {
124 				while (--left >= 0 && *cp)
125 					(void)putchar(*cp++);
126 				if (--left >= 0)
127 					putchar(' ');
128 			}
129 			for (cp = vis_args; --left >= 0 && *cp != '\0';)
130 				(void)putchar(*cp++);
131 		}
132 	} else
133 		/* XXX env? */
134 		(void)printf("%-*.*s", v->width, v->width, vis_args);
135 	free(vis_args);
136 	if (vis_env != NULL)
137 		free(vis_env);
138 }
139 
140 void
141 ucomm(k, ve)
142 	KINFO *k;
143 	VARENT *ve;
144 {
145 	VAR *v;
146 
147 	v = ve->var;
148 	(void)printf("%-*s", v->width, KI_PROC(k)->p_comm);
149 }
150 
151 void
152 logname(k, ve)
153 	KINFO *k;
154 	VARENT *ve;
155 {
156 	VAR *v;
157 
158 	v = ve->var;
159 #ifndef NEWVM
160 	(void)printf("%-*s", v->width, KI_PROC(k)->p_logname);
161 #else
162 	(void)printf("%-*s", v->width, KI_EPROC(k)->e_login);
163 #endif
164 }
165 
166 void
167 state(k, ve)
168 	KINFO *k;
169 	VARENT *ve;
170 {
171 	struct proc *p;
172 	int flag;
173 	char *cp;
174 	VAR *v;
175 	char buf[16];
176 
177 	v = ve->var;
178 	p = KI_PROC(k);
179 	flag = p->p_flag;
180 	cp = buf;
181 
182 	switch (p->p_stat) {
183 
184 	case SSTOP:
185 		*cp = 'T';
186 		break;
187 
188 	case SSLEEP:
189 		if (flag & P_SINTR)	/* interuptable (long) */
190 			*cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
191 		else
192 			*cp = 'D';
193 		break;
194 
195 	case SRUN:
196 	case SIDL:
197 		*cp = 'R';
198 		break;
199 
200 	case SZOMB:
201 		*cp = 'Z';
202 		break;
203 
204 	default:
205 		*cp = '?';
206 	}
207 	cp++;
208 	if (flag & P_INMEM) {
209 #ifndef NEWVM
210 		if (p->p_rssize > p->p_maxrss)
211 			*cp++ = '>';
212 #endif
213 	} else
214 		*cp++ = 'W';
215 	if (p->p_nice < NZERO)
216 		*cp++ = '<';
217 	else if (p->p_nice > NZERO)
218 		*cp++ = 'N';
219 #ifndef NEWVM
220 	if (flag & SUANOM)
221 		*cp++ = 'A';
222 	else if (flag & SSEQL)
223 		*cp++ = 'S';
224 #endif
225 	if (flag & P_TRACED)
226 		*cp++ = 'X';
227 	if (flag & P_WEXIT && p->p_stat != SZOMB)
228 		*cp++ = 'E';
229 #ifdef NEWVM
230 	if (flag & P_PPWAIT)
231 #else
232 	if (flag & SVFORK)
233 #endif
234 		*cp++ = 'V';
235 #ifdef NEWVM
236 	if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO))
237 #else
238 	if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO))
239 #endif
240 		*cp++ = 'L';
241 	if (KI_EPROC(k)->e_flag & EPROC_SLEADER)
242 		*cp++ = 's';
243 	if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid)
244 		*cp++ = '+';
245 	*cp = '\0';
246 	(void)printf("%-*s", v->width, buf);
247 }
248 
249 void
250 pri(k, ve)
251 	KINFO *k;
252 	VARENT *ve;
253 {
254 	VAR *v;
255 
256 	v = ve->var;
257 	(void)printf("%*d", v->width, KI_PROC(k)->p_priority - PZERO);
258 }
259 
260 void
261 uname(k, ve)
262 	KINFO *k;
263 	VARENT *ve;
264 {
265 	VAR *v;
266 
267 	v = ve->var;
268 #ifndef NEWVM
269 	(void)printf("%-*s",
270 	    (int)v->width, user_from_uid(KI_PROC(k)->p_uid, 0));
271 #else
272 	(void)printf("%-*s",
273 	    (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0));
274 #endif
275 }
276 
277 void
278 runame(k, ve)
279 	KINFO *k;
280 	VARENT *ve;
281 {
282 	VAR *v;
283 
284 	v = ve->var;
285 #ifndef NEWVM
286 	(void)printf("%-*s",
287 	    (int)v->width, user_from_uid(KI_PROC(k)->p_ruid, 0));
288 #else
289 	(void)printf("%-*s",
290 	    (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0));
291 #endif
292 }
293 
294 void
295 tdev(k, ve)
296 	KINFO *k;
297 	VARENT *ve;
298 {
299 	VAR *v;
300 	dev_t dev;
301 	char buff[16];
302 
303 	v = ve->var;
304 	dev = KI_EPROC(k)->e_tdev;
305 	if (dev == NODEV)
306 		(void)printf("%*s", v->width, "??");
307 	else {
308 		(void)snprintf(buff, sizeof(buff),
309 		    "%d/%d", major(dev), minor(dev));
310 		(void)printf("%*s", v->width, buff);
311 	}
312 }
313 
314 void
315 tname(k, ve)
316 	KINFO *k;
317 	VARENT *ve;
318 {
319 	VAR *v;
320 	dev_t dev;
321 	char *ttname;
322 
323 	v = ve->var;
324 	dev = KI_EPROC(k)->e_tdev;
325 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
326 		(void)printf("%-*s", v->width, "??");
327 	else {
328 		if (strncmp(ttname, "tty", 3) == 0 ||
329 		    strncmp(ttname, "cua", 3) == 0)
330 			ttname += 3;
331 		(void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
332 			KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-');
333 	}
334 }
335 
336 void
337 longtname(k, ve)
338 	KINFO *k;
339 	VARENT *ve;
340 {
341 	VAR *v;
342 	dev_t dev;
343 	char *ttname;
344 
345 	v = ve->var;
346 	dev = KI_EPROC(k)->e_tdev;
347 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
348 		(void)printf("%-*s", v->width, "??");
349 	else
350 		(void)printf("%-*s", v->width, ttname);
351 }
352 
353 void
354 started(k, ve)
355 	KINFO *k;
356 	VARENT *ve;
357 {
358 	VAR *v;
359 	static time_t now;
360 	struct tm *tp;
361 	char buf[100];
362 
363 	v = ve->var;
364 	if (!k->ki_u.u_valid) {
365 		(void)printf("%-*s", v->width, "-");
366 		return;
367 	}
368 
369 	tp = localtime(&k->ki_u.u_start.tv_sec);
370 	if (!now)
371 		(void)time(&now);
372 	if (now - k->ki_u.u_start.tv_sec < 24 * SECSPERHOUR) {
373 		/* I *hate* SCCS... */
374 		static char fmt[] = __CONCAT("%l:%", "M%p");
375 		(void)strftime(buf, sizeof(buf) - 1, fmt, tp);
376 	} else if (now - k->ki_u.u_start.tv_sec < 7 * SECSPERDAY) {
377 		/* I *hate* SCCS... */
378 		static char fmt[] = __CONCAT("%a%", "I%p");
379 		(void)strftime(buf, sizeof(buf) - 1, fmt, tp);
380 	} else
381 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
382 	(void)printf("%-*s", v->width, buf);
383 }
384 
385 void
386 lstarted(k, ve)
387 	KINFO *k;
388 	VARENT *ve;
389 {
390 	VAR *v;
391 	char buf[100];
392 
393 	v = ve->var;
394 	if (!k->ki_u.u_valid) {
395 		(void)printf("%-*s", v->width, "-");
396 		return;
397 	}
398 	(void)strftime(buf, sizeof(buf) -1, "%C",
399 	    localtime(&k->ki_u.u_start.tv_sec));
400 	(void)printf("%-*s", v->width, buf);
401 }
402 
403 void
404 wchan(k, ve)
405 	KINFO *k;
406 	VARENT *ve;
407 {
408 	VAR *v;
409 
410 	v = ve->var;
411 	if (KI_PROC(k)->p_wchan) {
412 		if (KI_PROC(k)->p_wmesg)
413 			(void)printf("%-*.*s", v->width, v->width,
414 				      KI_EPROC(k)->e_wmesg);
415 		else
416 			(void)printf("%-*x", v->width,
417 			    (int)KI_PROC(k)->p_wchan &~ KERNBASE);
418 	} else
419 		(void)printf("%-*s", v->width, "-");
420 }
421 
422 #define pgtok(a)        (((a)*NBPG)/1024)
423 
424 void
425 vsize(k, ve)
426 	KINFO *k;
427 	VARENT *ve;
428 {
429 	VAR *v;
430 
431 	v = ve->var;
432 	(void)printf("%*d", v->width,
433 #ifndef NEWVM
434 	    pgtok(KI_PROC(k)->p_dsize +
435 	        KI_PROC(k)->p_ssize + KI_EPROC(k)->e_xsize));
436 #else
437 	    pgtok(KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize +
438 		KI_EPROC(k)->e_vm.vm_tsize));
439 #endif
440 }
441 
442 void
443 rssize(k, ve)
444 	KINFO *k;
445 	VARENT *ve;
446 {
447 	VAR *v;
448 
449 	v = ve->var;
450 #ifndef NEWVM
451 	(void)printf("%*d", v->width,
452 	    pgtok(KI_PROC(k)->p_rssize + (KI_EPROC(k)->e_xccount ?
453 	    (KI_EPROC(k)->e_xrssize / KI_EPROC(k)->e_xccount) : 0)));
454 #else
455 	/* XXX don't have info about shared */
456 	(void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize));
457 #endif
458 }
459 
460 void
461 p_rssize(k, ve)		/* doesn't account for text */
462 	KINFO *k;
463 	VARENT *ve;
464 {
465 	VAR *v;
466 
467 	v = ve->var;
468 #ifndef NEWVM
469 	(void)printf("%*d", v->width, pgtok(KI_PROC(k)->p_rssize));
470 #else
471 	(void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize));
472 #endif
473 }
474 
475 void
476 cputime(k, ve)
477 	KINFO *k;
478 	VARENT *ve;
479 {
480 	VAR *v;
481 	long secs;
482 	long psecs;	/* "parts" of a second. first micro, then centi */
483 	char obuff[128];
484 
485 	v = ve->var;
486 	if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) {
487 		secs = 0;
488 		psecs = 0;
489 	} else {
490 		/*
491 		 * This counts time spent handling interrupts.  We could
492 		 * fix this, but it is not 100% trivial (and interrupt
493 		 * time fractions only work on the sparc anyway).	XXX
494 		 */
495 		secs = KI_PROC(k)->p_rtime.tv_sec;
496 		psecs = KI_PROC(k)->p_rtime.tv_usec;
497 		if (sumrusage) {
498 			secs += k->ki_u.u_cru.ru_utime.tv_sec +
499 				k->ki_u.u_cru.ru_stime.tv_sec;
500 			psecs += k->ki_u.u_cru.ru_utime.tv_usec +
501 				k->ki_u.u_cru.ru_stime.tv_usec;
502 		}
503 		/*
504 		 * round and scale to 100's
505 		 */
506 		psecs = (psecs + 5000) / 10000;
507 		secs += psecs / 100;
508 		psecs = psecs % 100;
509 	}
510 	(void)snprintf(obuff, sizeof(obuff),
511 	    "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
512 	(void)printf("%*s", v->width, obuff);
513 }
514 
515 double
516 getpcpu(k)
517 	KINFO *k;
518 {
519 	struct proc *p;
520 	static int failure;
521 
522 	if (!nlistread)
523 		failure = donlist();
524 	if (failure)
525 		return (0.0);
526 
527 	p = KI_PROC(k);
528 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
529 
530 	/* XXX - I don't like this */
531 	if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
532 		return (0.0);
533 	if (rawcpu)
534 		return (100.0 * fxtofl(p->p_pctcpu));
535 	return (100.0 * fxtofl(p->p_pctcpu) /
536 		(1.0 - exp(p->p_swtime * log(fxtofl(ccpu)))));
537 }
538 
539 void
540 pcpu(k, ve)
541 	KINFO *k;
542 	VARENT *ve;
543 {
544 	VAR *v;
545 
546 	v = ve->var;
547 	(void)printf("%*.1f", v->width, getpcpu(k));
548 }
549 
550 double
551 getpmem(k)
552 	KINFO *k;
553 {
554 	static int failure;
555 	struct proc *p;
556 	struct eproc *e;
557 	double fracmem;
558 	int szptudot;
559 
560 	if (!nlistread)
561 		failure = donlist();
562 	if (failure)
563 		return (0.0);
564 
565 	p = KI_PROC(k);
566 	e = KI_EPROC(k);
567 	if ((p->p_flag & P_INMEM) == 0)
568 		return (0.0);
569 #ifndef NEWVM
570 	szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize));
571 	fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/mempages;
572 	if (p->p_textp && e->e_xccount)
573 		fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/mempages;
574 #else
575 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
576 	szptudot = UPAGES;
577 	/* XXX don't have info about shared */
578 	fracmem = ((float)e->e_vm.vm_rssize + szptudot)/CLSIZE/mempages;
579 #endif
580 	return (100.0 * fracmem);
581 }
582 
583 void
584 pmem(k, ve)
585 	KINFO *k;
586 	VARENT *ve;
587 {
588 	VAR *v;
589 
590 	v = ve->var;
591 	(void)printf("%*.1f", v->width, getpmem(k));
592 }
593 
594 void
595 pagein(k, ve)
596 	KINFO *k;
597 	VARENT *ve;
598 {
599 	VAR *v;
600 
601 	v = ve->var;
602 	(void)printf("%*d", v->width,
603 	    k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0);
604 }
605 
606 void
607 maxrss(k, ve)
608 	KINFO *k;
609 	VARENT *ve;
610 {
611 	VAR *v;
612 
613 	v = ve->var;
614 #ifndef NEWVM	/* not yet */
615 	if (KI_PROC(k)->p_maxrss != (RLIM_INFINITY/NBPG))
616 		(void)printf("%*d", v->width, pgtok(KI_PROC(k)->p_maxrss));
617 	else
618 #endif
619 		(void)printf("%*s", v->width, "-");
620 }
621 
622 void
623 tsize(k, ve)
624 	KINFO *k;
625 	VARENT *ve;
626 {
627 	VAR *v;
628 
629 	v = ve->var;
630 #ifndef NEWVM
631 	(void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_xsize));
632 #else
633 	(void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_tsize));
634 #endif
635 }
636 
637 #ifndef NEWVM
638 void
639 trss(k, ve)
640 	KINFO *k;
641 	VARENT *ve;
642 {
643 	VAR *v;
644 
645 	v = ve->var;
646 	(void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_xrssize));
647 }
648 #endif
649 
650 /*
651  * Generic output routines.  Print fields from various prototype
652  * structures.
653  */
654 static void
655 printval(bp, v)
656 	char *bp;
657 	VAR *v;
658 {
659 	static char ofmt[32] = "%";
660 	char *fcp, *cp;
661 
662 	cp = ofmt + 1;
663 	fcp = v->fmt;
664 	if (v->flag & LJUST)
665 		*cp++ = '-';
666 	*cp++ = '*';
667 	while (*cp++ = *fcp++);
668 
669 	switch (v->type) {
670 	case CHAR:
671 		(void)printf(ofmt, v->width, *(char *)bp);
672 		break;
673 	case UCHAR:
674 		(void)printf(ofmt, v->width, *(u_char *)bp);
675 		break;
676 	case SHORT:
677 		(void)printf(ofmt, v->width, *(short *)bp);
678 		break;
679 	case USHORT:
680 		(void)printf(ofmt, v->width, *(u_short *)bp);
681 		break;
682 	case LONG:
683 		(void)printf(ofmt, v->width, *(long *)bp);
684 		break;
685 	case ULONG:
686 		(void)printf(ofmt, v->width, *(u_long *)bp);
687 		break;
688 	case KPTR:
689 		(void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
690 		break;
691 	default:
692 		errx(1, "unknown type %d", v->type);
693 	}
694 }
695 
696 void
697 pvar(k, ve)
698 	KINFO *k;
699 	VARENT *ve;
700 {
701 	VAR *v;
702 
703 	v = ve->var;
704 	printval((char *)((char *)KI_PROC(k) + v->off), v);
705 }
706 
707 void
708 evar(k, ve)
709 	KINFO *k;
710 	VARENT *ve;
711 {
712 	VAR *v;
713 
714 	v = ve->var;
715 	printval((char *)((char *)KI_EPROC(k) + v->off), v);
716 }
717 
718 void
719 uvar(k, ve)
720 	KINFO *k;
721 	VARENT *ve;
722 {
723 	VAR *v;
724 
725 	v = ve->var;
726 	if (k->ki_u.u_valid)
727 		printval((char *)((char *)&k->ki_u + v->off), v);
728 	else
729 		(void)printf("%*s", v->width, "-");
730 }
731 
732 void
733 rvar(k, ve)
734 	KINFO *k;
735 	VARENT *ve;
736 {
737 	VAR *v;
738 
739 	v = ve->var;
740 	if (k->ki_u.u_valid)
741 		printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v);
742 	else
743 		(void)printf("%*s", v->width, "-");
744 }
745