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