Home | History | Annotate | Line # | Download | only in ps
print.c revision 1.93
      1 /*	$NetBSD: print.c,v 1.93 2005/06/26 19:10:49 christos 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.93 2005/06/26 19:10:49 christos 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 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 		noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
    721 		if (mode == WIDTHMODE) {
    722 			int fmtlen;
    723 
    724 			fmtlen = strlen(ttname) + noctty;
    725 			if (v->width < fmtlen)
    726 				v->width = fmtlen;
    727 		} else {
    728 			if (noctty)
    729 				(void)printf("%-*s-", v->width - 1, ttname);
    730 			else
    731 				(void)printf("%-*s", v->width, ttname);
    732 		}
    733 	}
    734 }
    735 
    736 void
    737 longtname(void *arg, VARENT *ve, int mode)
    738 {
    739 	struct kinfo_proc2 *k;
    740 	VAR *v;
    741 	dev_t dev;
    742 	const char *ttname;
    743 
    744 	k = arg;
    745 	v = ve->var;
    746 	dev = k->p_tdev;
    747 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
    748 		if (mode == PRINTMODE)
    749 			(void)printf("%-*s", v->width, "?");
    750 		else
    751 			if (v->width < 2)
    752 				v->width = 2;
    753 	} else {
    754 		strprintorsetwidth(v, ttname, mode);
    755 	}
    756 }
    757 
    758 void
    759 started(void *arg, VARENT *ve, int mode)
    760 {
    761 	struct kinfo_proc2 *k;
    762 	VAR *v;
    763 	time_t startt;
    764 	struct tm *tp;
    765 	char buf[100], *cp;
    766 
    767 	k = arg;
    768 	v = ve->var;
    769 	if (!k->p_uvalid) {
    770 		if (mode == PRINTMODE)
    771 			(void)printf("%*s", v->width, "-");
    772 		return;
    773 	}
    774 
    775 	startt = k->p_ustart_sec;
    776 	tp = localtime(&startt);
    777 	if (now == 0)
    778 		(void)time(&now);
    779 	if (now - k->p_ustart_sec < SECSPERDAY)
    780 		/* I *hate* SCCS... */
    781 		(void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
    782 	else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
    783 		/* I *hate* SCCS... */
    784 		(void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
    785 	else
    786 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
    787 	/* %e and %l can start with a space. */
    788 	cp = buf;
    789 	if (*cp == ' ')
    790 		cp++;
    791 	strprintorsetwidth(v, cp, mode);
    792 }
    793 
    794 void
    795 lstarted(void *arg, VARENT *ve, int mode)
    796 {
    797 	struct kinfo_proc2 *k;
    798 	VAR *v;
    799 	time_t startt;
    800 	char buf[100];
    801 
    802 	k = arg;
    803 	v = ve->var;
    804 	if (!k->p_uvalid) {
    805 		/*
    806 		 * Minimum width is less than header - we don't
    807 		 * need to check it every time.
    808 		 */
    809 		if (mode == PRINTMODE)
    810 			(void)printf("%*s", v->width, "-");
    811 		return;
    812 	}
    813 	startt = k->p_ustart_sec;
    814 
    815 	/* assume all times are the same length */
    816 	if (mode != WIDTHMODE || v->width == 0) {
    817 		(void)strftime(buf, sizeof(buf) -1, "%c",
    818 		    localtime(&startt));
    819 		strprintorsetwidth(v, buf, mode);
    820 	}
    821 }
    822 
    823 void
    824 elapsed(void *arg, VARENT *ve, int mode)
    825 {
    826 	struct kinfo_proc2 *k;
    827 	VAR *v;
    828 	int32_t origseconds, secs, mins, hours, days;
    829 	int fmtlen, printed_something;
    830 
    831 	k = arg;
    832 	v = ve->var;
    833 	if (k->p_uvalid == 0) {
    834 		origseconds = 0;
    835 	} else {
    836 		if (now == 0)
    837 			(void)time(&now);
    838 		origseconds = now - k->p_ustart_sec;
    839 		if (origseconds < 0) {
    840 			/*
    841 			 * Don't try to be fancy if the machine's
    842 			 * clock has been rewound to before the
    843 			 * process "started".
    844 			 */
    845 			origseconds = 0;
    846 		}
    847 	}
    848 
    849 	secs = origseconds;
    850 	mins = secs / SECSPERMIN;
    851 	secs %= SECSPERMIN;
    852 	hours = mins / MINSPERHOUR;
    853 	mins %= MINSPERHOUR;
    854 	days = hours / HOURSPERDAY;
    855 	hours %= HOURSPERDAY;
    856 
    857 	if (mode == WIDTHMODE) {
    858 		if (origseconds == 0)
    859 			/* non-zero so fmtlen is calculated at least once */
    860 			origseconds = 1;
    861 
    862 		if (origseconds > v->longestp) {
    863 			v->longestp = origseconds;
    864 
    865 			if (days > 0) {
    866 				/* +9 for "-hh:mm:ss" */
    867 				fmtlen = iwidth(days) + 9;
    868 			} else if (hours > 0) {
    869 				/* +6 for "mm:ss" */
    870 				fmtlen = iwidth(hours) + 6;
    871 			} else {
    872 				/* +3 for ":ss" */
    873 				fmtlen = iwidth(mins) + 3;
    874 			}
    875 
    876 			if (fmtlen > v->width)
    877 				v->width = fmtlen;
    878 		}
    879 	} else {
    880 		printed_something = 0;
    881 		fmtlen = v->width;
    882 
    883 		if (days > 0) {
    884 			(void)printf("%*d", fmtlen - 9, days);
    885 			printed_something = 1;
    886 		} else if (fmtlen > 9) {
    887 			(void)printf("%*s", fmtlen - 9, "");
    888 		}
    889 		if (fmtlen > 9)
    890 			fmtlen = 9;
    891 
    892 		if (printed_something) {
    893 			(void)printf("-%.*d", fmtlen - 7, hours);
    894 			printed_something = 1;
    895 		} else if (hours > 0) {
    896 			(void)printf("%*d", fmtlen - 6, hours);
    897 			printed_something = 1;
    898 		} else if (fmtlen > 6) {
    899 			(void)printf("%*s", fmtlen - 6, "");
    900 		}
    901 		if (fmtlen > 6)
    902 			fmtlen = 6;
    903 
    904 		/* Don't need to set fmtlen or printed_something any more... */
    905 		if (printed_something) {
    906 			(void)printf(":%.*d", fmtlen - 4, mins);
    907 		} else if (mins > 0) {
    908 			(void)printf("%*d", fmtlen - 3, mins);
    909 		} else if (fmtlen > 3) {
    910 			(void)printf("%*s", fmtlen - 3, "0");
    911 		}
    912 
    913 		(void)printf(":%.2d", secs);
    914 	}
    915 }
    916 
    917 void
    918 wchan(void *arg, VARENT *ve, int mode)
    919 {
    920 	struct kinfo_lwp *l;
    921 	VAR *v;
    922 	char *buf;
    923 
    924 	l = arg;
    925 	v = ve->var;
    926 	if (l->l_wchan) {
    927 		if (l->l_wmesg) {
    928 			strprintorsetwidth(v, l->l_wmesg, mode);
    929 			v->width = min(v->width, KI_WMESGLEN);
    930 		} else {
    931 			(void)asprintf(&buf, "%-*" PRIx64, v->width,
    932 			    l->l_wchan);
    933 			if (buf == NULL)
    934 				err(1, "%s", "");
    935 			strprintorsetwidth(v, buf, mode);
    936 			v->width = min(v->width, KI_WMESGLEN);
    937 			free(buf);
    938 		}
    939 	} else {
    940 		if (mode == PRINTMODE)
    941 			(void)printf("%-*s", v->width, "-");
    942 	}
    943 }
    944 
    945 #define	pgtok(a)        (((a)*getpagesize())/1024)
    946 
    947 void
    948 vsize(void *arg, VARENT *ve, int mode)
    949 {
    950 	struct kinfo_proc2 *k;
    951 	VAR *v;
    952 
    953 	k = arg;
    954 	v = ve->var;
    955 	intprintorsetwidth(v,
    956 	    pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
    957 }
    958 
    959 void
    960 rssize(void *arg, VARENT *ve, int mode)
    961 {
    962 	struct kinfo_proc2 *k;
    963 	VAR *v;
    964 
    965 	k = arg;
    966 	v = ve->var;
    967 	/* XXX don't have info about shared */
    968 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
    969 }
    970 
    971 void
    972 p_rssize(void *arg, VARENT *ve, int mode)	/* doesn't account for text */
    973 {
    974 	struct kinfo_proc2 *k;
    975 	VAR *v;
    976 
    977 	k = arg;
    978 	v = ve->var;
    979 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
    980 }
    981 
    982 void
    983 cputime(void *arg, VARENT *ve, int mode)
    984 {
    985 	struct kinfo_proc2 *k;
    986 	VAR *v;
    987 	int32_t secs;
    988 	int32_t psecs;	/* "parts" of a second. first micro, then centi */
    989 	int fmtlen;
    990 
    991 	k = arg;
    992 	v = ve->var;
    993 	if (P_ZOMBIE(k) || k->p_uvalid == 0) {
    994 		secs = 0;
    995 		psecs = 0;
    996 	} else {
    997 		/*
    998 		 * This counts time spent handling interrupts.  We could
    999 		 * fix this, but it is not 100% trivial (and interrupt
   1000 		 * time fractions only work on the sparc anyway).	XXX
   1001 		 */
   1002 		secs = k->p_rtime_sec;
   1003 		psecs = k->p_rtime_usec;
   1004 		if (sumrusage) {
   1005 			secs += k->p_uctime_sec;
   1006 			psecs += k->p_uctime_usec;
   1007 		}
   1008 		/*
   1009 		 * round and scale to 100's
   1010 		 */
   1011 		psecs = (psecs + 5000) / 10000;
   1012 		secs += psecs / 100;
   1013 		psecs = psecs % 100;
   1014 	}
   1015 	if (mode == WIDTHMODE) {
   1016 		/*
   1017 		 * Ugg, this is the only field where a value of 0 is longer
   1018 		 * than the column title.
   1019 		 * Use SECSPERMIN, because secs is divided by that when
   1020 		 * passed to iwidth().
   1021 		 */
   1022 		if (secs == 0)
   1023 			secs = SECSPERMIN;
   1024 
   1025 		if (secs > v->longestp) {
   1026 			v->longestp = secs;
   1027 			/* "+6" for the ":%02ld.%02ld" in the printf() below */
   1028 			fmtlen = iwidth(secs / SECSPERMIN) + 6;
   1029 			if (fmtlen > v->width)
   1030 				v->width = fmtlen;
   1031 		}
   1032 	} else {
   1033 		(void)printf("%*ld:%02ld.%02ld", v->width - 6,
   1034 		    (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
   1035 		    (long)psecs);
   1036 	}
   1037 }
   1038 
   1039 double
   1040 getpcpu(k)
   1041 	struct kinfo_proc2 *k;
   1042 {
   1043 	static int failure;
   1044 
   1045 	if (!nlistread)
   1046 		failure = (kd) ? donlist() : 1;
   1047 	if (failure)
   1048 		return (0.0);
   1049 
   1050 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
   1051 
   1052 	/* XXX - I don't like this */
   1053 	if (k->p_swtime == 0 || (k->p_flag & L_INMEM) == 0 ||
   1054 	    k->p_stat == SZOMB)
   1055 		return (0.0);
   1056 	if (rawcpu)
   1057 		return (100.0 * fxtofl(k->p_pctcpu));
   1058 	return (100.0 * fxtofl(k->p_pctcpu) /
   1059 		(1.0 - exp(k->p_swtime * log(ccpu))));
   1060 }
   1061 
   1062 void
   1063 pcpu(void *arg, VARENT *ve, int mode)
   1064 {
   1065 	struct kinfo_proc2 *k;
   1066 	VAR *v;
   1067 
   1068 	k = arg;
   1069 	v = ve->var;
   1070 	doubleprintorsetwidth(v, getpcpu(k), 1, mode);
   1071 }
   1072 
   1073 double
   1074 getpmem(k)
   1075 	struct kinfo_proc2 *k;
   1076 {
   1077 	static int failure;
   1078 	double fracmem;
   1079 	int szptudot;
   1080 
   1081 	if (!nlistread)
   1082 		failure = (kd) ? donlist() : 1;
   1083 	if (failure)
   1084 		return (0.0);
   1085 
   1086 	if ((k->p_flag & L_INMEM) == 0)
   1087 		return (0.0);
   1088 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
   1089 	szptudot = uspace/getpagesize();
   1090 	/* XXX don't have info about shared */
   1091 	fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
   1092 	return (100.0 * fracmem);
   1093 }
   1094 
   1095 void
   1096 pmem(void *arg, VARENT *ve, int mode)
   1097 {
   1098 	struct kinfo_proc2 *k;
   1099 	VAR *v;
   1100 
   1101 	k = arg;
   1102 	v = ve->var;
   1103 	doubleprintorsetwidth(v, getpmem(k), 1, mode);
   1104 }
   1105 
   1106 void
   1107 pagein(void *arg, VARENT *ve, int mode)
   1108 {
   1109 	struct kinfo_proc2 *k;
   1110 	VAR *v;
   1111 
   1112 	k = arg;
   1113 	v = ve->var;
   1114 	intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
   1115 }
   1116 
   1117 void
   1118 maxrss(void *arg, VARENT *ve, int mode)
   1119 {
   1120 	VAR *v;
   1121 
   1122 	v = ve->var;
   1123 	/* No need to check width! */
   1124 	if (mode == PRINTMODE)
   1125 		(void)printf("%*s", v->width, "-");
   1126 }
   1127 
   1128 void
   1129 tsize(void *arg, VARENT *ve, int mode)
   1130 {
   1131 	struct kinfo_proc2 *k;
   1132 	VAR *v;
   1133 
   1134 	k = arg;
   1135 	v = ve->var;
   1136 	intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
   1137 }
   1138 
   1139 /*
   1140  * Generic output routines.  Print fields from various prototype
   1141  * structures.
   1142  */
   1143 static void
   1144 printval(bp, v, mode)
   1145 	void *bp;
   1146 	VAR *v;
   1147 	int mode;
   1148 {
   1149 	static char ofmt[32] = "%";
   1150 	int width, vok, fmtlen;
   1151 	const char *fcp;
   1152 	char *cp;
   1153 	int64_t val;
   1154 	u_int64_t uval;
   1155 
   1156 	val = 0;	/* XXXGCC -Wuninitialized [hpcarm] */
   1157 	uval = 0;	/* XXXGCC -Wuninitialized [hpcarm] */
   1158 
   1159 	/*
   1160 	 * Note that the "INF127" check is nonsensical for types
   1161 	 * that are or can be signed.
   1162 	 */
   1163 #define	GET(type)		(*(type *)bp)
   1164 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
   1165 
   1166 #define	VSIGN	1
   1167 #define	VUNSIGN	2
   1168 #define	VPTR	3
   1169 
   1170 	if (mode == WIDTHMODE) {
   1171 		vok = 0;
   1172 		switch (v->type) {
   1173 		case CHAR:
   1174 			val = GET(char);
   1175 			vok = VSIGN;
   1176 			break;
   1177 		case UCHAR:
   1178 			uval = CHK_INF127(GET(u_char));
   1179 			vok = VUNSIGN;
   1180 			break;
   1181 		case SHORT:
   1182 			val = GET(short);
   1183 			vok = VSIGN;
   1184 			break;
   1185 		case USHORT:
   1186 			uval = CHK_INF127(GET(u_short));
   1187 			vok = VUNSIGN;
   1188 			break;
   1189 		case INT32:
   1190 			val = GET(int32_t);
   1191 			vok = VSIGN;
   1192 			break;
   1193 		case INT:
   1194 			val = GET(int);
   1195 			vok = VSIGN;
   1196 			break;
   1197 		case UINT:
   1198 		case UINT32:
   1199 			uval = CHK_INF127(GET(u_int));
   1200 			vok = VUNSIGN;
   1201 			break;
   1202 		case LONG:
   1203 			val = GET(long);
   1204 			vok = VSIGN;
   1205 			break;
   1206 		case ULONG:
   1207 			uval = CHK_INF127(GET(u_long));
   1208 			vok = VUNSIGN;
   1209 			break;
   1210 		case KPTR:
   1211 			uval = GET(u_int64_t);
   1212 			vok = VPTR;
   1213 			break;
   1214 		case KPTR24:
   1215 			uval = GET(u_int64_t);
   1216 			uval &= 0xffffff;
   1217 			vok = VPTR;
   1218 			break;
   1219 		case INT64:
   1220 			val = GET(int64_t);
   1221 			vok = VSIGN;
   1222 			break;
   1223 		case UINT64:
   1224 			uval = CHK_INF127(GET(u_int64_t));
   1225 			vok = VUNSIGN;
   1226 			break;
   1227 
   1228 		case SIGLIST:
   1229 		default:
   1230 			/* nothing... */;
   1231 		}
   1232 		switch (vok) {
   1233 		case VSIGN:
   1234 			if (val < 0 && val < v->longestn) {
   1235 				v->longestn = val;
   1236 				fmtlen = iwidth(-val) + 1;
   1237 				if (fmtlen > v->width)
   1238 					v->width = fmtlen;
   1239 			} else if (val > 0 && val > v->longestp) {
   1240 				v->longestp = val;
   1241 				fmtlen = iwidth(val);
   1242 				if (fmtlen > v->width)
   1243 					v->width = fmtlen;
   1244 			}
   1245 			return;
   1246 		case VUNSIGN:
   1247 			if (uval > v->longestu) {
   1248 				v->longestu = uval;
   1249 				v->width = iwidth(uval);
   1250 			}
   1251 			return;
   1252 		case VPTR:
   1253 			fmtlen = 0;
   1254 			while (uval > 0) {
   1255 				uval >>= 4;
   1256 				fmtlen++;
   1257 			}
   1258 			if (fmtlen > v->width)
   1259 				v->width = fmtlen;
   1260 			return;
   1261 		}
   1262 	}
   1263 
   1264 	width = v->width;
   1265 	cp = ofmt + 1;
   1266 	fcp = v->fmt;
   1267 	if (v->flag & LJUST)
   1268 		*cp++ = '-';
   1269 	*cp++ = '*';
   1270 	while ((*cp++ = *fcp++) != '\0')
   1271 		continue;
   1272 
   1273 	switch (v->type) {
   1274 	case CHAR:
   1275 		(void)printf(ofmt, width, GET(char));
   1276 		return;
   1277 	case UCHAR:
   1278 		(void)printf(ofmt, width, CHK_INF127(GET(u_char)));
   1279 		return;
   1280 	case SHORT:
   1281 		(void)printf(ofmt, width, GET(short));
   1282 		return;
   1283 	case USHORT:
   1284 		(void)printf(ofmt, width, CHK_INF127(GET(u_short)));
   1285 		return;
   1286 	case INT:
   1287 		(void)printf(ofmt, width, GET(int));
   1288 		return;
   1289 	case UINT:
   1290 		(void)printf(ofmt, width, CHK_INF127(GET(u_int)));
   1291 		return;
   1292 	case LONG:
   1293 		(void)printf(ofmt, width, GET(long));
   1294 		return;
   1295 	case ULONG:
   1296 		(void)printf(ofmt, width, CHK_INF127(GET(u_long)));
   1297 		return;
   1298 	case KPTR:
   1299 		(void)printf(ofmt, width, GET(u_int64_t));
   1300 		return;
   1301 	case KPTR24:
   1302 		(void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
   1303 		return;
   1304 	case INT32:
   1305 		(void)printf(ofmt, width, GET(int32_t));
   1306 		return;
   1307 	case UINT32:
   1308 		(void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
   1309 		return;
   1310 	case SIGLIST:
   1311 		{
   1312 			sigset_t *s = (sigset_t *)(void *)bp;
   1313 			size_t i;
   1314 #define	SIGSETSIZE	(sizeof(s->__bits) / sizeof(s->__bits[0]))
   1315 			char buf[SIGSETSIZE * 8 + 1];
   1316 
   1317 			for (i = 0; i < SIGSETSIZE; i++)
   1318 				(void)snprintf(&buf[i * 8], 9, "%.8x",
   1319 				    s->__bits[(SIGSETSIZE - 1) - i]);
   1320 
   1321 			/* Skip leading zeroes */
   1322 			for (i = 0; buf[i] == '0'; i++)
   1323 				continue;
   1324 
   1325 			if (buf[i] == '\0')
   1326 				i--;
   1327 			strprintorsetwidth(v, buf + i, mode);
   1328 #undef SIGSETSIZE
   1329 		}
   1330 		return;
   1331 	case INT64:
   1332 		(void)printf(ofmt, width, GET(int64_t));
   1333 		return;
   1334 	case UINT64:
   1335 		(void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
   1336 		return;
   1337 	default:
   1338 		errx(1, "unknown type %d", v->type);
   1339 	}
   1340 #undef GET
   1341 #undef CHK_INF127
   1342 }
   1343 
   1344 void
   1345 pvar(void *arg, VARENT *ve, int mode)
   1346 {
   1347 	VAR *v;
   1348 
   1349 	v = ve->var;
   1350 	if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) {
   1351 		if (mode == PRINTMODE)
   1352 			(void)printf("%*s", v->width, "-");
   1353 		return;
   1354 	}
   1355 
   1356 	(void)printval((char *)arg + v->off, v, mode);
   1357 }
   1358 
   1359 void
   1360 putimeval(void *arg, VARENT *ve, int mode)
   1361 {
   1362 	VAR *v = ve->var;
   1363 	struct kinfo_proc2 *k = arg;
   1364 	ulong secs = *(uint32_t *)((char *)arg + v->off);
   1365 	ulong usec = *(uint32_t *)((char *)arg + v->off + sizeof (uint32_t));
   1366 	int fmtlen;
   1367 
   1368 	if (!k->p_uvalid) {
   1369 		if (mode == PRINTMODE)
   1370 			(void)printf("%*s", v->width, "-");
   1371 		return;
   1372 	}
   1373 
   1374 	if (mode == WIDTHMODE) {
   1375 		if (secs == 0)
   1376 			/* non-zero so fmtlen is calculated at least once */
   1377 			secs = 1;
   1378 		if (secs > v->longestu) {
   1379 			v->longestu = secs;
   1380 			if (secs <= 999)
   1381 				/* sss.ssssss */
   1382 				fmtlen = iwidth(secs) + 6 + 1;
   1383 			else
   1384 				/* hh:mm:ss.ss */
   1385 				fmtlen = iwidth((secs + 1) / SECSPERHOUR)
   1386 					+ 2 + 1 + 2 + 1 + 2 + 1;
   1387 			if (fmtlen > v->width)
   1388 				v->width = fmtlen;
   1389 		}
   1390 		return;
   1391 	}
   1392 
   1393 	if (secs < 999)
   1394 		(void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
   1395 	else {
   1396 		uint h, m;
   1397 		usec += 5000;
   1398 		if (usec >= 1000000) {
   1399 			usec -= 1000000;
   1400 			secs++;
   1401 		}
   1402 		m = secs / SECSPERMIN;
   1403 		secs -= m * SECSPERMIN;
   1404 		h = m / MINSPERHOUR;
   1405 		m -= h * MINSPERHOUR;
   1406 		(void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
   1407 		    usec / 10000u );
   1408 	}
   1409 }
   1410