1 /*        $NetBSD: print.c,v 1.138 2022/01/26 11:48:53 andvar Exp $   */
2 
3 /*
4  * Copyright (c) 2000, 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Simon Burge.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1990, 1993, 1994
34  *        The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  */
60 
61 #include <sys/cdefs.h>
62 #ifndef lint
63 #if 0
64 static char sccsid[] = "@(#)print.c     8.6 (Berkeley) 4/16/94";
65 #else
66 __RCSID("$NetBSD: print.c,v 1.138 2022/01/26 11:48:53 andvar Exp $");
67 #endif
68 #endif /* not lint */
69 
70 #include <sys/param.h>
71 #include <sys/time.h>
72 #include <sys/resource.h>
73 #include <sys/sysctl.h>
74 #include <sys/lwp.h>
75 #include <sys/proc.h>
76 #include <sys/stat.h>
77 #include <sys/ucred.h>
78 #include <sys/sysctl.h>
79 #include <sys/acct.h>
80 #include <sys/ktrace.h>
81 
82 #include <err.h>
83 #include <grp.h>
84 #include <kvm.h>
85 #include <math.h>
86 #include <nlist.h>
87 #include <pwd.h>
88 #include <stddef.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <time.h>
93 #include <util.h>
94 #include <tzfile.h>
95 #include <unistd.h>
96 #include <signal.h>
97 
98 #include "ps.h"
99 
100 static char *cmdpart(char *);
101 static void  printval(void *, VAR *, enum mode);
102 static int   titlecmp(char *, char **);
103 
104 static void  doubleprintorsetwidth(VAR *, double, int, enum mode);
105 static void  intprintorsetwidth(VAR *, int, enum mode);
106 static void  strprintorsetwidth(VAR *, const char *, enum mode);
107 
108 static time_t now;
109 
110 #define   min(a,b)  ((a) <= (b) ? (a) : (b))
111 
112 /* pre-NetBSD 5.x support. */
113 #ifndef LSDEAD
114 #define LSDEAD 6
115 #endif
116 
117 static void __attribute__((__format__(__strftime__, 3, 0)))
safe_strftime(char * buf,size_t bufsiz,const char * fmt,const struct tm * tp)118 safe_strftime(char *buf, size_t bufsiz, const char *fmt,
119     const struct tm *tp)
120 {
121           if (tp == NULL || strftime(buf, bufsiz, fmt, tp) == 0)
122                     strlcpy(buf, "-", sizeof(buf));
123 }
124 
125 static int
iwidth(u_int64_t v)126 iwidth(u_int64_t v)
127 {
128           u_int64_t nlim, lim;
129           int w = 1;
130 
131           for (lim = 10; v >= lim; lim = nlim) {
132                     nlim = lim * 10;
133                     w++;
134                     if (nlim < lim)
135                               break;
136           }
137           return w;
138 }
139 
140 static char *
cmdpart(char * arg0)141 cmdpart(char *arg0)
142 {
143           char *cp;
144 
145           return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
146 }
147 
148 void
printheader(void)149 printheader(void)
150 {
151           int len;
152           VAR *v;
153           struct varent *vent;
154           static int firsttime = 1;
155           static int noheader = 0;
156 
157           /*
158            * If all the columns have user-specified null headers,
159            * don't print the blank header line at all.
160            */
161           if (firsttime) {
162                     SIMPLEQ_FOREACH(vent, &displaylist, next) {
163                               if (vent->var->header[0])
164                                         break;
165                     }
166                     if (vent == NULL) {
167                               noheader = 1;
168                               firsttime = 0;
169                     }
170 
171           }
172           if (noheader)
173                     return;
174 
175           SIMPLEQ_FOREACH(vent, &displaylist, next) {
176                     v = vent->var;
177                     if (firsttime) {
178                               len = strlen(v->header);
179                               if (len > v->width)
180                                         v->width = len;
181                               totwidth += v->width + 1;     /* +1 for space */
182                     }
183                     if (v->flag & LJUST) {
184                               if (SIMPLEQ_NEXT(vent, next) == NULL)   /* last one */
185                                         (void)printf("%s", v->header);
186                               else
187                                         (void)printf("%-*s", v->width,
188                                             v->header);
189                     } else
190                               (void)printf("%*s", v->width, v->header);
191                     if (SIMPLEQ_NEXT(vent, next) != NULL)
192                               (void)putchar(' ');
193           }
194           (void)putchar('\n');
195           if (firsttime) {
196                     firsttime = 0;
197                     totwidth--;         /* take off last space */
198           }
199 }
200 
201 /*
202  * Return 1 if the command name in the argument vector (u-area) does
203  * not match the command name (p_comm)
204  */
205 static int
titlecmp(char * name,char ** argv)206 titlecmp(char *name, char **argv)
207 {
208           char *title;
209           int namelen;
210 
211 
212           /* no argument vector == no match; system processes/threads do that */
213           if (argv == 0 || argv[0] == 0)
214                     return (1);
215 
216           title = cmdpart(argv[0]);
217 
218           /* the basename matches */
219           if (!strcmp(name, title))
220                     return (0);
221 
222           /* handle login shells, by skipping the leading - */
223           if (title[0] == '-' && !strcmp(name, title + 1))
224                     return (0);
225 
226           namelen = strlen(name);
227 
228           /* handle daemons that report activity as daemonname: activity */
229           if (argv[1] == 0 &&
230               !strncmp(name, title, namelen) &&
231               title[namelen + 0] == ':' &&
232               title[namelen + 1] == ' ')
233                     return (0);
234 
235           return (1);
236 }
237 
238 static void
doubleprintorsetwidth(VAR * v,double val,int prec,enum mode mode)239 doubleprintorsetwidth(VAR *v, double val, int prec, enum mode mode)
240 {
241           int fmtlen;
242 
243           if (mode == WIDTHMODE) {
244                     if (val < 0.0 && val < v->longestnd) {
245                               fmtlen = (int)log10(-val) + prec + 2;
246                               v->longestnd = val;
247                               if (fmtlen > v->width)
248                                         v->width = fmtlen;
249                     } else if (val > 0.0 && val > v->longestpd) {
250                               fmtlen = (int)log10(val) + prec + 1;
251                               v->longestpd = val;
252                               if (fmtlen > v->width)
253                                         v->width = fmtlen;
254                     }
255           } else {
256                     (void)printf("%*.*f", v->width, prec, val);
257           }
258 }
259 
260 static void
intprintorsetwidth(VAR * v,int val,enum mode mode)261 intprintorsetwidth(VAR *v, int val, enum mode mode)
262 {
263           int fmtlen;
264 
265           if (mode == WIDTHMODE) {
266                     if (val < 0 && val < v->longestn) {
267                               v->longestn = val;
268                               fmtlen = iwidth(-val) + 1;
269                               if (fmtlen > v->width)
270                                         v->width = fmtlen;
271                     } else if (val > 0 && val > v->longestp) {
272                               v->longestp = val;
273                               fmtlen = iwidth(val);
274                               if (fmtlen > v->width)
275                                         v->width = fmtlen;
276                     }
277           } else
278                     (void)printf("%*d", v->width, val);
279 }
280 
281 static void
strprintorsetwidth(VAR * v,const char * str,enum mode mode)282 strprintorsetwidth(VAR *v, const char *str, enum mode mode)
283 {
284           int len;
285 
286           if (mode == WIDTHMODE) {
287                     len = strlen(str);
288                     if (len > v->width)
289                               v->width = len;
290           } else {
291                     if (v->flag & LJUST)
292                               (void)printf("%-*.*s", v->width, v->width, str);
293                     else
294                               (void)printf("%*.*s", v->width, v->width, str);
295           }
296 }
297 
298 void
command(struct pinfo * pi,VARENT * ve,enum mode mode)299 command(struct pinfo *pi, VARENT *ve, enum mode mode)
300 {
301           struct kinfo_proc2 *ki = pi->ki;
302           VAR *v;
303           int left;
304           char **argv, **p, *name;
305 
306           if (mode == WIDTHMODE)
307                     return;
308 
309           v = ve->var;
310           if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
311                     if (SIMPLEQ_NEXT(ve, next) == NULL) {
312                               left = termwidth - (totwidth - v->width);
313                               if (left < 1) /* already wrapped, just use std width */
314                                         left = v->width;
315                     } else
316                               left = v->width;
317           } else
318                     left = -1;
319           if (needenv && kd) {
320                     argv = kvm_getenvv2(kd, ki, termwidth);
321                     if ((p = argv) != NULL) {
322                               while (*p) {
323                                         fmt_puts(*p, &left);
324                                         p++;
325                                         fmt_putc(' ', &left);
326                               }
327                     }
328           }
329           if (needcomm) {
330                     if (pi->prefix)
331                               (void)fmt_puts(pi->prefix, &left);
332                     name = ki->p_comm;
333                     if (!commandonly) {
334                               argv = kvm_getargv2(kd, ki, termwidth);
335                               if ((p = argv) != NULL) {
336                                         while (*p) {
337                                                   fmt_puts(*p, &left);
338                                                   p++;
339                                                   fmt_putc(' ', &left);
340                                                   if (v->flag & ARGV0)
341                                                             break;
342                                         }
343                                         if (!(v->flag & ARGV0) &&
344                                             titlecmp(name, argv)) {
345                                                   /*
346                                                    * append the real command name within
347                                                    * parentheses, if the command name
348                                                    * does not match the one in the
349                                                    * argument vector
350                                                    */
351                                                   fmt_putc('(', &left);
352                                                   fmt_puts(name, &left);
353                                                   fmt_putc(')', &left);
354                                         }
355                               } else {
356                                         /*
357                                          * Commands that don't set an argv vector
358                                          * are printed with square brackets if they
359                                          * are system commands.  Otherwise they are
360                                          * printed within parentheses.
361                                          */
362                                         if (ki->p_flag & P_SYSTEM) {
363                                                   fmt_putc('[', &left);
364                                                   fmt_puts(name, &left);
365                                                   fmt_putc(']', &left);
366                                         } else {
367                                                   fmt_putc('(', &left);
368                                                   fmt_puts(name, &left);
369                                                   fmt_putc(')', &left);
370                                         }
371                               }
372                     } else {
373                               fmt_puts(name, &left);
374                     }
375           }
376           if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
377                     (void)printf("%*s", left, "");
378 }
379 
380 void
groups(struct pinfo * pi,VARENT * ve,enum mode mode)381 groups(struct pinfo *pi, VARENT *ve, enum mode mode)
382 {
383           struct kinfo_proc2 *ki = pi->ki;
384           VAR *v;
385           int left, i;
386           char buf[16], *p;
387 
388           if (mode == WIDTHMODE)
389                     return;
390 
391           v = ve->var;
392           if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
393                     if (SIMPLEQ_NEXT(ve, next) == NULL) {
394                               left = termwidth - (totwidth - v->width);
395                               if (left < 1) /* already wrapped, just use std width */
396                                         left = v->width;
397                     } else
398                               left = v->width;
399           } else
400                     left = -1;
401 
402           if (ki->p_ngroups == 0)
403                     fmt_putc('-', &left);
404 
405           for (i = 0; i < ki->p_ngroups; i++) {
406                     (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]);
407                     if (i)
408                               fmt_putc(' ', &left);
409                     for (p = &buf[0]; *p; p++)
410                               fmt_putc(*p, &left);
411           }
412 
413           if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
414                     (void)printf("%*s", left, "");
415 }
416 
417 void
groupnames(struct pinfo * pi,VARENT * ve,enum mode mode)418 groupnames(struct pinfo *pi, VARENT *ve, enum mode mode)
419 {
420           struct kinfo_proc2 *ki = pi->ki;
421           VAR *v;
422           int left, i;
423           const char *p;
424 
425           if (mode == WIDTHMODE)
426                     return;
427 
428           v = ve->var;
429           if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
430                     if (SIMPLEQ_NEXT(ve, next) == NULL) {
431                               left = termwidth - (totwidth - v->width);
432                               if (left < 1) /* already wrapped, just use std width */
433                                         left = v->width;
434                     } else
435                               left = v->width;
436           } else
437                     left = -1;
438 
439           if (ki->p_ngroups == 0)
440                     fmt_putc('-', &left);
441 
442           for (i = 0; i < ki->p_ngroups; i++) {
443                     if (i)
444                               fmt_putc(' ', &left);
445                     for (p = group_from_gid(ki->p_groups[i], 0); *p; p++)
446                               fmt_putc(*p, &left);
447           }
448 
449           if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
450                     (void)printf("%*s", left, "");
451 }
452 
453 void
ucomm(struct pinfo * pi,VARENT * ve,enum mode mode)454 ucomm(struct pinfo *pi, VARENT *ve, enum mode mode)
455 {
456           struct kinfo_proc2 *k = pi->ki;
457           char buf[MAXPATHLEN], *p;
458           VAR *v;
459 
460           v = ve->var;
461           if (pi->prefix)
462                     snprintf(p = buf, sizeof(buf), "%s%s", pi->prefix, k->p_comm);
463           else
464                     p = k->p_comm;
465           strprintorsetwidth(v, p, mode);
466 }
467 
468 void
emul(struct pinfo * pi,VARENT * ve,enum mode mode)469 emul(struct pinfo *pi, VARENT *ve, enum mode mode)
470 {
471           struct kinfo_proc2 *k = pi->ki;
472           VAR *v;
473 
474           v = ve->var;
475           strprintorsetwidth(v, k->p_ename, mode);
476 }
477 
478 void
logname(struct pinfo * pi,VARENT * ve,enum mode mode)479 logname(struct pinfo *pi, VARENT *ve, enum mode mode)
480 {
481           struct kinfo_proc2 *k = pi->ki;
482           VAR *v;
483 
484           v = ve->var;
485           strprintorsetwidth(v, k->p_login, mode);
486 }
487 
488 void
state(struct pinfo * pi,VARENT * ve,enum mode mode)489 state(struct pinfo *pi, VARENT *ve, enum mode mode)
490 {
491           struct kinfo_proc2 *k = pi->ki;
492           int flag, is_zombie;
493           char *cp;
494           VAR *v;
495           char buf[16];
496 
497           is_zombie = 0;
498           v = ve->var;
499           flag = k->p_flag;
500           cp = buf;
501 
502           /*
503            * NOTE: There are historical letters, which are no longer used:
504            *
505            * - W: indicated that process is swapped out.
506            * - L: indicated non-zero l_holdcnt (i.e. that process was
507            *   prevented from swapping-out.
508            *
509            * These letters should not be used for new states to avoid
510            * conflicts with old applications which might depend on them.
511            */
512           switch (k->p_stat) {
513 
514           case LSSTOP:
515                     *cp = 'T';
516                     break;
517 
518           case LSSLEEP:
519                     if (flag & L_SINTR) /* interruptable (long) */
520                               *cp = (int)k->p_slptime >= maxslp ? 'I' : 'S';
521                     else
522                               *cp = 'D';
523                     break;
524 
525           case LSRUN:
526           case LSIDL:
527                     *cp = 'R';
528                     break;
529 
530           case LSONPROC:
531                     *cp = 'O';
532                     break;
533 
534           case LSZOMB:
535                     *cp = 'Z';
536                     is_zombie = 1;
537                     break;
538 
539           case LSSUSPENDED:
540                     *cp = 'U';
541                     break;
542 
543           default:
544                     *cp = '?';
545           }
546           cp++;
547           if (k->p_nice < NZERO)
548                     *cp++ = '<';
549           else if (k->p_nice > NZERO)
550                     *cp++ = 'N';
551           if (flag & P_TRACED)
552                     *cp++ = 'X';
553           if (flag & P_WEXIT && !is_zombie)
554                     *cp++ = 'E';
555           if (flag & P_PPWAIT)
556                     *cp++ = 'V';
557           if (flag & P_SYSTEM)
558                     *cp++ = 'K';
559           if (k->p_eflag & EPROC_SLEADER)
560                     *cp++ = 's';
561           if (flag & P_SA)
562                     *cp++ = 'a';
563           else if (k->p_nlwps > 1)
564                     *cp++ = 'l';
565           if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
566                     *cp++ = '+';
567           *cp = '\0';
568           strprintorsetwidth(v, buf, mode);
569 }
570 
571 void
lstate(struct pinfo * pi,VARENT * ve,enum mode mode)572 lstate(struct pinfo *pi, VARENT *ve, enum mode mode)
573 {
574           struct kinfo_lwp *k = pi->li;
575           int flag;
576           char *cp;
577           VAR *v;
578           char buf[16];
579 
580           v = ve->var;
581           flag = k->l_flag;
582           cp = buf;
583 
584           switch (k->l_stat) {
585 
586           case LSSTOP:
587                     *cp = 'T';
588                     break;
589 
590           case LSSLEEP:
591                     if (flag & L_SINTR) /* interruptible (long) */
592                               *cp = (int)k->l_slptime >= maxslp ? 'I' : 'S';
593                     else
594                               *cp = 'D';
595                     break;
596 
597           case LSRUN:
598           case LSIDL:
599                     *cp = 'R';
600                     break;
601 
602           case LSONPROC:
603                     *cp = 'O';
604                     break;
605 
606           case LSZOMB:
607           case LSDEAD:
608                     *cp = 'Z';
609                     break;
610 
611           case LSSUSPENDED:
612                     *cp = 'U';
613                     break;
614 
615           default:
616                     *cp = '?';
617           }
618           cp++;
619           if (flag & L_SYSTEM)
620                     *cp++ = 'K';
621           if (flag & L_SA)
622                     *cp++ = 'a';
623           if (flag & L_DETACHED)
624                     *cp++ = '-';
625           *cp = '\0';
626           strprintorsetwidth(v, buf, mode);
627 }
628 
629 void
pnice(struct pinfo * pi,VARENT * ve,enum mode mode)630 pnice(struct pinfo *pi, VARENT *ve, enum mode mode)
631 {
632           struct kinfo_proc2 *k = pi->ki;
633           VAR *v;
634 
635           v = ve->var;
636           intprintorsetwidth(v, k->p_nice - NZERO, mode);
637 }
638 
639 void
pri(struct pinfo * pi,VARENT * ve,enum mode mode)640 pri(struct pinfo *pi, VARENT *ve, enum mode mode)
641 {
642           struct kinfo_lwp *l = pi->li;
643           VAR *v;
644 
645           v = ve->var;
646           intprintorsetwidth(v, l->l_priority, mode);
647 }
648 
649 void
usrname(struct pinfo * pi,VARENT * ve,enum mode mode)650 usrname(struct pinfo *pi, VARENT *ve, enum mode mode)
651 {
652           struct kinfo_proc2 *k = pi->ki;
653           VAR *v;
654 
655           v = ve->var;
656           strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
657 }
658 
659 void
runame(struct pinfo * pi,VARENT * ve,enum mode mode)660 runame(struct pinfo *pi, VARENT *ve, enum mode mode)
661 {
662           struct kinfo_proc2 *k = pi->ki;
663           VAR *v;
664 
665           v = ve->var;
666           strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
667 }
668 
669 void
svuname(struct pinfo * pi,VARENT * ve,enum mode mode)670 svuname(struct pinfo *pi, VARENT *ve, enum mode mode)
671 {
672           struct kinfo_proc2 *k = pi->ki;
673           VAR *v;
674 
675           v = ve->var;
676           strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
677 }
678 
679 void
gname(struct pinfo * pi,VARENT * ve,enum mode mode)680 gname(struct pinfo *pi, VARENT *ve, enum mode mode)
681 {
682           struct kinfo_proc2 *k = pi->ki;
683           VAR *v;
684 
685           v = ve->var;
686           strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
687 }
688 
689 void
rgname(struct pinfo * pi,VARENT * ve,enum mode mode)690 rgname(struct pinfo *pi, VARENT *ve, enum mode mode)
691 {
692           struct kinfo_proc2 *k = pi->ki;
693           VAR *v;
694 
695           v = ve->var;
696           strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
697 }
698 
699 void
svgname(struct pinfo * pi,VARENT * ve,enum mode mode)700 svgname(struct pinfo *pi, VARENT *ve, enum mode mode)
701 {
702           struct kinfo_proc2 *k = pi->ki;
703           VAR *v;
704 
705           v = ve->var;
706           strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
707 }
708 
709 void
tdev(struct pinfo * pi,VARENT * ve,enum mode mode)710 tdev(struct pinfo *pi, VARENT *ve, enum mode mode)
711 {
712           struct kinfo_proc2 *k = pi->ki;
713           VAR *v;
714           dev_t dev;
715           char buff[16];
716 
717           v = ve->var;
718           dev = k->p_tdev;
719           if (dev == NODEV) {
720                     if (mode == PRINTMODE)
721                               (void)printf("%*s", v->width, "?");
722                     else
723                               if (v->width < 2)
724                                         v->width = 2;
725           } else {
726                     (void)snprintf(buff, sizeof(buff),
727                         "%lld/%lld", (long long)major(dev), (long long)minor(dev));
728                     strprintorsetwidth(v, buff, mode);
729           }
730 }
731 
732 void
tname(struct pinfo * pi,VARENT * ve,enum mode mode)733 tname(struct pinfo *pi, VARENT *ve, enum mode mode)
734 {
735           struct kinfo_proc2 *k = pi->ki;
736           VAR *v;
737           dev_t dev;
738           const char *ttname;
739           int noctty;
740 
741           v = ve->var;
742           dev = k->p_tdev;
743           if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
744                     if (mode == PRINTMODE)
745                               (void)printf("%-*s", v->width, "?");
746                     else
747                               if (v->width < 2)
748                                         v->width = 2;
749           } else {
750                     noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
751                     if (mode == WIDTHMODE) {
752                               int fmtlen;
753 
754                               fmtlen = strlen(ttname) + noctty;
755                               if (v->width < fmtlen)
756                                         v->width = fmtlen;
757                     } else {
758                               if (noctty)
759                                         (void)printf("%-*s-", v->width - 1, ttname);
760                               else
761                                         (void)printf("%-*s", v->width, ttname);
762                     }
763           }
764 }
765 
766 void
longtname(struct pinfo * pi,VARENT * ve,enum mode mode)767 longtname(struct pinfo *pi, VARENT *ve, enum mode mode)
768 {
769           struct kinfo_proc2 *k = pi->ki;
770           VAR *v;
771           dev_t dev;
772           const char *ttname;
773 
774           v = ve->var;
775           dev = k->p_tdev;
776           if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
777                     if (mode == PRINTMODE)
778                               (void)printf("%-*s", v->width, "?");
779                     else
780                               if (v->width < 2)
781                                         v->width = 2;
782           } else {
783                     strprintorsetwidth(v, ttname, mode);
784           }
785 }
786 
787 void
started(struct pinfo * pi,VARENT * ve,enum mode mode)788 started(struct pinfo *pi, VARENT *ve, enum mode mode)
789 {
790           struct kinfo_proc2 *k = pi->ki;
791           VAR *v;
792           time_t startt;
793           struct tm *tp;
794           char buf[100], *cp;
795 
796           v = ve->var;
797           if (!k->p_uvalid) {
798                     if (mode == PRINTMODE)
799                               (void)printf("%*s", v->width, "-");
800                     return;
801           }
802 
803           startt = k->p_ustart_sec;
804           tp = localtime(&startt);
805           if (now == 0)
806                     (void)time(&now);
807           if (now - k->p_ustart_sec < SECSPERDAY)
808                     safe_strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp);
809           else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
810                     safe_strftime(buf, sizeof(buf) - 1, "%a%I%p", tp);
811           else
812                     safe_strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
813           /* %e and %l can start with a space. */
814           cp = buf;
815           if (*cp == ' ')
816                     cp++;
817           strprintorsetwidth(v, cp, mode);
818 }
819 
820 void
lstarted(struct pinfo * pi,VARENT * ve,enum mode mode)821 lstarted(struct pinfo *pi, VARENT *ve, enum mode mode)
822 {
823           struct kinfo_proc2 *k = pi->ki;
824           VAR *v;
825           time_t startt;
826           char buf[100];
827 
828           v = ve->var;
829           startt = k->p_ustart_sec;
830 
831           if (mode == WIDTHMODE) {
832                     /*
833                      * We only need to set the width once, as we assume
834                      * that all times are the same length.  We do need to
835                      * check against the header length as well, as "no
836                      * header" mode for this variable will set the field
837                      * width to the length of the header anyway (ref: the
838                      * P1003.1-2004 comment in findvar()).
839                      *
840                      * XXX: The hardcoded "STARTED" string.  Better or
841                      * worse than a "<= 7" or some other arbitrary number?
842                      */
843                     if (v->width > (int)sizeof("STARTED") - 1) {
844                               return;
845                     }
846           } else {
847                     if (!k->p_uvalid) {
848                               (void)printf("%*s", v->width, "-");
849                               return;
850                     }
851           }
852           safe_strftime(buf, sizeof(buf) - 1, "%c", localtime(&startt));
853           strprintorsetwidth(v, buf, mode);
854 }
855 
856 void
elapsed(struct pinfo * pi,VARENT * ve,enum mode mode)857 elapsed(struct pinfo *pi, VARENT *ve, enum mode mode)
858 {
859           struct kinfo_proc2 *k = pi->ki;
860           VAR *v;
861           int32_t origseconds, secs, mins, hours, days;
862           int fmtlen, printed_something;
863 
864           v = ve->var;
865           if (k->p_uvalid == 0) {
866                     origseconds = 0;
867           } else {
868                     if (now == 0)
869                               (void)time(&now);
870                     origseconds = now - k->p_ustart_sec;
871                     if (origseconds < 0) {
872                               /*
873                                * Don't try to be fancy if the machine's
874                                * clock has been rewound to before the
875                                * process "started".
876                                */
877                               origseconds = 0;
878                     }
879           }
880 
881           secs = origseconds;
882           mins = secs / SECSPERMIN;
883           secs %= SECSPERMIN;
884           hours = mins / MINSPERHOUR;
885           mins %= MINSPERHOUR;
886           days = hours / HOURSPERDAY;
887           hours %= HOURSPERDAY;
888 
889           if (mode == WIDTHMODE) {
890                     if (origseconds == 0)
891                               /* non-zero so fmtlen is calculated at least once */
892                               origseconds = 1;
893 
894                     if (origseconds > v->longestp) {
895                               v->longestp = origseconds;
896 
897                               if (days > 0) {
898                                         /* +9 for "-hh:mm:ss" */
899                                         fmtlen = iwidth(days) + 9;
900                               } else if (hours > 0) {
901                                         /* +6 for "mm:ss" */
902                                         fmtlen = iwidth(hours) + 6;
903                               } else {
904                                         /* +3 for ":ss" */
905                                         fmtlen = iwidth(mins) + 3;
906                               }
907 
908                               if (fmtlen > v->width)
909                                         v->width = fmtlen;
910                     }
911           } else {
912                     printed_something = 0;
913                     fmtlen = v->width;
914 
915                     if (days > 0) {
916                               (void)printf("%*d", fmtlen - 9, days);
917                               printed_something = 1;
918                     } else if (fmtlen > 9) {
919                               (void)printf("%*s", fmtlen - 9, "");
920                     }
921                     if (fmtlen > 9)
922                               fmtlen = 9;
923 
924                     if (printed_something) {
925                               (void)printf("-%.*d", fmtlen - 7, hours);
926                               printed_something = 1;
927                     } else if (hours > 0) {
928                               (void)printf("%*d", fmtlen - 6, hours);
929                               printed_something = 1;
930                     } else if (fmtlen > 6) {
931                               (void)printf("%*s", fmtlen - 6, "");
932                     }
933                     if (fmtlen > 6)
934                               fmtlen = 6;
935 
936                     /* Don't need to set fmtlen or printed_something any more... */
937                     if (printed_something) {
938                               (void)printf(":%.*d", fmtlen - 4, mins);
939                     } else if (mins > 0) {
940                               (void)printf("%*d", fmtlen - 3, mins);
941                     } else if (fmtlen > 3) {
942                               (void)printf("%*s", fmtlen - 3, "0");
943                     }
944 
945                     (void)printf(":%.2d", secs);
946           }
947 }
948 
949 void
wchan(struct pinfo * pi,VARENT * ve,enum mode mode)950 wchan(struct pinfo *pi, VARENT *ve, enum mode mode)
951 {
952           struct kinfo_lwp *l = pi->li;
953           VAR *v;
954 
955           v = ve->var;
956           if (l->l_wmesg[0]) {
957                     strprintorsetwidth(v, l->l_wmesg, mode);
958                     v->width = min(v->width, KI_WMESGLEN);
959           } else {
960                     if (mode == PRINTMODE)
961                               (void)printf("%-*s", v->width, "-");
962           }
963 }
964 
965 #define   pgtok(a)        (((a)*(size_t)getpagesize())/1024)
966 
967 void
vsize(struct pinfo * pi,VARENT * ve,enum mode mode)968 vsize(struct pinfo *pi, VARENT *ve, enum mode mode)
969 {
970           struct kinfo_proc2 *k = pi->ki;
971           VAR *v;
972 
973           v = ve->var;
974           intprintorsetwidth(v, pgtok(k->p_vm_msize), mode);
975 }
976 
977 void
rssize(struct pinfo * pi,VARENT * ve,enum mode mode)978 rssize(struct pinfo *pi, VARENT *ve, enum mode mode)
979 {
980           struct kinfo_proc2 *k = pi->ki;
981           VAR *v;
982 
983           v = ve->var;
984           /* XXX don't have info about shared */
985           intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
986 }
987 
988 void
p_rssize(struct pinfo * pi,VARENT * ve,enum mode mode)989 p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode)      /* doesn't account for text */
990 {
991           struct kinfo_proc2 *k = pi->ki;
992           VAR *v;
993 
994           v = ve->var;
995           intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
996 }
997 
998 void
cpuid(struct pinfo * pi,VARENT * ve,enum mode mode)999 cpuid(struct pinfo *pi, VARENT *ve, enum mode mode)
1000 {
1001           struct kinfo_lwp *l = pi->li;
1002           VAR *v;
1003 
1004           v = ve->var;
1005           intprintorsetwidth(v, l->l_cpuid, mode);
1006 }
1007 
1008 static void
cputime1(int32_t secs,int32_t psecs,VAR * v,enum mode mode)1009 cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode)
1010 {
1011           int fmtlen;
1012 
1013           /*
1014            * round and scale to 100's
1015            */
1016           psecs = (psecs + 5000) / 10000;
1017           secs += psecs / 100;
1018           psecs = psecs % 100;
1019 
1020           if (mode == WIDTHMODE) {
1021                     /*
1022                      * Ugg, this is the only field where a value of 0 is longer
1023                      * than the column title.
1024                      * Use SECSPERMIN, because secs is divided by that when
1025                      * passed to iwidth().
1026                      */
1027                     if (secs == 0)
1028                               secs = SECSPERMIN;
1029 
1030                     if (secs > v->longestp) {
1031                               v->longestp = secs;
1032                               /* "+6" for the ":%02ld.%02ld" in the printf() below */
1033                               fmtlen = iwidth(secs / SECSPERMIN) + 6;
1034                               if (fmtlen > v->width)
1035                                         v->width = fmtlen;
1036                     }
1037           } else {
1038                     (void)printf("%*ld:%02ld.%02ld", v->width - 6,
1039                         (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
1040                         (long)psecs);
1041           }
1042 }
1043 
1044 void
cputime(struct pinfo * pi,VARENT * ve,enum mode mode)1045 cputime(struct pinfo *pi, VARENT *ve, enum mode mode)
1046 {
1047           struct kinfo_proc2 *k = pi->ki;
1048           VAR *v;
1049           int32_t secs;
1050           int32_t psecs;      /* "parts" of a second. first micro, then centi */
1051 
1052           v = ve->var;
1053 
1054           /*
1055            * This counts time spent handling interrupts.  We could
1056            * fix this, but it is not 100% trivial (and interrupt
1057            * time fractions only work on the sparc anyway). XXX
1058            */
1059           secs = k->p_rtime_sec;
1060           psecs = k->p_rtime_usec;
1061           if (sumrusage) {
1062                     secs += k->p_uctime_sec;
1063                     psecs += k->p_uctime_usec;
1064           }
1065 
1066           cputime1(secs, psecs, v, mode);
1067 }
1068 
1069 void
lcputime(struct pinfo * pi,VARENT * ve,enum mode mode)1070 lcputime(struct pinfo *pi, VARENT *ve, enum mode mode)
1071 {
1072           struct kinfo_lwp *l = pi->li;
1073           VAR *v;
1074           int32_t secs;
1075           int32_t psecs;      /* "parts" of a second. first micro, then centi */
1076 
1077           v = ve->var;
1078 
1079           secs = l->l_rtime_sec;
1080           psecs = l->l_rtime_usec;
1081 
1082           cputime1(secs, psecs, v, mode);
1083 }
1084 
1085 void
pcpu(struct pinfo * pi,VARENT * ve,enum mode mode)1086 pcpu(struct pinfo *pi, VARENT *ve, enum mode mode)
1087 {
1088           VAR *v;
1089           double dbl;
1090 
1091           v = ve->var;
1092           dbl = pi->pcpu;
1093           doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode);
1094 }
1095 
1096 double
getpmem(const struct kinfo_proc2 * k)1097 getpmem(const struct kinfo_proc2 *k)
1098 {
1099           double fracmem;
1100           int szptudot;
1101 
1102           if (!nlistread)
1103                     donlist();
1104 
1105           /* XXX want pmap ptpages, segtab, etc. (per architecture) */
1106           szptudot = uspace/getpagesize();
1107           /* XXX don't have info about shared */
1108           fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
1109           return (100.0 * fracmem);
1110 }
1111 
1112 void
pmem(struct pinfo * pi,VARENT * ve,enum mode mode)1113 pmem(struct pinfo *pi, VARENT *ve, enum mode mode)
1114 {
1115           struct kinfo_proc2 *k = pi->ki;
1116           VAR *v;
1117 
1118           v = ve->var;
1119           doubleprintorsetwidth(v, getpmem(k), 1, mode);
1120 }
1121 
1122 void
pagein(struct pinfo * pi,VARENT * ve,enum mode mode)1123 pagein(struct pinfo *pi, VARENT *ve, enum mode mode)
1124 {
1125           struct kinfo_proc2 *k = pi->ki;
1126           VAR *v;
1127 
1128           v = ve->var;
1129           intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
1130 }
1131 
1132 void
maxrss(struct pinfo * pi,VARENT * ve,enum mode mode)1133 maxrss(struct pinfo *pi, VARENT *ve, enum mode mode)
1134 {
1135           VAR *v;
1136 
1137           v = ve->var;
1138           /* No need to check width! */
1139           if (mode == PRINTMODE)
1140                     (void)printf("%*s", v->width, "-");
1141 }
1142 
1143 void
tsize(struct pinfo * pi,VARENT * ve,enum mode mode)1144 tsize(struct pinfo *pi, VARENT *ve, enum mode mode)
1145 {
1146           struct kinfo_proc2 *k = pi->ki;
1147           VAR *v;
1148 
1149           v = ve->var;
1150           intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
1151 }
1152 
1153 static void
printsig(VAR * v,const sigset_t * s,enum mode mode)1154 printsig(VAR *v, const sigset_t *s, enum mode mode)
1155 {
1156 #define   SIGSETSIZE          __arraycount(s->__bits)
1157           if ((v->flag & ALTPR) == 0) {
1158                     char buf[SIGSETSIZE * 8 + 1];
1159                     size_t i;
1160 
1161                     for (i = 0; i < SIGSETSIZE; i++)
1162                               (void)snprintf(&buf[i * 8], 9, "%.8x",
1163                                   s->__bits[(SIGSETSIZE - 1) - i]);
1164 
1165                     /* Skip leading zeroes */
1166                     for (i = 0; buf[i] == '0'; i++)
1167                               continue;
1168 
1169                     if (buf[i] == '\0')
1170                               i--;
1171                     strprintorsetwidth(v, buf + i, mode);
1172           } else {
1173                     size_t maxlen = 1024, len = 0;
1174                     char *buf = emalloc(maxlen);
1175                     *buf = '\0';
1176                     for (size_t i = 0; i < SIGSETSIZE; i++) {
1177                               uint32_t m = s->__bits[i];
1178                               for (uint32_t j = 0; j < 32; j++) {
1179                                         if ((m & (1 << j)) == 0)
1180                                                   continue;
1181                                         const char *n = signalname(j + 1);
1182                                         size_t sn = strlen(n);
1183                                         if (len)
1184                                                   sn++;
1185                                         if (len + sn >= maxlen) {
1186                                                   maxlen += 1024;
1187                                                   buf = erealloc(buf, maxlen);
1188                                         }
1189                                         snprintf(buf + len, sn + 1, "%s%s",
1190                                             len == 0 ? "" : ",", n);
1191                                         len += sn;
1192                               }
1193                     }
1194                     strprintorsetwidth(v, buf, mode);
1195                     free(buf);
1196 #undef SIGSETSIZE
1197           }
1198 }
1199 
1200 static void
printflag(VAR * v,int flag,enum mode mode)1201 printflag(VAR *v, int flag, enum mode mode)
1202 {
1203           char buf[1024];
1204           const char *fmt;
1205 
1206           switch (v->type) {
1207           case PROCFLAG:
1208                     fmt = __SYSCTL_PROC_FLAG_BITS;
1209                     break;
1210           case KTRACEFLAG:
1211                     fmt = __KTRACE_FLAG_BITS;
1212                     break;
1213           case PROCACFLAG:
1214                     fmt = __ACCT_FLAG_BITS;
1215                     break;
1216           default:
1217                     err(EXIT_FAILURE, "Bad type %d", v->type);
1218           }
1219 
1220           snprintb(buf, sizeof(buf), fmt, (unsigned)flag);
1221           strprintorsetwidth(v, buf, mode);
1222 }
1223 
1224 /*
1225  * Generic output routines.  Print fields from various prototype
1226  * structures.
1227  */
1228 static void
printval(void * bp,VAR * v,enum mode mode)1229 printval(void *bp, VAR *v, enum mode mode)
1230 {
1231           static char ofmt[32] = "%";
1232           int width, vok, fmtlen;
1233           const char *fcp;
1234           char *cp;
1235           int64_t val;
1236           u_int64_t uval;
1237 
1238           val = 0;  /* XXXGCC -Wuninitialized [hpcarm] */
1239           uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */
1240 
1241           /*
1242            * Note that the "INF127" check is nonsensical for types
1243            * that are or can be signed.
1244            */
1245 #define   GET(type)           (*(type *)bp)
1246 #define   CHK_INF127(n)                 (((n) > 127) && (v->flag & INF127) ? 127 : (n))
1247 
1248 #define   VSIGN     1
1249 #define   VUNSIGN   2
1250 #define   VPTR      3
1251 
1252           if (mode == WIDTHMODE) {
1253                     vok = 0;
1254                     switch (v->type) {
1255                     case CHAR:
1256                               val = GET(char);
1257                               vok = VSIGN;
1258                               break;
1259                     case UCHAR:
1260                               uval = CHK_INF127(GET(u_char));
1261                               vok = VUNSIGN;
1262                               break;
1263                     case SHORT:
1264                               val = GET(short);
1265                               vok = VSIGN;
1266                               break;
1267                     case PROCACFLAG:
1268                               if (v->flag & ALTPR)
1269                                         break;
1270                               /*FALLTHROUGH*/
1271                     case USHORT:
1272                               uval = CHK_INF127(GET(u_short));
1273                               vok = VUNSIGN;
1274                               break;
1275                     case INT32:
1276                               val = GET(int32_t);
1277                               vok = VSIGN;
1278                               break;
1279                     case KTRACEFLAG:
1280                     case PROCFLAG:
1281                               if (v->flag & ALTPR)
1282                                         break;
1283                               /*FALLTHROUGH*/
1284                     case INT:
1285                               val = GET(int);
1286                               vok = VSIGN;
1287                               break;
1288                     case UINT:
1289                     case UINT32:
1290                               uval = CHK_INF127(GET(u_int));
1291                               vok = VUNSIGN;
1292                               break;
1293                     case LONG:
1294                               val = GET(long);
1295                               vok = VSIGN;
1296                               break;
1297                     case ULONG:
1298                               uval = CHK_INF127(GET(u_long));
1299                               vok = VUNSIGN;
1300                               break;
1301                     case KPTR:
1302                               uval = GET(u_int64_t);
1303                               vok = VPTR;
1304                               break;
1305                     case KPTR24:
1306                               uval = GET(u_int64_t);
1307                               uval &= 0xffffff;
1308                               vok = VPTR;
1309                               break;
1310                     case INT64:
1311                               val = GET(int64_t);
1312                               vok = VSIGN;
1313                               break;
1314                     case UINT64:
1315                               uval = CHK_INF127(GET(u_int64_t));
1316                               vok = VUNSIGN;
1317                               break;
1318 
1319                     case SIGLIST:
1320                     default:
1321                               /* nothing... */;
1322                     }
1323                     switch (vok) {
1324                     case VSIGN:
1325                               if (val < 0 && val < v->longestn) {
1326                                         v->longestn = val;
1327                                         fmtlen = iwidth(-val) + 1;
1328                                         if (fmtlen > v->width)
1329                                                   v->width = fmtlen;
1330                               } else if (val > 0 && val > v->longestp) {
1331                                         v->longestp = val;
1332                                         fmtlen = iwidth(val);
1333                                         if (fmtlen > v->width)
1334                                                   v->width = fmtlen;
1335                               }
1336                               return;
1337                     case VUNSIGN:
1338                               if (uval > v->longestu) {
1339                                         v->longestu = uval;
1340                                         v->width = iwidth(uval);
1341                               }
1342                               return;
1343                     case VPTR:
1344                               fmtlen = 0;
1345                               while (uval > 0) {
1346                                         uval >>= 4;
1347                                         fmtlen++;
1348                               }
1349                               if (fmtlen > v->width)
1350                                         v->width = fmtlen;
1351                               return;
1352                     }
1353           }
1354 
1355           width = v->width;
1356           cp = ofmt + 1;
1357           fcp = v->fmt;
1358           if (v->flag & LJUST)
1359                     *cp++ = '-';
1360           *cp++ = '*';
1361           while ((*cp++ = *fcp++) != '\0')
1362                     continue;
1363 
1364           switch (v->type) {
1365           case CHAR:
1366                     (void)printf(ofmt, width, GET(char));
1367                     return;
1368           case UCHAR:
1369                     (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
1370                     return;
1371           case SHORT:
1372                     (void)printf(ofmt, width, GET(short));
1373                     return;
1374           case PROCACFLAG:
1375                     if (v->flag & ALTPR) {
1376                               printflag(v, CHK_INF127(GET(u_short)), mode);
1377                               return;
1378                     }
1379                     /*FALLTHROUGH*/
1380           case USHORT:
1381                     (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
1382                     return;
1383           case KTRACEFLAG:
1384           case PROCFLAG:
1385                     if (v->flag & ALTPR) {
1386                               printflag(v, GET(int), mode);
1387                               return;
1388                     }
1389                     /*FALLTHROUGH*/
1390           case INT:
1391                     (void)printf(ofmt, width, GET(int));
1392                     return;
1393           case UINT:
1394                     (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
1395                     return;
1396           case LONG:
1397                     (void)printf(ofmt, width, GET(long));
1398                     return;
1399           case ULONG:
1400                     (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
1401                     return;
1402           case KPTR:
1403                     (void)printf(ofmt, width, GET(u_int64_t));
1404                     return;
1405           case KPTR24:
1406                     (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
1407                     return;
1408           case INT32:
1409                     (void)printf(ofmt, width, GET(int32_t));
1410                     return;
1411           case UINT32:
1412                     (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
1413                     return;
1414           case INT64:
1415                     (void)printf(ofmt, width, GET(int64_t));
1416                     return;
1417           case UINT64:
1418                     (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
1419                     return;
1420           case SIGLIST:
1421                     printsig(v, (const sigset_t *)(void *)bp, mode);
1422                     return;
1423           default:
1424                     errx(EXIT_FAILURE, "unknown type %d", v->type);
1425           }
1426 #undef GET
1427 #undef CHK_INF127
1428 }
1429 
1430 void
pvar(struct pinfo * pi,VARENT * ve,enum mode mode)1431 pvar(struct pinfo *pi, VARENT *ve, enum mode mode)
1432 {
1433           VAR *v = ve->var;
1434           char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
1435 
1436           if ((v->flag & UAREA) && !pi->ki->p_uvalid) {
1437                     if (mode == PRINTMODE)
1438                               (void)printf("%*s", v->width, "-");
1439                     return;
1440           }
1441 
1442           (void)printval(b + v->off, v, mode);
1443 }
1444 
1445 void
putimeval(struct pinfo * pi,VARENT * ve,enum mode mode)1446 putimeval(struct pinfo *pi, VARENT *ve, enum mode mode)
1447 {
1448           VAR *v = ve->var;
1449           struct kinfo_proc2 *k = pi->ki;
1450           char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
1451           ulong secs = *(uint32_t *)(b + v->off);
1452           ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t));
1453           int fmtlen;
1454 
1455           if (!k->p_uvalid) {
1456                     if (mode == PRINTMODE)
1457                               (void)printf("%*s", v->width, "-");
1458                     return;
1459           }
1460 
1461           if (mode == WIDTHMODE) {
1462                     if (secs == 0)
1463                               /* non-zero so fmtlen is calculated at least once */
1464                               secs = 1;
1465                     if (secs > v->longestu) {
1466                               v->longestu = secs;
1467                               if (secs <= 999)
1468                                         /* sss.ssssss */
1469                                         fmtlen = iwidth(secs) + 6 + 1;
1470                               else
1471                                         /* hh:mm:ss.ss */
1472                                         fmtlen = iwidth((secs + 1) / SECSPERHOUR)
1473                                                   + 2 + 1 + 2 + 1 + 2 + 1;
1474                               if (fmtlen > v->width)
1475                                         v->width = fmtlen;
1476                     }
1477                     return;
1478           }
1479 
1480           if (secs < 999)
1481                     (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
1482           else {
1483                     uint h, m;
1484                     usec += 5000;
1485                     if (usec >= 1000000) {
1486                               usec -= 1000000;
1487                               secs++;
1488                     }
1489                     m = secs / SECSPERMIN;
1490                     secs -= m * SECSPERMIN;
1491                     h = m / MINSPERHOUR;
1492                     m -= h * MINSPERHOUR;
1493                     (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
1494                         usec / 10000u );
1495           }
1496 }
1497 
1498 void
lname(struct pinfo * pi,VARENT * ve,enum mode mode)1499 lname(struct pinfo *pi, VARENT *ve, enum mode mode)
1500 {
1501           struct kinfo_lwp *l = pi->li;
1502           VAR *v;
1503 
1504           v = ve->var;
1505           if (l->l_name[0] != '\0') {
1506                     strprintorsetwidth(v, l->l_name, mode);
1507                     v->width = min(v->width, KI_LNAMELEN);
1508           } else {
1509                     if (mode == PRINTMODE)
1510                               (void)printf("%-*s", v->width, "-");
1511           }
1512 }
1513