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