xref: /freebsd/bin/ps/print.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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 <err.h>
44 #include <grp.h>
45 #include <jail.h>
46 #include <langinfo.h>
47 #include <locale.h>
48 #include <math.h>
49 #include <nlist.h>
50 #include <pwd.h>
51 #include <stddef.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <vis.h>
58 #include <libxo/xo.h>
59 
60 #include "ps.h"
61 
62 #define	COMMAND_WIDTH	16
63 #define	ARGUMENTS_WIDTH	16
64 
65 #define	ps_pgtok(a)	(((a) * getpagesize()) / 1024)
66 
67 void
68 printheader(void)
69 {
70 	VAR *v;
71 	struct varent *vent;
72 
73 	STAILQ_FOREACH(vent, &varlist, next_ve)
74 		if (*vent->header != '\0')
75 			break;
76 	if (!vent)
77 		return;
78 
79 	STAILQ_FOREACH(vent, &varlist, next_ve) {
80 		v = vent->var;
81 		if (v->flag & LJUST) {
82 			if (STAILQ_NEXT(vent, next_ve) == NULL)	/* last one */
83 				xo_emit("{T:/%hs}", vent->header);
84 			else
85 				xo_emit("{T:/%-*hs}", v->width, vent->header);
86 		} else
87 			xo_emit("{T:/%*hs}", v->width, vent->header);
88 		if (STAILQ_NEXT(vent, next_ve) != NULL)
89 			xo_emit("{P: }");
90 	}
91 	xo_emit("\n");
92 }
93 
94 char *
95 arguments(KINFO *k, VARENT *ve)
96 {
97 	char *vis_args;
98 
99 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
100 		xo_errx(1, "malloc failed");
101 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
102 
103 	if (STAILQ_NEXT(ve, next_ve) != NULL && strlen(vis_args) > ARGUMENTS_WIDTH)
104 		vis_args[ARGUMENTS_WIDTH] = '\0';
105 
106 	return (vis_args);
107 }
108 
109 char *
110 command(KINFO *k, VARENT *ve)
111 {
112 	char *vis_args, *vis_env, *str;
113 
114 	if (cflag) {
115 		/* If it is the last field, then don't pad */
116 		if (STAILQ_NEXT(ve, next_ve) == NULL) {
117 			asprintf(&str, "%s%s%s%s%s",
118 			    k->ki_d.prefix ? k->ki_d.prefix : "",
119 			    k->ki_p->ki_comm,
120 			    (showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
121 			    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "",
122 			    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_moretdname : "");
123 		} else
124 			str = strdup(k->ki_p->ki_comm);
125 
126 		return (str);
127 	}
128 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
129 		xo_errx(1, "malloc failed");
130 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
131 
132 	if (STAILQ_NEXT(ve, next_ve) == NULL) {
133 		/* last field */
134 
135 		if (k->ki_env) {
136 			if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1))
137 			    == NULL)
138 				xo_errx(1, "malloc failed");
139 			strvis(vis_env, k->ki_env,
140 			    VIS_TAB | VIS_NL | VIS_NOSLASH);
141 		} else
142 			vis_env = NULL;
143 
144 		asprintf(&str, "%s%s%s%s",
145 		    k->ki_d.prefix ? k->ki_d.prefix : "",
146 		    vis_env ? vis_env : "",
147 		    vis_env ? " " : "",
148 		    vis_args);
149 
150 		if (vis_env != NULL)
151 			free(vis_env);
152 		free(vis_args);
153 	} else {
154 		/* ki_d.prefix & ki_env aren't shown for interim fields */
155 		str = vis_args;
156 
157 		if (strlen(str) > COMMAND_WIDTH)
158 			str[COMMAND_WIDTH] = '\0';
159 	}
160 
161 	return (str);
162 }
163 
164 char *
165 ucomm(KINFO *k, VARENT *ve)
166 {
167 	char *str;
168 
169 	if (STAILQ_NEXT(ve, next_ve) == NULL) {	/* last field, don't pad */
170 		asprintf(&str, "%s%s%s%s%s",
171 		    k->ki_d.prefix ? k->ki_d.prefix : "",
172 		    k->ki_p->ki_comm,
173 		    (showthreads && k->ki_p->ki_numthreads > 1) ? "/" : "",
174 		    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_tdname : "",
175 		    (showthreads && k->ki_p->ki_numthreads > 1) ? k->ki_p->ki_moretdname : "");
176 	} else {
177 		if (showthreads && k->ki_p->ki_numthreads > 1)
178 			asprintf(&str, "%s/%s%s", k->ki_p->ki_comm,
179 			    k->ki_p->ki_tdname, k->ki_p->ki_moretdname);
180 		else
181 			str = strdup(k->ki_p->ki_comm);
182 	}
183 	return (str);
184 }
185 
186 char *
187 tdnam(KINFO *k, VARENT *ve __unused)
188 {
189 	char *str;
190 
191 	if (showthreads && k->ki_p->ki_numthreads > 1)
192 		asprintf(&str, "%s%s", k->ki_p->ki_tdname,
193 		    k->ki_p->ki_moretdname);
194 	else
195 		str = strdup("      ");
196 
197 	return (str);
198 }
199 
200 char *
201 logname(KINFO *k, VARENT *ve __unused)
202 {
203 
204 	if (*k->ki_p->ki_login == '\0')
205 		return (NULL);
206 	return (strdup(k->ki_p->ki_login));
207 }
208 
209 char *
210 state(KINFO *k, VARENT *ve __unused)
211 {
212 	long flag, tdflags;
213 	char *cp, *buf;
214 
215 	buf = malloc(16);
216 	if (buf == NULL)
217 		xo_errx(1, "malloc failed");
218 
219 	flag = k->ki_p->ki_flag;
220 	tdflags = k->ki_p->ki_tdflags;	/* XXXKSE */
221 	cp = buf;
222 
223 	switch (k->ki_p->ki_stat) {
224 
225 	case SSTOP:
226 		*cp = 'T';
227 		break;
228 
229 	case SSLEEP:
230 		if (tdflags & TDF_SINTR)	/* interruptible (long) */
231 			*cp = k->ki_p->ki_slptime >= MAXSLP ? 'I' : 'S';
232 		else
233 			*cp = 'D';
234 		break;
235 
236 	case SRUN:
237 	case SIDL:
238 		*cp = 'R';
239 		break;
240 
241 	case SWAIT:
242 		*cp = 'W';
243 		break;
244 
245 	case SLOCK:
246 		*cp = 'L';
247 		break;
248 
249 	case SZOMB:
250 		*cp = 'Z';
251 		break;
252 
253 	default:
254 		*cp = '?';
255 	}
256 	cp++;
257 	if (!(flag & P_INMEM))
258 		*cp++ = 'W';
259 	if (k->ki_p->ki_nice < NZERO || k->ki_p->ki_pri.pri_class == PRI_REALTIME)
260 		*cp++ = '<';
261 	else if (k->ki_p->ki_nice > NZERO || k->ki_p->ki_pri.pri_class == PRI_IDLE)
262 		*cp++ = 'N';
263 	if (flag & P_TRACED)
264 		*cp++ = 'X';
265 	if (flag & P_WEXIT && k->ki_p->ki_stat != SZOMB)
266 		*cp++ = 'E';
267 	if (flag & P_PPWAIT)
268 		*cp++ = 'V';
269 	if ((flag & P_SYSTEM) || k->ki_p->ki_lock > 0)
270 		*cp++ = 'L';
271 	if ((k->ki_p->ki_cr_flags & CRED_FLAG_CAPMODE) != 0)
272 		*cp++ = 'C';
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 username(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 cpunum(KINFO *k, VARENT *ve __unused)
546 {
547 	char *cpu;
548 
549 	if (k->ki_p->ki_stat == SRUN && k->ki_p->ki_oncpu != NOCPU) {
550 		asprintf(&cpu, "%d", k->ki_p->ki_oncpu);
551 	} else {
552 		asprintf(&cpu, "%d", k->ki_p->ki_lastcpu);
553 	}
554 	return (cpu);
555 }
556 
557 char *
558 systime(KINFO *k, VARENT *ve)
559 {
560 	long secs, psecs;
561 
562 	secs = k->ki_p->ki_rusage.ru_stime.tv_sec;
563 	psecs = k->ki_p->ki_rusage.ru_stime.tv_usec;
564 	if (sumrusage) {
565 		secs += k->ki_p->ki_childstime.tv_sec;
566 		psecs += k->ki_p->ki_childstime.tv_usec;
567 	}
568 	return (printtime(k, ve, secs, psecs));
569 }
570 
571 char *
572 usertime(KINFO *k, VARENT *ve)
573 {
574 	long secs, psecs;
575 
576 	secs = k->ki_p->ki_rusage.ru_utime.tv_sec;
577 	psecs = k->ki_p->ki_rusage.ru_utime.tv_usec;
578 	if (sumrusage) {
579 		secs += k->ki_p->ki_childutime.tv_sec;
580 		psecs += k->ki_p->ki_childutime.tv_usec;
581 	}
582 	return (printtime(k, ve, secs, psecs));
583 }
584 
585 char *
586 elapsed(KINFO *k, VARENT *ve __unused)
587 {
588 	time_t val;
589 	int days, hours, mins, secs;
590 	char *str;
591 
592 	if (!k->ki_valid)
593 		return (NULL);
594 	val = now - k->ki_p->ki_start.tv_sec;
595 	days = val / (24 * 60 * 60);
596 	val %= 24 * 60 * 60;
597 	hours = val / (60 * 60);
598 	val %= 60 * 60;
599 	mins = val / 60;
600 	secs = val % 60;
601 	if (days != 0)
602 		asprintf(&str, "%3d-%02d:%02d:%02d", days, hours, mins, secs);
603 	else if (hours != 0)
604 		asprintf(&str, "%02d:%02d:%02d", hours, mins, secs);
605 	else
606 		asprintf(&str, "%02d:%02d", mins, secs);
607 
608 	return (str);
609 }
610 
611 char *
612 elapseds(KINFO *k, VARENT *ve __unused)
613 {
614 	time_t val;
615 	char *str;
616 
617 	if (!k->ki_valid)
618 		return (NULL);
619 	val = now - k->ki_p->ki_start.tv_sec;
620 	asprintf(&str, "%jd", (intmax_t)val);
621 	return (str);
622 }
623 
624 double
625 getpcpu(const KINFO *k)
626 {
627 	static int failure;
628 
629 	if (!nlistread)
630 		failure = donlist();
631 	if (failure)
632 		return (0.0);
633 
634 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
635 
636 	/* XXX - I don't like this */
637 	if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_flag & P_INMEM) == 0)
638 		return (0.0);
639 	if (rawcpu)
640 		return (100.0 * fxtofl(k->ki_p->ki_pctcpu));
641 	return (100.0 * fxtofl(k->ki_p->ki_pctcpu) /
642 		(1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu)))));
643 }
644 
645 char *
646 pcpu(KINFO *k, VARENT *ve __unused)
647 {
648 	char *str;
649 
650 	asprintf(&str, "%.1f", getpcpu(k));
651 	return (str);
652 }
653 
654 static double
655 getpmem(KINFO *k)
656 {
657 	static int failure;
658 	double fracmem;
659 
660 	if (!nlistread)
661 		failure = donlist();
662 	if (failure)
663 		return (0.0);
664 
665 	if ((k->ki_p->ki_flag & P_INMEM) == 0)
666 		return (0.0);
667 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
668 	/* XXX don't have info about shared */
669 	fracmem = ((double)k->ki_p->ki_rssize) / mempages;
670 	return (100.0 * fracmem);
671 }
672 
673 char *
674 pmem(KINFO *k, VARENT *ve __unused)
675 {
676 	char *str;
677 
678 	asprintf(&str, "%.1f", getpmem(k));
679 	return (str);
680 }
681 
682 char *
683 pagein(KINFO *k, VARENT *ve __unused)
684 {
685 	char *str;
686 
687 	asprintf(&str, "%ld", k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0);
688 	return (str);
689 }
690 
691 /* ARGSUSED */
692 char *
693 maxrss(KINFO *k __unused, VARENT *ve __unused)
694 {
695 
696 	/* XXX not yet */
697 	return (NULL);
698 }
699 
700 char *
701 priorityr(KINFO *k, VARENT *ve __unused)
702 {
703 	struct priority *lpri;
704 	char *str;
705 	unsigned class, level;
706 
707 	lpri = &k->ki_p->ki_pri;
708 	class = lpri->pri_class;
709 	level = lpri->pri_level;
710 	switch (class) {
711 	case RTP_PRIO_REALTIME:
712 	/* alias for PRI_REALTIME */
713 		asprintf(&str, "real:%u", level - PRI_MIN_REALTIME);
714 		break;
715 	case RTP_PRIO_NORMAL:
716 	/* alias for PRI_TIMESHARE */
717 		if (level >= PRI_MIN_TIMESHARE)
718 			asprintf(&str, "normal:%u", level - PRI_MIN_TIMESHARE);
719 		else
720 			asprintf(&str, "kernel:%u", level - PRI_MIN_KERN);
721 		break;
722 	case RTP_PRIO_IDLE:
723 	/* alias for PRI_IDLE */
724 		asprintf(&str, "idle:%u", level - PRI_MIN_IDLE);
725 		break;
726 	case RTP_PRIO_ITHD:
727 	/* alias for PRI_ITHD */
728 		asprintf(&str, "intr:%u", level - PRI_MIN_ITHD);
729 		break;
730 	default:
731 		asprintf(&str, "%u:%u", class, level);
732 		break;
733 	}
734 	return (str);
735 }
736 
737 /*
738  * Generic output routines.  Print fields from various prototype
739  * structures.
740  */
741 static char *
742 printval(void *bp, VAR *v)
743 {
744 	static char ofmt[32] = "%";
745 	const char *fcp;
746 	char *cp, *str;
747 
748 	cp = ofmt + 1;
749 	fcp = v->fmt;
750 	while ((*cp++ = *fcp++));
751 
752 #define	CHKINF127(n)	(((n) > 127) && (v->flag & INF127) ? 127 : (n))
753 
754 	switch (v->type) {
755 	case CHAR:
756 		(void)asprintf(&str, ofmt, *(char *)bp);
757 		break;
758 	case UCHAR:
759 		(void)asprintf(&str, ofmt, *(u_char *)bp);
760 		break;
761 	case SHORT:
762 		(void)asprintf(&str, ofmt, *(short *)bp);
763 		break;
764 	case USHORT:
765 		(void)asprintf(&str, ofmt, *(u_short *)bp);
766 		break;
767 	case INT:
768 		(void)asprintf(&str, ofmt, *(int *)bp);
769 		break;
770 	case UINT:
771 		(void)asprintf(&str, ofmt, CHKINF127(*(u_int *)bp));
772 		break;
773 	case LONG:
774 		(void)asprintf(&str, ofmt, *(long *)bp);
775 		break;
776 	case ULONG:
777 		(void)asprintf(&str, ofmt, *(u_long *)bp);
778 		break;
779 	case KPTR:
780 		(void)asprintf(&str, ofmt, *(u_long *)bp);
781 		break;
782 	case PGTOK:
783 		(void)asprintf(&str, ofmt, ps_pgtok(*(u_long *)bp));
784 		break;
785 	}
786 
787 	return (str);
788 }
789 
790 char *
791 kvar(KINFO *k, VARENT *ve)
792 {
793 	VAR *v;
794 
795 	v = ve->var;
796 	return (printval((char *)((char *)k->ki_p + v->off), v));
797 }
798 
799 char *
800 rvar(KINFO *k, VARENT *ve)
801 {
802 	VAR *v;
803 
804 	v = ve->var;
805 	if (!k->ki_valid)
806 		return (NULL);
807 	return (printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v));
808 }
809 
810 char *
811 emulname(KINFO *k, VARENT *ve __unused)
812 {
813 
814 	return (strdup(k->ki_p->ki_emul));
815 }
816 
817 char *
818 label(KINFO *k, VARENT *ve __unused)
819 {
820 	char *string;
821 	mac_t proclabel;
822 	int error;
823 
824 	string = NULL;
825 	if (mac_prepare_process_label(&proclabel) == -1) {
826 		xo_warn("mac_prepare_process_label");
827 		goto out;
828 	}
829 	error = mac_get_pid(k->ki_p->ki_pid, proclabel);
830 	if (error == 0) {
831 		if (mac_to_text(proclabel, &string) == -1)
832 			string = NULL;
833 	}
834 	mac_free(proclabel);
835 out:
836 	return (string);
837 }
838 
839 char *
840 loginclass(KINFO *k, VARENT *ve __unused)
841 {
842 
843 	/*
844 	 * Don't display login class for system processes;
845 	 * login classes are used for resource limits,
846 	 * and limits don't apply to system processes.
847 	 */
848 	if (k->ki_p->ki_flag & P_SYSTEM) {
849 		return (strdup("-"));
850 	}
851 	return (strdup(k->ki_p->ki_loginclass));
852 }
853 
854 char *
855 jailname(KINFO *k, VARENT *ve __unused)
856 {
857 	char *name;
858 
859 	if (k->ki_p->ki_jid == 0)
860 		return (strdup("-"));
861 	name = jail_getname(k->ki_p->ki_jid);
862 	if (name == NULL)
863 		return (strdup("-"));
864 	return (name);
865 }
866