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