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