xref: /dragonfly/bin/ps/print.c (revision 23265324)
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  * @(#)print.c	8.6 (Berkeley) 4/16/94
34  * $FreeBSD: src/bin/ps/print.c,v 1.36.2.4 2002/11/30 13:00:14 tjr Exp $
35  * $DragonFly: src/bin/ps/print.c,v 1.31 2007/02/18 16:15:23 corecode Exp $
36  */
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42 
43 #include <sys/ucred.h>
44 #include <sys/user.h>
45 #include <sys/sysctl.h>
46 #include <sys/rtprio.h>
47 #include <vm/vm.h>
48 
49 #include <err.h>
50 #include <langinfo.h>
51 #include <locale.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 static const char *make_printable(const char *str);
64 
65 void
66 printheader(void)
67 {
68 	const VAR *v;
69 	struct varent *vent;
70 	int allempty;
71 
72 	allempty = 1;
73 	STAILQ_FOREACH(vent, &var_head, link) {
74 		if (*vent->header != '\0') {
75 			allempty = 0;
76 			break;
77 		}
78 	}
79 	if (allempty)
80 		return;
81 	STAILQ_FOREACH(vent, &var_head, link) {
82 		v = vent->var;
83 		if (v->flag & LJUST) {
84 			if (STAILQ_NEXT(vent, link) == NULL)	/* last one */
85 				printf("%s", vent->header);
86 			else
87 				printf("%-*s", vent->width, vent->header);
88 		} else
89 			printf("%*s", vent->width, vent->header);
90 		if (STAILQ_NEXT(vent, link) != NULL)
91 			putchar(' ');
92 	}
93 	putchar('\n');
94 }
95 
96 void
97 command(const KINFO *k, const struct varent *vent)
98 {
99 	const VAR *v;
100 	int left;
101 	char *cp, *vis_env, *vis_args;
102 
103 	v = vent->var;
104 
105 	if (cflag) {
106 		/* Don't pad the last field. */
107 		if (STAILQ_NEXT(vent, link) == NULL)
108 			printf("%s", make_printable(KI_PROC(k, comm)));
109 		else
110 			printf("%-*s", vent->width,
111 				make_printable(KI_PROC(k, comm)));
112 		return;
113 	}
114 
115 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
116 		err(1, NULL);
117 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
118 	if (k->ki_env) {
119 		if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
120 			err(1, NULL);
121 		strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
122 	} else
123 		vis_env = NULL;
124 
125 	if (STAILQ_NEXT(vent, link) == NULL) {
126 		/* last field */
127 		if (termwidth == UNLIMITED) {
128 			if (vis_env)
129 				printf("%s ", vis_env);
130 			printf("%s", vis_args);
131 		} else {
132 			left = termwidth - (totwidth - vent->width);
133 			if (left < 1) /* already wrapped, just use std width */
134 				left = vent->width;
135 			if ((cp = vis_env) != NULL) {
136 				while (--left >= 0 && *cp)
137 					putchar(*cp++);
138 				if (--left >= 0)
139 					putchar(' ');
140 			}
141 			for (cp = vis_args; --left >= 0 && *cp != '\0';)
142 				putchar(*cp++);
143 		}
144 	} else
145 		/* XXX env? */
146 		printf("%-*.*s", vent->width, vent->width, vis_args);
147 	free(vis_args);
148 	if (vis_env != NULL)
149 		free(vis_env);
150 }
151 
152 void
153 ucomm(const KINFO *k, const struct varent *vent)
154 {
155 	printf("%-*s", vent->width, make_printable(KI_PROC(k, comm)));
156 }
157 
158 void
159 logname(const KINFO *k, const struct varent *vent)
160 {
161 	const char *s = KI_PROC(k, login);
162 
163 	printf("%-*s", vent->width, *s != '\0' ? s : "-");
164 }
165 
166 void
167 state(const KINFO *k, const struct varent *vent)
168 {
169 	int flag;
170 	char *cp;
171 	char buf[16];
172 
173 	flag = KI_PROC(k, flags);
174 	cp = buf;
175 
176 	switch (KI_PROC(k, stat)) {
177 
178 	case SSTOP:
179 		*cp = 'T';
180 		break;
181 
182 	case SACTIVE:
183 		switch (KI_LWP(k, stat)) {
184 		case LSSLEEP:
185 			if (KI_LWP(k, flags) & LWP_SINTR)	/* interruptable (long) */
186 				*cp = KI_LWP(k, slptime) >= MAXSLP ? 'I' : 'S';
187 			else if (KI_LWP(k, tdflags) & TDF_SINTR)
188 				*cp = 'S';
189 			else
190 				*cp = 'D';
191 			break;
192 
193 		case LSRUN:
194 			*cp = 'R';
195 			if (KI_LWP(k, tdflags) & TDF_RUNNING) {
196 			    ++cp;
197 			    sprintf(cp, "%d", KI_LWP(k, cpuid));
198 			    while (cp[1])
199 				++cp;
200 			}
201 			break;
202 
203 		case LSSTOP:
204 			/* shouldn't happen anyways */
205 			*cp = 'T';
206 			break;
207 		}
208 		break;
209 
210 	case SZOMB:
211 		*cp = 'Z';
212 		break;
213 
214 	default:
215 		*cp = '?';
216 	}
217 
218 	cp++;
219 	if (flag & P_SWAPPEDOUT)
220 		*cp++ = 'W';
221 	if (KI_PROC(k, nice) < NZERO)
222 		*cp++ = '<';
223 	else if (KI_PROC(k, nice) > NZERO)
224 		*cp++ = 'N';
225 	if (flag & P_TRACED)
226 		*cp++ = 'X';
227 	if (flag & P_WEXIT && KI_PROC(k, stat) != SZOMB)
228 		*cp++ = 'E';
229 	if (flag & P_PPWAIT)
230 		*cp++ = 'V';
231 	if ((flag & P_SYSTEM) || KI_PROC(k, lock) > 0)
232 		*cp++ = 'L';
233 	if (numcpus > 1 && KI_LWP(k, mpcount) == 0)
234 		*cp++ = 'M';
235 	if (flag & P_JAILED)
236 		*cp++ = 'J';
237 	if (KI_PROC(k, auxflags) & KI_SLEADER)
238 		*cp++ = 's';
239 	if ((flag & P_CONTROLT) && KI_PROC(k, pgid) == KI_PROC(k, tpgid))
240 		*cp++ = '+';
241 	*cp = '\0';
242 	printf("%-*s", vent->width, buf);
243 }
244 
245 /*
246  * Normalized priority (lower is better).  For pure threads
247  * output a negated LWKT priority (so lower still means better).
248  *
249  * XXX bsd4 scheduler specific.
250  */
251 void
252 pri(const KINFO *k, const struct varent *vent)
253 {
254 	if (KI_LWP(k, pid) != -1)
255 	    printf("%*d", vent->width, KI_LWP(k, prio));
256 	else
257 	    printf("%*d", vent->width, -(KI_LWP(k, tdprio) & TDPRI_MASK));
258 }
259 
260 void
261 tdpri(const KINFO *k, const struct varent *vent)
262 {
263 	char buf[32];
264 	int val = KI_LWP(k, tdprio);
265 
266 	snprintf(buf, sizeof(buf), "%02d/%d", val & TDPRI_MASK, val / TDPRI_CRIT);
267 	printf("%*s", vent->width, buf);
268 }
269 
270 void
271 uname(const KINFO *k, const struct varent *vent)
272 {
273 	printf("%-*s", vent->width,
274 	       user_from_uid(KI_PROC(k, uid), 0));
275 }
276 
277 int
278 s_uname(const KINFO *k)
279 {
280 	return (strlen(user_from_uid(KI_PROC(k, uid), 0)));
281 }
282 
283 void
284 runame(const KINFO *k, const struct varent *vent)
285 {
286 	printf("%-*s", vent->width,
287 	       user_from_uid(KI_PROC(k, ruid), 0));
288 }
289 
290 int
291 s_runame(const KINFO *k)
292 {
293 	return (strlen(user_from_uid(KI_PROC(k, ruid), 0)));
294 }
295 
296 void
297 tdev(const KINFO *k, const struct varent *vent)
298 {
299 	dev_t dev;
300 	char buff[16];
301 
302 	dev = KI_PROC(k, tdev);
303 	if (dev == NODEV)
304 		printf("%*s", vent->width, "??");
305 	else {
306 		snprintf(buff, sizeof(buff), "%d/%d", major(dev), minor(dev));
307 		printf("%*s", vent->width, buff);
308 	}
309 }
310 
311 void
312 tname(const KINFO *k, const struct varent *vent)
313 {
314 	dev_t dev;
315 	const char *ttname;
316 
317 	dev = KI_PROC(k, tdev);
318 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
319 		printf("%*s ", vent->width-1, "??");
320 	else {
321 		if (strncmp(ttname, "tty", 3) == 0 ||
322 		    strncmp(ttname, "cua", 3) == 0)
323 			ttname += 3;
324 		printf("%*.*s%c", vent->width-1, vent->width-1, ttname,
325 			KI_PROC(k, auxflags) & KI_CTTY ? ' ' : '-');
326 	}
327 }
328 
329 void
330 longtname(const KINFO *k, const struct varent *vent)
331 {
332 	dev_t dev;
333 	const char *ttname;
334 
335 	dev = KI_PROC(k, tdev);
336 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
337 		printf("%-*s", vent->width, "??");
338 	else
339 		printf("%-*s", vent->width, ttname);
340 }
341 
342 void
343 started(const KINFO *k, const struct varent *vent)
344 {
345 	static time_t now;
346 	time_t then;
347 	struct tm *tp;
348 	char buf[100];
349 	static int  use_ampm = -1;
350 
351 	if (use_ampm < 0)
352 		use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
353 
354 	then = KI_PROC(k, start).tv_sec;
355 	if (then < btime.tv_sec) {
356 		then = btime.tv_sec;
357 	}
358 
359 	tp = localtime(&then);
360 	if (!now)
361 		time(&now);
362 	if (now - then < 24 * 3600) {
363 		strftime(buf, sizeof(buf) - 1,
364 		use_ampm ? "%l:%M%p" : "%k:%M  ", tp);
365 	} else if (now - then < 7 * 86400) {
366 		strftime(buf, sizeof(buf) - 1,
367 		use_ampm ? "%a%I%p" : "%a%H  ", tp);
368 	} else
369 		strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
370 	printf("%-*s", vent->width, buf);
371 }
372 
373 void
374 lstarted(const KINFO *k, const struct varent *vent)
375 {
376 	time_t then;
377 	char buf[100];
378 
379 	then = KI_PROC(k, start).tv_sec;
380 	strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
381 	printf("%-*s", vent->width, buf);
382 }
383 
384 void
385 wchan(const KINFO *k, const struct varent *vent)
386 {
387 	if (KI_LWP(k, wchan)) {
388 		if (*KI_LWP(k, wmesg) != '\0')
389 			printf("%-*.*s", vent->width, vent->width,
390 			       KI_LWP(k, wmesg));
391 		else
392 			printf("%-*lx", vent->width,
393 			       (long)KI_LWP(k, wchan));
394 	} else
395 		printf("%-*s", vent->width, "-");
396 }
397 
398 #ifndef pgtok
399 #define pgtok(a)        (((a)*getpagesize())/1024)
400 #endif
401 
402 void
403 vsize(const KINFO *k, const struct varent *vent)
404 {
405 	printf("%*d", vent->width, (KI_PROC(k, vm_map_size)/1024));
406 }
407 
408 void
409 rssize(const KINFO *k, const struct varent *vent)
410 {
411 	/* XXX don't have info about shared */
412 	printf("%*lu", vent->width, (u_long)pgtok(KI_PROC(k, vm_rssize)));
413 }
414 
415 void
416 p_rssize(const KINFO *k, const struct varent *vent)	/* doesn't account for text */
417 {
418 	printf("%*ld", vent->width, (long)pgtok(KI_PROC(k, vm_rssize)));
419 }
420 
421 void
422 cputime(const KINFO *k, const struct varent *vent)
423 {
424 	long secs;
425 	long psecs;	/* "parts" of a second. first micro, then centi */
426 	u_int64_t timeus;
427 	char obuff[128];
428 	static char decimal_point = '\0';
429 
430 	if (decimal_point == '\0')
431 		decimal_point = localeconv()->decimal_point[0];
432 
433 	/*
434 	 * This counts time spent handling interrupts.  We could
435 	 * fix this, but it is not 100% trivial (and interrupt
436 	 * time fractions only work on the sparc anyway).	XXX
437 	 */
438 	timeus = KI_LWP(k, uticks) + KI_LWP(k, sticks) +
439 		KI_LWP(k, iticks);
440 	secs = timeus / 1000000;
441 	psecs = timeus % 1000000;
442 	if (sumrusage) {
443 		secs += KI_PROC(k, cru).ru_utime.tv_sec +
444 			KI_PROC(k, cru).ru_stime.tv_sec;
445 		psecs += KI_PROC(k, cru).ru_utime.tv_usec +
446 			KI_PROC(k, cru).ru_stime.tv_usec;
447 	}
448 	/*
449 	 * round and scale to 100's
450 	 */
451 	psecs = (psecs + 5000) / 10000;
452 	secs += psecs / 100;
453 	psecs = psecs % 100;
454 	snprintf(obuff, sizeof(obuff),
455 	    "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs);
456 	printf("%*s", vent->width, obuff);
457 }
458 
459 double
460 getpcpu(const KINFO *k)
461 {
462 	static int failure;
463 
464 	if (!nlistread)
465 		failure = donlist();
466 	if (failure)
467 		return (0.0);
468 
469 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
470 
471 	/* XXX - I don't like this */
472 	if (KI_PROC(k, swtime) == 0 || (KI_PROC(k, flags) & P_SWAPPEDOUT))
473 		return (0.0);
474 	if (rawcpu)
475 		return (100.0 * fxtofl(KI_LWP(k, pctcpu)));
476 	return (100.0 * fxtofl(KI_LWP(k, pctcpu)) /
477 		(1.0 - exp(KI_PROC(k, swtime) * log(fxtofl(ccpu)))));
478 }
479 
480 void
481 pcpu(const KINFO *k, const struct varent *vent)
482 {
483 	printf("%*.1f", vent->width, getpcpu(k));
484 }
485 
486 void
487 pnice(const KINFO *k, const struct varent *vent)
488 {
489 	int niceval;
490 
491 	switch (KI_LWP(k, rtprio).type) {
492 	case RTP_PRIO_REALTIME:
493 		niceval = PRIO_MIN - 1 - RTP_PRIO_MAX + KI_LWP(k, rtprio).prio;
494 		break;
495 	case RTP_PRIO_IDLE:
496 		niceval = PRIO_MAX + 1 + KI_LWP(k, rtprio).prio;
497 		break;
498 	case RTP_PRIO_THREAD:
499 		niceval = PRIO_MIN - 1 - RTP_PRIO_MAX - KI_LWP(k, rtprio).prio;
500 		break;
501 	default:
502 		niceval = KI_PROC(k, nice) - NZERO;
503 		break;
504 	}
505 	printf("%*d", vent->width, niceval);
506 }
507 
508 
509 double
510 getpmem(const KINFO *k)
511 {
512 	static int failure;
513 	double fracmem;
514 	int szptudot;
515 
516 	if (!nlistread)
517 		failure = donlist();
518 	if (failure)
519 		return (0.0);
520 
521 	if (KI_PROC(k, flags) & P_SWAPPEDOUT)
522 		return (0.0);
523 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
524 	szptudot = UPAGES;
525 	/* XXX don't have info about shared */
526 	fracmem = ((float)KI_PROC(k, vm_rssize) + szptudot)/mempages;
527 	return (100.0 * fracmem);
528 }
529 
530 void
531 pmem(const KINFO *k, const struct varent *vent)
532 {
533 	printf("%*.1f", vent->width, getpmem(k));
534 }
535 
536 void
537 pagein(const KINFO *k, const struct varent *vent)
538 {
539 	printf("%*ld", vent->width, KI_LWP(k, ru).ru_majflt);
540 }
541 
542 /* ARGSUSED */
543 void
544 maxrss(const KINFO *k __unused, const struct varent *vent)
545 {
546 	printf("%*ld", vent->width, KI_PROC(k, ru).ru_maxrss);
547 }
548 
549 void
550 tsize(const KINFO *k, const struct varent *vent)
551 {
552 	printf("%*ld", vent->width, (long)pgtok(KI_PROC(k, vm_tsize)));
553 }
554 
555 void
556 rtprior(const KINFO *k, const struct varent *vent)
557 {
558 	struct rtprio *prtp;
559 	char str[8];
560 	unsigned prio, type;
561 
562 	prtp = &KI_LWP(k, rtprio);
563 	prio = prtp->prio;
564 	type = prtp->type;
565 	switch (type) {
566 	case RTP_PRIO_REALTIME:
567 		snprintf(str, sizeof(str), "real:%u", prio);
568 		break;
569 	case RTP_PRIO_NORMAL:
570 		strncpy(str, "normal", sizeof(str));
571 		break;
572 	case RTP_PRIO_IDLE:
573 		snprintf(str, sizeof(str), "idle:%u", prio);
574 		break;
575 	default:
576 		snprintf(str, sizeof(str), "%u:%u", type, prio);
577 		break;
578 	}
579 	str[sizeof(str) - 1] = '\0';
580 	printf("%*s", vent->width, str);
581 }
582 
583 /*
584  * Generic output routines.  Print fields from various prototype
585  * structures.
586  */
587 static void
588 printval(const char *bp, const struct varent *vent)
589 {
590 	static char ofmt[32] = "%";
591 	const char *fcp;
592 	char *cp;
593 
594 	cp = ofmt + 1;
595 	fcp = vent->var->fmt;
596 	if (vent->var->flag & LJUST)
597 		*cp++ = '-';
598 	*cp++ = '*';
599 	while ((*cp++ = *fcp++));
600 
601 	switch (vent->var->type) {
602 	case CHAR:
603 		printf(ofmt, vent->width, *(const char *)bp);
604 		break;
605 	case UCHAR:
606 		printf(ofmt, vent->width, *(const u_char *)bp);
607 		break;
608 	case SHORT:
609 		printf(ofmt, vent->width, *(const short *)bp);
610 		break;
611 	case USHORT:
612 		printf(ofmt, vent->width, *(const u_short *)bp);
613 		break;
614 	case INT:
615 		printf(ofmt, vent->width, *(const int *)bp);
616 		break;
617 	case UINT:
618 		printf(ofmt, vent->width, *(const u_int *)bp);
619 		break;
620 	case LONG:
621 		printf(ofmt, vent->width, *(const long *)bp);
622 		break;
623 	case ULONG:
624 		printf(ofmt, vent->width, *(const u_long *)bp);
625 		break;
626 	case KPTR:
627 		printf(ofmt, vent->width, *(const u_long *)bp);
628 		break;
629 	default:
630 		errx(1, "unknown type %d", vent->var->type);
631 	}
632 }
633 
634 void
635 pvar(const KINFO *k, const struct varent *vent)
636 {
637 	printval((char *)((char *)k->ki_proc + vent->var->off), vent);
638 }
639 
640 void
641 lpest(const KINFO *k, const struct varent *vent)
642 {
643 	int val;
644 
645 	val = *(int *)((char *)&k->ki_proc->kp_lwp + vent->var->off);
646 	val = val / 128;
647 	printval((char *)&val, vent);
648 }
649 
650 
651 void
652 lpvar(const KINFO *k, const struct varent *vent)
653 {
654 	printval((char *)((char *)&k->ki_proc->kp_lwp + vent->var->off), vent);
655 }
656 
657 void
658 rvar(const KINFO *k, const struct varent *vent)
659 {
660 	printval(((const char *)&KI_LWP(k, ru) + vent->var->off), vent);
661 }
662 
663 static const char *
664 make_printable(const char *str)
665 {
666     static char *cpy;
667     int len;
668 
669     if (cpy)
670 	free(cpy);
671     len = strlen(str);
672     if ((cpy = malloc(len * 4 + 1)) == NULL)
673 	err(1, NULL);
674     strvis(cpy, str, VIS_TAB | VIS_NL | VIS_NOSLASH);
675     return(cpy);
676 }
677