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