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