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