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