xref: /freebsd/bin/ps/print.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #if 0
31 #ifndef lint
32 static char sccsid[] = "@(#)print.c	8.6 (Berkeley) 4/16/94";
33 #endif /* not lint */
34 #endif
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 #include <sys/param.h>
40 #include <sys/time.h>
41 #include <sys/resource.h>
42 #include <sys/proc.h>
43 #include <sys/stat.h>
44 
45 #include <sys/mac.h>
46 #include <sys/user.h>
47 #include <sys/sysctl.h>
48 #include <sys/vmmeter.h>
49 
50 #include <err.h>
51 #include <grp.h>
52 #include <langinfo.h>
53 #include <locale.h>
54 #include <math.h>
55 #include <nlist.h>
56 #include <pwd.h>
57 #include <stddef.h>
58 #include <stdint.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <vis.h>
64 #include <libxo/xo.h>
65 
66 #include "ps.h"
67 
68 #define	COMMAND_WIDTH	16
69 #define	ARGUMENTS_WIDTH	16
70 
71 #define	ps_pgtok(a)	(((a) * getpagesize()) / 1024)
72 
73 void
74 printheader(void)
75 {
76 	VAR *v;
77 	struct varent *vent;
78 
79 	STAILQ_FOREACH(vent, &varlist, next_ve)
80 		if (*vent->header != '\0')
81 			break;
82 	if (!vent)
83 		return;
84 
85 	STAILQ_FOREACH(vent, &varlist, next_ve) {
86 		v = vent->var;
87 		if (v->flag & LJUST) {
88 			if (STAILQ_NEXT(vent, next_ve) == NULL)	/* last one */
89 				xo_emit("{T:/%s}", vent->header);
90 			else
91 				xo_emit("{T:/%-*s}", v->width, vent->header);
92 		} else
93 			xo_emit("{T:/%*s}", v->width, vent->header);
94 		if (STAILQ_NEXT(vent, next_ve) != NULL)
95 			xo_emit("{P: }");
96 	}
97 	xo_emit("\n");
98 }
99 
100 char *
101 arguments(KINFO *k, VARENT *ve)
102 {
103 	char *vis_args;
104 
105 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
106 		xo_errx(1, "malloc failed");
107 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
108 
109 	if (STAILQ_NEXT(ve, next_ve) != NULL && strlen(vis_args) > ARGUMENTS_WIDTH)
110 		vis_args[ARGUMENTS_WIDTH] = '\0';
111 
112 	return (vis_args);
113 }
114 
115 char *
116 command(KINFO *k, VARENT *ve)
117 {
118 	char *vis_args, *vis_env, *str;
119 
120 	if (cflag) {
121 		/* If it is the last field, then don't pad */
122 		if (STAILQ_NEXT(ve, next_ve) == NULL) {
123 			asprintf(&str, "%s%s%s%s",
124 			    k->ki_d.prefix ? k->ki_d.prefix : "",
125 			    k->ki_p->ki_comm,
126 			    (showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
127 			    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "");
128 		} else
129 			str = strdup(k->ki_p->ki_comm);
130 
131 		return (str);
132 	}
133 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
134 		xo_errx(1, "malloc failed");
135 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
136 
137 	if (STAILQ_NEXT(ve, next_ve) == NULL) {
138 		/* last field */
139 
140 		if (k->ki_env) {
141 			if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1))
142 			    == NULL)
143 				xo_errx(1, "malloc failed");
144 			strvis(vis_env, k->ki_env,
145 			    VIS_TAB | VIS_NL | VIS_NOSLASH);
146 		} else
147 			vis_env = NULL;
148 
149 		asprintf(&str, "%s%s%s%s",
150 		    k->ki_d.prefix ? k->ki_d.prefix : "",
151 		    vis_env ? vis_env : "",
152 		    vis_env ? " " : "",
153 		    vis_args);
154 
155 		if (vis_env != NULL)
156 			free(vis_env);
157 		free(vis_args);
158 	} else {
159 		/* ki_d.prefix & ki_env aren't shown for interim fields */
160 		str = vis_args;
161 
162 		if (strlen(str) > COMMAND_WIDTH)
163 			str[COMMAND_WIDTH] = '\0';
164 	}
165 
166 	return (str);
167 }
168 
169 char *
170 ucomm(KINFO *k, VARENT *ve)
171 {
172 	char *str;
173 
174 	if (STAILQ_NEXT(ve, next_ve) == NULL) {	/* last field, don't pad */
175 		asprintf(&str, "%s%s%s%s",
176 		    k->ki_d.prefix ? k->ki_d.prefix : "",
177 		    k->ki_p->ki_comm,
178 		    (showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
179 		    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "");
180 	} else {
181 		if (showthreads && k->ki_p->ki_numthreads > 1)
182 			asprintf(&str, "%s/%s", k->ki_p->ki_comm, k->ki_p->ki_tdname);
183 		else
184 			str = strdup(k->ki_p->ki_comm);
185 	}
186 	return (str);
187 }
188 
189 char *
190 tdnam(KINFO *k, VARENT *ve __unused)
191 {
192 	char *str;
193 
194 	if (showthreads && k->ki_p->ki_numthreads > 1)
195 		str = strdup(k->ki_p->ki_tdname);
196 	else
197 		str = strdup("      ");
198 
199 	return (str);
200 }
201 
202 char *
203 logname(KINFO *k, VARENT *ve __unused)
204 {
205 
206 	if (*k->ki_p->ki_login == '\0')
207 		return (NULL);
208 	return (strdup(k->ki_p->ki_login));
209 }
210 
211 char *
212 state(KINFO *k, VARENT *ve __unused)
213 {
214 	long flag, tdflags;
215 	char *cp, *buf;
216 
217 	buf = malloc(16);
218 	if (buf == NULL)
219 		xo_errx(1, "malloc failed");
220 
221 	flag = k->ki_p->ki_flag;
222 	tdflags = k->ki_p->ki_tdflags;	/* XXXKSE */
223 	cp = buf;
224 
225 	switch (k->ki_p->ki_stat) {
226 
227 	case SSTOP:
228 		*cp = 'T';
229 		break;
230 
231 	case SSLEEP:
232 		if (tdflags & TDF_SINTR)	/* interruptable (long) */
233 			*cp = k->ki_p->ki_slptime >= MAXSLP ? 'I' : 'S';
234 		else
235 			*cp = 'D';
236 		break;
237 
238 	case SRUN:
239 	case SIDL:
240 		*cp = 'R';
241 		break;
242 
243 	case SWAIT:
244 		*cp = 'W';
245 		break;
246 
247 	case SLOCK:
248 		*cp = 'L';
249 		break;
250 
251 	case SZOMB:
252 		*cp = 'Z';
253 		break;
254 
255 	default:
256 		*cp = '?';
257 	}
258 	cp++;
259 	if (!(flag & P_INMEM))
260 		*cp++ = 'W';
261 	if (k->ki_p->ki_nice < NZERO)
262 		*cp++ = '<';
263 	else if (k->ki_p->ki_nice > NZERO)
264 		*cp++ = 'N';
265 	if (flag & P_TRACED)
266 		*cp++ = 'X';
267 	if (flag & P_WEXIT && k->ki_p->ki_stat != SZOMB)
268 		*cp++ = 'E';
269 	if (flag & P_PPWAIT)
270 		*cp++ = 'V';
271 	if ((flag & P_SYSTEM) || k->ki_p->ki_lock > 0)
272 		*cp++ = 'L';
273 	if (k->ki_p->ki_kiflag & KI_SLEADER)
274 		*cp++ = 's';
275 	if ((flag & P_CONTROLT) && k->ki_p->ki_pgid == k->ki_p->ki_tpgid)
276 		*cp++ = '+';
277 	if (flag & P_JAILED)
278 		*cp++ = 'J';
279 	*cp = '\0';
280 	return (buf);
281 }
282 
283 #define	scalepri(x)	((x) - PZERO)
284 
285 char *
286 pri(KINFO *k, VARENT *ve __unused)
287 {
288 	char *str;
289 
290 	asprintf(&str, "%d", scalepri(k->ki_p->ki_pri.pri_level));
291 	return (str);
292 }
293 
294 char *
295 upr(KINFO *k, VARENT *ve __unused)
296 {
297 	char *str;
298 
299 	asprintf(&str, "%d", scalepri(k->ki_p->ki_pri.pri_user));
300 	return (str);
301 }
302 #undef scalepri
303 
304 char *
305 uname(KINFO *k, VARENT *ve __unused)
306 {
307 
308 	return (strdup(user_from_uid(k->ki_p->ki_uid, 0)));
309 }
310 
311 char *
312 egroupname(KINFO *k, VARENT *ve __unused)
313 {
314 
315 	return (strdup(group_from_gid(k->ki_p->ki_groups[0], 0)));
316 }
317 
318 char *
319 rgroupname(KINFO *k, VARENT *ve __unused)
320 {
321 
322 	return (strdup(group_from_gid(k->ki_p->ki_rgid, 0)));
323 }
324 
325 char *
326 runame(KINFO *k, VARENT *ve __unused)
327 {
328 
329 	return (strdup(user_from_uid(k->ki_p->ki_ruid, 0)));
330 }
331 
332 char *
333 tdev(KINFO *k, VARENT *ve __unused)
334 {
335 	dev_t dev;
336 	char *str;
337 
338 	dev = k->ki_p->ki_tdev;
339 	if (dev == NODEV)
340 		str = strdup("-");
341 	else
342 		asprintf(&str, "%#jx", (uintmax_t)dev);
343 
344 	return (str);
345 }
346 
347 char *
348 tname(KINFO *k, VARENT *ve __unused)
349 {
350 	dev_t dev;
351 	char *ttname, *str;
352 
353 	dev = k->ki_p->ki_tdev;
354 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
355 		str = strdup("- ");
356 	else {
357 		if (strncmp(ttname, "tty", 3) == 0 ||
358 		    strncmp(ttname, "cua", 3) == 0)
359 			ttname += 3;
360 		if (strncmp(ttname, "pts/", 4) == 0)
361 			ttname += 4;
362 		asprintf(&str, "%s%c", ttname,
363 		    k->ki_p->ki_kiflag & KI_CTTY ? ' ' : '-');
364 	}
365 
366 	return (str);
367 }
368 
369 char *
370 longtname(KINFO *k, VARENT *ve __unused)
371 {
372 	dev_t dev;
373 	const char *ttname;
374 
375 	dev = k->ki_p->ki_tdev;
376 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
377 		ttname = "-";
378 
379 	return (strdup(ttname));
380 }
381 
382 char *
383 started(KINFO *k, VARENT *ve __unused)
384 {
385 	time_t then;
386 	struct tm *tp;
387 	size_t buflen = 100;
388 	char *buf;
389 
390 	if (!k->ki_valid)
391 		return (NULL);
392 
393 	buf = malloc(buflen);
394 	if (buf == NULL)
395 		xo_errx(1, "malloc failed");
396 
397 	then = k->ki_p->ki_start.tv_sec;
398 	tp = localtime(&then);
399 	if (now - k->ki_p->ki_start.tv_sec < 24 * 3600) {
400 		(void)strftime(buf, buflen, "%H:%M  ", tp);
401 	} else if (now - k->ki_p->ki_start.tv_sec < 7 * 86400) {
402 		(void)strftime(buf, buflen, "%a%H  ", tp);
403 	} else
404 		(void)strftime(buf, buflen, "%e%b%y", tp);
405 	return (buf);
406 }
407 
408 char *
409 lstarted(KINFO *k, VARENT *ve __unused)
410 {
411 	time_t then;
412 	char *buf;
413 	size_t buflen = 100;
414 
415 	if (!k->ki_valid)
416 		return (NULL);
417 
418 	buf = malloc(buflen);
419 	if (buf == NULL)
420 		xo_errx(1, "malloc failed");
421 
422 	then = k->ki_p->ki_start.tv_sec;
423 	(void)strftime(buf, buflen, "%c", localtime(&then));
424 	return (buf);
425 }
426 
427 char *
428 lockname(KINFO *k, VARENT *ve __unused)
429 {
430 	char *str;
431 
432 	if (k->ki_p->ki_kiflag & KI_LOCKBLOCK) {
433 		if (k->ki_p->ki_lockname[0] != 0)
434 			str = strdup(k->ki_p->ki_lockname);
435 		else
436 			str = strdup("???");
437 	} else
438 		str = NULL;
439 
440 	return (str);
441 }
442 
443 char *
444 wchan(KINFO *k, VARENT *ve __unused)
445 {
446 	char *str;
447 
448 	if (k->ki_p->ki_wchan) {
449 		if (k->ki_p->ki_wmesg[0] != 0)
450 			str = strdup(k->ki_p->ki_wmesg);
451 		else
452 			asprintf(&str, "%lx", (long)k->ki_p->ki_wchan);
453 	} else
454 		str = NULL;
455 
456 	return (str);
457 }
458 
459 char *
460 nwchan(KINFO *k, VARENT *ve __unused)
461 {
462 	char *str;
463 
464 	if (k->ki_p->ki_wchan)
465 		asprintf(&str, "%0lx", (long)k->ki_p->ki_wchan);
466 	else
467 		str = NULL;
468 
469 	return (str);
470 }
471 
472 char *
473 mwchan(KINFO *k, VARENT *ve __unused)
474 {
475 	char *str;
476 
477 	if (k->ki_p->ki_wchan) {
478 		if (k->ki_p->ki_wmesg[0] != 0)
479 			str = strdup(k->ki_p->ki_wmesg);
480 		else
481                         asprintf(&str, "%lx", (long)k->ki_p->ki_wchan);
482 	} else if (k->ki_p->ki_kiflag & KI_LOCKBLOCK) {
483 		if (k->ki_p->ki_lockname[0]) {
484 			str = strdup(k->ki_p->ki_lockname);
485 		} else
486 			str = strdup("???");
487 	} else
488 		str = NULL;
489 
490 	return (str);
491 }
492 
493 char *
494 vsize(KINFO *k, VARENT *ve __unused)
495 {
496 	char *str;
497 
498 	asprintf(&str, "%lu", (u_long)(k->ki_p->ki_size / 1024));
499 	return (str);
500 }
501 
502 static char *
503 printtime(KINFO *k, VARENT *ve __unused, long secs, long psecs)
504 /* psecs is "parts" of a second. first micro, then centi */
505 {
506 	static char decimal_point;
507 	char *str;
508 
509 	if (decimal_point == '\0')
510 		decimal_point = localeconv()->decimal_point[0];
511 	if (!k->ki_valid) {
512 		secs = 0;
513 		psecs = 0;
514 	} else {
515 		/* round and scale to 100's */
516 		psecs = (psecs + 5000) / 10000;
517 		secs += psecs / 100;
518 		psecs = psecs % 100;
519 	}
520 	asprintf(&str, "%ld:%02ld%c%02ld",
521 	    secs / 60, secs % 60, decimal_point, psecs);
522 	return (str);
523 }
524 
525 char *
526 cputime(KINFO *k, VARENT *ve)
527 {
528 	long secs, psecs;
529 
530 	/*
531 	 * This counts time spent handling interrupts.  We could
532 	 * fix this, but it is not 100% trivial (and interrupt
533 	 * time fractions only work on the sparc anyway).	XXX
534 	 */
535 	secs = k->ki_p->ki_runtime / 1000000;
536 	psecs = k->ki_p->ki_runtime % 1000000;
537 	if (sumrusage) {
538 		secs += k->ki_p->ki_childtime.tv_sec;
539 		psecs += k->ki_p->ki_childtime.tv_usec;
540 	}
541 	return (printtime(k, ve, secs, psecs));
542 }
543 
544 char *
545 systime(KINFO *k, VARENT *ve)
546 {
547 	long secs, psecs;
548 
549 	secs = k->ki_p->ki_rusage.ru_stime.tv_sec;
550 	psecs = k->ki_p->ki_rusage.ru_stime.tv_usec;
551 	if (sumrusage) {
552 		secs += k->ki_p->ki_childstime.tv_sec;
553 		psecs += k->ki_p->ki_childstime.tv_usec;
554 	}
555 	return (printtime(k, ve, secs, psecs));
556 }
557 
558 char *
559 usertime(KINFO *k, VARENT *ve)
560 {
561 	long secs, psecs;
562 
563 	secs = k->ki_p->ki_rusage.ru_utime.tv_sec;
564 	psecs = k->ki_p->ki_rusage.ru_utime.tv_usec;
565 	if (sumrusage) {
566 		secs += k->ki_p->ki_childutime.tv_sec;
567 		psecs += k->ki_p->ki_childutime.tv_usec;
568 	}
569 	return (printtime(k, ve, secs, psecs));
570 }
571 
572 char *
573 elapsed(KINFO *k, VARENT *ve __unused)
574 {
575 	time_t val;
576 	int days, hours, mins, secs;
577 	char *str;
578 
579 	if (!k->ki_valid)
580 		return (NULL);
581 	val = now - k->ki_p->ki_start.tv_sec;
582 	days = val / (24 * 60 * 60);
583 	val %= 24 * 60 * 60;
584 	hours = val / (60 * 60);
585 	val %= 60 * 60;
586 	mins = val / 60;
587 	secs = val % 60;
588 	if (days != 0)
589 		asprintf(&str, "%3d-%02d:%02d:%02d", days, hours, mins, secs);
590 	else if (hours != 0)
591 		asprintf(&str, "%02d:%02d:%02d", hours, mins, secs);
592 	else
593 		asprintf(&str, "%02d:%02d", mins, secs);
594 
595 	return (str);
596 }
597 
598 char *
599 elapseds(KINFO *k, VARENT *ve __unused)
600 {
601 	time_t val;
602 	char *str;
603 
604 	if (!k->ki_valid)
605 		return (NULL);
606 	val = now - k->ki_p->ki_start.tv_sec;
607 	asprintf(&str, "%jd", (intmax_t)val);
608 	return (str);
609 }
610 
611 double
612 getpcpu(const KINFO *k)
613 {
614 	static int failure;
615 
616 	if (!nlistread)
617 		failure = donlist();
618 	if (failure)
619 		return (0.0);
620 
621 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
622 
623 	/* XXX - I don't like this */
624 	if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_flag & P_INMEM) == 0)
625 		return (0.0);
626 	if (rawcpu)
627 		return (100.0 * fxtofl(k->ki_p->ki_pctcpu));
628 	return (100.0 * fxtofl(k->ki_p->ki_pctcpu) /
629 		(1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu)))));
630 }
631 
632 char *
633 pcpu(KINFO *k, VARENT *ve __unused)
634 {
635 	char *str;
636 
637 	asprintf(&str, "%.1f", getpcpu(k));
638 	return (str);
639 }
640 
641 static double
642 getpmem(KINFO *k)
643 {
644 	static int failure;
645 	double fracmem;
646 
647 	if (!nlistread)
648 		failure = donlist();
649 	if (failure)
650 		return (0.0);
651 
652 	if ((k->ki_p->ki_flag & P_INMEM) == 0)
653 		return (0.0);
654 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
655 	/* XXX don't have info about shared */
656 	fracmem = ((float)k->ki_p->ki_rssize) / mempages;
657 	return (100.0 * fracmem);
658 }
659 
660 char *
661 pmem(KINFO *k, VARENT *ve __unused)
662 {
663 	char *str;
664 
665 	asprintf(&str, "%.1f", getpmem(k));
666 	return (str);
667 }
668 
669 char *
670 pagein(KINFO *k, VARENT *ve __unused)
671 {
672 	char *str;
673 
674 	asprintf(&str, "%ld", k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0);
675 	return (str);
676 }
677 
678 /* ARGSUSED */
679 char *
680 maxrss(KINFO *k __unused, VARENT *ve __unused)
681 {
682 
683 	/* XXX not yet */
684 	return (NULL);
685 }
686 
687 char *
688 priorityr(KINFO *k, VARENT *ve __unused)
689 {
690 	struct priority *lpri;
691 	char *str;
692 	unsigned class, level;
693 
694 	lpri = &k->ki_p->ki_pri;
695 	class = lpri->pri_class;
696 	level = lpri->pri_level;
697 	switch (class) {
698 	case PRI_ITHD:
699 		asprintf(&str, "intr:%u", level);
700 		break;
701 	case PRI_REALTIME:
702 		asprintf(&str, "real:%u", level);
703 		break;
704 	case PRI_TIMESHARE:
705 		asprintf(&str, "normal");
706 		break;
707 	case PRI_IDLE:
708 		asprintf(&str, "idle:%u", level);
709 		break;
710 	default:
711 		asprintf(&str, "%u:%u", class, level);
712 		break;
713 	}
714 	return (str);
715 }
716 
717 /*
718  * Generic output routines.  Print fields from various prototype
719  * structures.
720  */
721 static char *
722 printval(void *bp, VAR *v)
723 {
724 	static char ofmt[32] = "%";
725 	const char *fcp;
726 	char *cp, *str;
727 
728 	cp = ofmt + 1;
729 	fcp = v->fmt;
730 	while ((*cp++ = *fcp++));
731 
732 #define	CHKINF127(n)	(((n) > 127) && (v->flag & INF127) ? 127 : (n))
733 
734 	switch (v->type) {
735 	case CHAR:
736 		(void)asprintf(&str, ofmt, *(char *)bp);
737 		break;
738 	case UCHAR:
739 		(void)asprintf(&str, ofmt, *(u_char *)bp);
740 		break;
741 	case SHORT:
742 		(void)asprintf(&str, ofmt, *(short *)bp);
743 		break;
744 	case USHORT:
745 		(void)asprintf(&str, ofmt, *(u_short *)bp);
746 		break;
747 	case INT:
748 		(void)asprintf(&str, ofmt, *(int *)bp);
749 		break;
750 	case UINT:
751 		(void)asprintf(&str, ofmt, CHKINF127(*(u_int *)bp));
752 		break;
753 	case LONG:
754 		(void)asprintf(&str, ofmt, *(long *)bp);
755 		break;
756 	case ULONG:
757 		(void)asprintf(&str, ofmt, *(u_long *)bp);
758 		break;
759 	case KPTR:
760 		(void)asprintf(&str, ofmt, *(u_long *)bp);
761 		break;
762 	case PGTOK:
763 		(void)asprintf(&str, ofmt, ps_pgtok(*(u_long *)bp));
764 		break;
765 	default:
766 		xo_errx(1, "unknown type %d", v->type);
767 	}
768 
769 	return (str);
770 }
771 
772 char *
773 kvar(KINFO *k, VARENT *ve)
774 {
775 	VAR *v;
776 
777 	v = ve->var;
778 	return (printval((char *)((char *)k->ki_p + v->off), v));
779 }
780 
781 char *
782 rvar(KINFO *k, VARENT *ve)
783 {
784 	VAR *v;
785 
786 	v = ve->var;
787 	if (!k->ki_valid)
788 		return (NULL);
789 	return (printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v));
790 }
791 
792 char *
793 emulname(KINFO *k, VARENT *ve __unused)
794 {
795 
796 	return (strdup(k->ki_p->ki_emul));
797 }
798 
799 char *
800 label(KINFO *k, VARENT *ve __unused)
801 {
802 	char *string;
803 	mac_t proclabel;
804 	int error;
805 
806 	string = NULL;
807 	if (mac_prepare_process_label(&proclabel) == -1) {
808 		xo_warn("mac_prepare_process_label");
809 		goto out;
810 	}
811 	error = mac_get_pid(k->ki_p->ki_pid, proclabel);
812 	if (error == 0) {
813 		if (mac_to_text(proclabel, &string) == -1)
814 			string = NULL;
815 	}
816 	mac_free(proclabel);
817 out:
818 	return (string);
819 }
820 
821 char *
822 loginclass(KINFO *k, VARENT *ve __unused)
823 {
824 
825 	/*
826 	 * Don't display login class for system processes;
827 	 * login classes are used for resource limits,
828 	 * and limits don't apply to system processes.
829 	 */
830 	if (k->ki_p->ki_flag & P_SYSTEM) {
831 		return (strdup("-"));
832 	}
833 	return (strdup(k->ki_p->ki_loginclass));
834 }
835