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