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
67void
68printheader(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
94char *
95arguments(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
109char *
110command(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
164char *
165ucomm(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
186char *
187tdnam(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
200char *
201logname(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
209char *
210state(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
285char *
286pri(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
294char *
295upr(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
304char *
305username(KINFO *k, VARENT *ve __unused)
306{
307
308	return (strdup(user_from_uid(k->ki_p->ki_uid, 0)));
309}
310
311char *
312egroupname(KINFO *k, VARENT *ve __unused)
313{
314
315	return (strdup(group_from_gid(k->ki_p->ki_groups[0], 0)));
316}
317
318char *
319rgroupname(KINFO *k, VARENT *ve __unused)
320{
321
322	return (strdup(group_from_gid(k->ki_p->ki_rgid, 0)));
323}
324
325char *
326runame(KINFO *k, VARENT *ve __unused)
327{
328
329	return (strdup(user_from_uid(k->ki_p->ki_ruid, 0)));
330}
331
332char *
333tdev(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
347char *
348tname(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
369char *
370longtname(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
382char *
383started(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
408char *
409lstarted(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
427char *
428lockname(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
443char *
444wchan(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
459char *
460nwchan(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
472char *
473mwchan(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
493char *
494vsize(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
502static char *
503printtime(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
525char *
526cputime(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
544char *
545cpunum(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
557char *
558systime(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
571char *
572usertime(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
585char *
586elapsed(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
611char *
612elapseds(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
624double
625getpcpu(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
645char *
646pcpu(KINFO *k, VARENT *ve __unused)
647{
648	char *str;
649
650	asprintf(&str, "%.1f", getpcpu(k));
651	return (str);
652}
653
654static double
655getpmem(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
673char *
674pmem(KINFO *k, VARENT *ve __unused)
675{
676	char *str;
677
678	asprintf(&str, "%.1f", getpmem(k));
679	return (str);
680}
681
682char *
683pagein(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 */
692char *
693maxrss(KINFO *k __unused, VARENT *ve __unused)
694{
695
696	/* XXX not yet */
697	return (NULL);
698}
699
700char *
701priorityr(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 */
741static char *
742printval(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
790char *
791kvar(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
799char *
800rvar(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
810char *
811emulname(KINFO *k, VARENT *ve __unused)
812{
813
814	return (strdup(k->ki_p->ki_emul));
815}
816
817char *
818label(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);
835out:
836	return (string);
837}
838
839char *
840loginclass(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
854char *
855jailname(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