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