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