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