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