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