Home | History | Annotate | Line # | Download | only in ps
print.c revision 1.54
      1 /*	$NetBSD: print.c,v 1.54 2000/06/08 00:51:10 simonb Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1990, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)print.c	8.6 (Berkeley) 4/16/94";
     40 #else
     41 __RCSID("$NetBSD: print.c,v 1.54 2000/06/08 00:51:10 simonb Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 #include <sys/param.h>
     46 #include <sys/time.h>
     47 #include <sys/resource.h>
     48 #include <sys/proc.h>
     49 #include <sys/stat.h>
     50 #include <sys/ucred.h>
     51 #include <sys/sysctl.h>
     52 
     53 #include <vm/vm.h>
     54 
     55 #include <err.h>
     56 #include <kvm.h>
     57 #include <math.h>
     58 #include <nlist.h>
     59 #include <pwd.h>
     60 #include <stddef.h>
     61 #include <stdio.h>
     62 #include <stdlib.h>
     63 #include <string.h>
     64 #include <time.h>
     65 #include <tzfile.h>
     66 #include <unistd.h>
     67 
     68 #include "ps.h"
     69 
     70 static char *cmdpart __P((char *));
     71 static void  printval __P((void *, VAR *, int));
     72 static int   titlecmp __P((char *, char **));
     73 
     74 static void  doubleprintorsetwidth __P((VAR *, double, int, int));
     75 static void  intprintorsetwidth __P((VAR *, int, int));
     76 static void  strprintorsetwidth __P((VAR *, const char *, int));
     77 
     78 #define	min(a,b)	((a) <= (b) ? (a) : (b))
     79 #define	max(a,b)	((a) >= (b) ? (a) : (b))
     80 
     81 static char *
     82 cmdpart(arg0)
     83 	char *arg0;
     84 {
     85 	char *cp;
     86 
     87 	return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
     88 }
     89 
     90 void
     91 printheader()
     92 {
     93 	int len;
     94 	VAR *v;
     95 	struct varent *vent;
     96 	static int firsttime = 1;
     97 
     98 	for (vent = vhead; vent; vent = vent->next) {
     99 		v = vent->var;
    100 		if (firsttime && vent->next != NULL) {
    101 			len = strlen(v->header);
    102 			if (len > v->width)
    103 				v->width = len;
    104 			totwidth += v->width + 1;	/* +1 for space */
    105 		}
    106 		if (v->flag & LJUST) {
    107 			if (vent->next == NULL)	/* last one */
    108 				(void)printf("%s", v->header);
    109 			else
    110 				(void)printf("%-*s", v->width,
    111 				    v->header);
    112 		} else
    113 			(void)printf("%*s", v->width, v->header);
    114 		if (vent->next != NULL)
    115 			(void)putchar(' ');
    116 	}
    117 	(void)putchar('\n');
    118 	if (firsttime)
    119 		firsttime = 0;
    120 }
    121 
    122 static int
    123 titlecmp(name, argv)
    124 	char *name;
    125 	char **argv;
    126 {
    127 	char *title;
    128 	int namelen;
    129 
    130 	if (argv == 0 || argv[0] == 0)
    131 		return (1);
    132 
    133 	title = cmdpart(argv[0]);
    134 
    135 	if (!strcmp(name, title))
    136 		return (0);
    137 
    138 	if (title[0] == '-' && !strcmp(name, title+1))
    139 		return (0);
    140 
    141 	namelen = strlen(name);
    142 
    143 	if (argv[1] == 0 &&
    144 	    !strncmp(name, title, namelen) &&
    145 	    title[namelen+0] == ':' &&
    146 	    title[namelen+1] == ' ')
    147 		return (0);
    148 
    149 	return (1);
    150 }
    151 
    152 static void
    153 doubleprintorsetwidth(v, val, prec, mode)
    154 	VAR *v;
    155 	double val;
    156 	int prec;
    157 	int mode;
    158 {
    159 	int fmtlen;
    160 
    161 	if (mode == WIDTHMODE) {
    162 		if (val < 0.0 && val < v->longestnd) {
    163 			fmtlen = (int)log10(-val) + prec + 2;
    164 			v->longestnd = val;
    165 			if (fmtlen > v->width)
    166 				v->width = fmtlen;
    167 		} else if (val > 0.0 && val > v->longestpd) {
    168 			fmtlen = (int)log10(val) + prec + 1;
    169 			v->longestpd = val;
    170 			if (fmtlen > v->width)
    171 				v->width = fmtlen;
    172 		}
    173 	} else {
    174 		printf("%*.*f", v->width, prec, val);
    175 	}
    176 }
    177 
    178 static void
    179 intprintorsetwidth(v, val, mode)
    180 	VAR *v;
    181 	int val;
    182 	int mode;
    183 {
    184 	int fmtlen;
    185 
    186 	if (mode == WIDTHMODE) {
    187 		if (val < 0 && val < v->longestn) {
    188 			fmtlen = (int)log10((double)-val) + 2;
    189 			v->longestn = val;
    190 			if (fmtlen > v->width)
    191 				v->width = fmtlen;
    192 		} else if (val > 0 && val > v->longestp) {
    193 			fmtlen = (int)log10((double)val) + 1;
    194 			v->longestp = val;
    195 			if (fmtlen > v->width)
    196 				v->width = fmtlen;
    197 		}
    198 	} else
    199 		printf("%*d", v->width, val);
    200 }
    201 
    202 static void
    203 strprintorsetwidth(v, str, mode)
    204 	VAR *v;
    205 	const char *str;
    206 {
    207 	int len;
    208 
    209 	if (mode == WIDTHMODE) {
    210 		len = strlen(str);
    211 		if (len > v->width)
    212 			v->width = len;
    213 	} else {
    214 		if (v->flag & LJUST)
    215 			printf("%-*.*s", v->width, v->width, str);
    216 		else
    217 			printf("%*.*s", v->width, v->width, str);
    218 	}
    219 }
    220 
    221 void
    222 command(ki, ve, mode)
    223 	struct kinfo_proc2 *ki;
    224 	VARENT *ve;
    225 	int mode;
    226 {
    227 	VAR *v;
    228 	int left;
    229 	char **argv, **p, *name;
    230 
    231 	v = ve->var;
    232 	if (mode == WIDTHMODE) {
    233 		v->width = 0;
    234 		return;
    235 	}
    236 	v = ve->var;
    237 	if (ve->next != NULL || termwidth != UNLIMITED) {
    238 		if (ve->next == NULL) {
    239 			left = termwidth - totwidth;
    240 			if (left < 1) /* already wrapped, just use std width */
    241 				left = v->width;
    242 		} else
    243 			left = v->width;
    244 	} else
    245 		left = -1;
    246 	if (needenv && kd) {
    247 		argv = kvm_getenvv2(kd, ki, termwidth);
    248 		if ((p = argv) != NULL) {
    249 			while (*p) {
    250 				fmt_puts(*p, &left);
    251 				p++;
    252 				fmt_putc(' ', &left);
    253 			}
    254 		}
    255 	}
    256 	if (needcomm) {
    257 		name = ki->p_comm;
    258 		if (!commandonly) {
    259 			argv = NULL;
    260 			if (!use_procfs)
    261 				argv = kvm_getargv2(kd, ki, termwidth);
    262 			else
    263 				argv = procfs_getargv(ki, termwidth);
    264 			if ((p = argv) != NULL) {
    265 				while (*p) {
    266 					fmt_puts(*p, &left);
    267 					p++;
    268 					fmt_putc(' ', &left);
    269 				}
    270 			}
    271 			if (titlecmp(name, argv)) {
    272 				fmt_putc('(', &left);
    273 				fmt_puts(name, &left);
    274 				fmt_putc(')', &left);
    275 			}
    276 			if (use_procfs && argv) {
    277 				free(argv[0]);
    278 				free(argv);
    279 			}
    280 		} else {
    281 			fmt_puts(name, &left);
    282 		}
    283 	}
    284 	if (ve->next && left > 0)
    285 		printf("%*s", left, "");
    286 }
    287 
    288 void
    289 ucomm(k, ve, mode)
    290 	struct kinfo_proc2 *k;
    291 	VARENT *ve;
    292 	int mode;
    293 {
    294 	VAR *v;
    295 
    296 	v = ve->var;
    297 	strprintorsetwidth(v, k->p_comm, mode);
    298 }
    299 
    300 void
    301 logname(k, ve, mode)
    302 	struct kinfo_proc2 *k;
    303 	VARENT *ve;
    304 	int mode;
    305 {
    306 	VAR *v;
    307 
    308 	v = ve->var;
    309 	strprintorsetwidth(v, k->p_login, mode);
    310 }
    311 
    312 void
    313 state(k, ve, mode)
    314 	struct kinfo_proc2 *k;
    315 	VARENT *ve;
    316 	int mode;
    317 {
    318 	int flag, is_zombie;
    319 	char *cp;
    320 	VAR *v;
    321 	char buf[16];
    322 
    323 	is_zombie = 0;
    324 	v = ve->var;
    325 	flag = k->p_flag;
    326 	cp = buf;
    327 
    328 	switch (k->p_stat) {
    329 
    330 	case SSTOP:
    331 		*cp = 'T';
    332 		break;
    333 
    334 	case SSLEEP:
    335 		if (flag & P_SINTR)	/* interuptable (long) */
    336 			*cp = k->p_slptime >= MAXSLP ? 'I' : 'S';
    337 		else
    338 			*cp = 'D';
    339 		break;
    340 
    341 	case SRUN:
    342 	case SIDL:
    343 	case SONPROC:
    344 		*cp = 'R';
    345 		break;
    346 
    347 	case SZOMB:
    348 	case SDEAD:
    349 		*cp = 'Z';
    350 		is_zombie = 1;
    351 		break;
    352 
    353 	default:
    354 		*cp = '?';
    355 	}
    356 	cp++;
    357 	if (flag & P_INMEM) {
    358 	} else
    359 		*cp++ = 'W';
    360 	if (k->p_nice < NZERO)
    361 		*cp++ = '<';
    362 	else if (k->p_nice > NZERO)
    363 		*cp++ = 'N';
    364 	if (flag & P_TRACED)
    365 		*cp++ = 'X';
    366 	if (flag & P_WEXIT && !is_zombie)
    367 		*cp++ = 'E';
    368 	if (flag & P_PPWAIT)
    369 		*cp++ = 'V';
    370 	if ((flag & P_SYSTEM) || k->p_holdcnt)
    371 		*cp++ = 'L';
    372 	if (k->p_eflag & EPROC_SLEADER)
    373 		*cp++ = 's';
    374 	if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
    375 		*cp++ = '+';
    376 	*cp = '\0';
    377 	strprintorsetwidth(v, buf, mode);
    378 }
    379 
    380 void
    381 pnice(k, ve, mode)
    382 	struct kinfo_proc2 *k;
    383 	VARENT *ve;
    384 	int mode;
    385 {
    386 	VAR *v;
    387 
    388 	v = ve->var;
    389 	intprintorsetwidth(v, k->p_nice - NZERO, mode);
    390 }
    391 
    392 void
    393 pri(k, ve, mode)
    394 	struct kinfo_proc2 *k;
    395 	VARENT *ve;
    396 	int mode;
    397 {
    398 	VAR *v;
    399 
    400 	v = ve->var;
    401 	intprintorsetwidth(v, k->p_priority - PZERO, mode);
    402 }
    403 
    404 void
    405 uname(k, ve, mode)
    406 	struct kinfo_proc2 *k;
    407 	VARENT *ve;
    408 	int mode;
    409 {
    410 	VAR *v;
    411 
    412 	v = ve->var;
    413 	strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
    414 }
    415 
    416 void
    417 runame(k, ve, mode)
    418 	struct kinfo_proc2 *k;
    419 	VARENT *ve;
    420 	int mode;
    421 {
    422 	VAR *v;
    423 
    424 	v = ve->var;
    425 	strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
    426 }
    427 
    428 void
    429 tdev(k, ve, mode)
    430 	struct kinfo_proc2 *k;
    431 	VARENT *ve;
    432 	int mode;
    433 {
    434 	VAR *v;
    435 	dev_t dev;
    436 	char buff[16];
    437 
    438 	v = ve->var;
    439 	dev = k->p_tdev;
    440 	if (dev == NODEV) {
    441 		/*
    442 		 * Minimum width is width of header - we don't
    443 		 * need to check it every time.
    444 		 */
    445 		if (mode == PRINTMODE)
    446 			(void)printf("%*s", v->width, "??");
    447 	} else {
    448 		(void)snprintf(buff, sizeof(buff),
    449 		    "%d/%d", major(dev), minor(dev));
    450 		strprintorsetwidth(v, buff, mode);
    451 	}
    452 }
    453 
    454 void
    455 tname(k, ve, mode)
    456 	struct kinfo_proc2 *k;
    457 	VARENT *ve;
    458 	int mode;
    459 {
    460 	VAR *v;
    461 	dev_t dev;
    462 	const char *ttname;
    463 	int noctty;
    464 
    465 	v = ve->var;
    466 	dev = k->p_tdev;
    467 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
    468 		/*
    469 		 * Minimum width is width of header - we don't
    470 		 * need to check it every time.
    471 		 */
    472 		if (mode == PRINTMODE)
    473 			(void)printf("%-*s", v->width, "??");
    474 	} else {
    475 		if (strncmp(ttname, "tty", 3) == 0 ||
    476 		    strncmp(ttname, "dty", 3) == 0)
    477 			ttname += 3;
    478 		noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
    479 		if (mode == WIDTHMODE) {
    480 			int fmtlen;
    481 
    482 			fmtlen = strlen(ttname) + noctty;
    483 			if (v->width < fmtlen)
    484 				v->width = fmtlen;
    485 		} else {
    486 			if (noctty)
    487 				printf("%-*s-", v->width - 1, ttname);
    488 			else
    489 				printf("%-*s", v->width, ttname);
    490 		}
    491 	}
    492 }
    493 
    494 void
    495 longtname(k, ve, mode)
    496 	struct kinfo_proc2 *k;
    497 	VARENT *ve;
    498 	int mode;
    499 {
    500 	VAR *v;
    501 	dev_t dev;
    502 	const char *ttname;
    503 
    504 	v = ve->var;
    505 	dev = k->p_tdev;
    506 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
    507 		/*
    508 		 * Minimum width is width of header - we don't
    509 		 * need to check it every time.
    510 		 */
    511 		if (mode == PRINTMODE)
    512 			(void)printf("%-*s", v->width, "??");
    513 	}
    514 	else {
    515 		strprintorsetwidth(v, ttname, mode);
    516 	}
    517 }
    518 
    519 void
    520 started(k, ve, mode)
    521 	struct kinfo_proc2 *k;
    522 	VARENT *ve;
    523 	int mode;
    524 {
    525 	VAR *v;
    526 	static time_t now;
    527 	time_t startt;
    528 	struct tm *tp;
    529 	char buf[100], *cp;
    530 
    531 	/*
    532 	 * XXX: The maximum width of this field is the same as the header
    533 	 *      "STARTED" for locales that have 3 letter abbreviated month
    534 	 *      names and 2 letter am/pm descriptions.
    535 	 */
    536 	if (mode == WIDTHMODE)
    537 		return;
    538 
    539 	v = ve->var;
    540 	if (!k->p_uvalid) {
    541 		if (mode == PRINTMODE)
    542 			(void)printf("%*s", v->width, "-");
    543 		return;
    544 	}
    545 
    546 	startt = k->p_ustart_sec;
    547 	tp = localtime(&startt);
    548 	if (!now)
    549 		(void)time(&now);
    550 	if (now - k->p_ustart_sec < SECSPERDAY)
    551 		/* I *hate* SCCS... */
    552 		(void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
    553 	else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
    554 		/* I *hate* SCCS... */
    555 		(void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
    556 	else
    557 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
    558 	/* %e and %l can start with a space. */
    559 	cp = buf;
    560 	if (*cp == ' ')
    561 		cp++;
    562 	strprintorsetwidth(v, cp, mode);
    563 }
    564 
    565 void
    566 lstarted(k, ve, mode)
    567 	struct kinfo_proc2 *k;
    568 	VARENT *ve;
    569 	int mode;
    570 {
    571 	VAR *v;
    572 	time_t startt;
    573 	char buf[100];
    574 
    575 	v = ve->var;
    576 	if (!k->p_uvalid) {
    577 		/*
    578 		 * Minimum width is less than header - we don't
    579 		 * need to check it every time.
    580 		 */
    581 		if (mode == PRINTMODE)
    582 			(void)printf("%*s", v->width, "-");
    583 		return;
    584 	}
    585 	startt = k->p_ustart_sec;
    586 
    587 	/* assume all times are the same length */
    588 	if (mode != WIDTHMODE || v->width == 0) {
    589 		(void)strftime(buf, sizeof(buf) -1, "%c",
    590 		    localtime(&startt));
    591 		strprintorsetwidth(v, buf, mode);
    592 	}
    593 }
    594 
    595 void
    596 wchan(k, ve, mode)
    597 	struct kinfo_proc2 *k;
    598 	VARENT *ve;
    599 	int mode;
    600 {
    601 	VAR *v;
    602 	char *buf;
    603 
    604 	v = ve->var;
    605 	if (k->p_wchan) {
    606 		if (k->p_wmesg) {
    607 			strprintorsetwidth(v, k->p_wmesg, mode);
    608 			v->width = min(v->width, WMESGLEN);
    609 		} else {
    610 			(void)asprintf(&buf, "%-*llx", v->width,
    611 			    (long long)k->p_wchan);
    612 			if (buf == NULL)
    613 				err(1, "%s", "");
    614 			strprintorsetwidth(v, buf, mode);
    615 			v->width = min(v->width, WMESGLEN);
    616 			free(buf);
    617 		}
    618 	} else {
    619 		if (mode == PRINTMODE)
    620 			(void)printf("%-*s", v->width, "-");
    621 	}
    622 }
    623 
    624 #define pgtok(a)        (((a)*getpagesize())/1024)
    625 
    626 void
    627 vsize(k, ve, mode)
    628 	struct kinfo_proc2 *k;
    629 	VARENT *ve;
    630 	int mode;
    631 {
    632 	VAR *v;
    633 
    634 	v = ve->var;
    635 	intprintorsetwidth(v,
    636 	    pgtok(k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize), mode);
    637 }
    638 
    639 void
    640 rssize(k, ve, mode)
    641 	struct kinfo_proc2 *k;
    642 	VARENT *ve;
    643 	int mode;
    644 {
    645 	VAR *v;
    646 
    647 	v = ve->var;
    648 	/* XXX don't have info about shared */
    649 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
    650 }
    651 
    652 void
    653 p_rssize(k, ve, mode)		/* doesn't account for text */
    654 	struct kinfo_proc2 *k;
    655 	VARENT *ve;
    656 	int mode;
    657 {
    658 	VAR *v;
    659 
    660 	v = ve->var;
    661 	intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
    662 }
    663 
    664 void
    665 cputime(k, ve, mode)
    666 	struct kinfo_proc2 *k;
    667 	VARENT *ve;
    668 	int mode;
    669 {
    670 	VAR *v;
    671 	long secs;
    672 	long psecs;	/* "parts" of a second. first micro, then centi */
    673 	int fmtlen;
    674 
    675 	v = ve->var;
    676 	if (P_ZOMBIE(k) || k->p_uvalid == 0) {
    677 		secs = 0;
    678 		psecs = 0;
    679 	} else {
    680 		/*
    681 		 * This counts time spent handling interrupts.  We could
    682 		 * fix this, but it is not 100% trivial (and interrupt
    683 		 * time fractions only work on the sparc anyway).	XXX
    684 		 */
    685 		secs = k->p_rtime_sec;
    686 		psecs = k->p_rtime_usec;
    687 		if (sumrusage) {
    688 			secs += k->p_uctime_sec;
    689 			psecs += k->p_uctime_usec;
    690 		}
    691 		/*
    692 		 * round and scale to 100's
    693 		 */
    694 		psecs = (psecs + 5000) / 10000;
    695 		secs += psecs / 100;
    696 		psecs = psecs % 100;
    697 	}
    698 	if (mode == WIDTHMODE) {
    699 		/*
    700 		 * Ugg, this is the only field where a value of 0 longer
    701 		 * than the column title, and log10(0) isn't good enough.
    702 		 * Use SECSPERMIN, because secs is divided by that when
    703 		 * passed to log10().
    704 		 */
    705 		if (secs == 0 && v->longestp == 0)
    706 			secs = SECSPERMIN;
    707 		if (secs > v->longestp) {
    708 			/* "+6" for the "%02ld.%02ld" in the printf() below */
    709 			fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
    710 			v->longestp = secs;
    711 			if (fmtlen > v->width)
    712 				v->width = fmtlen;
    713 		}
    714 	} else {
    715 		printf("%*ld:%02ld.%02ld", v->width - 6, secs / SECSPERMIN,
    716 		    secs % SECSPERMIN, psecs);
    717 	}
    718 }
    719 
    720 double
    721 getpcpu(k)
    722 	struct kinfo_proc2 *k;
    723 {
    724 	static int failure;
    725 
    726 	if (!nlistread)
    727 		failure = (kd) ? donlist() : 1;
    728 	if (failure)
    729 		return (0.0);
    730 
    731 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
    732 
    733 	/* XXX - I don't like this */
    734 	if (k->p_swtime == 0 || (k->p_flag & P_INMEM) == 0 ||
    735 	    k->p_stat == SZOMB || k->p_stat == SDEAD)
    736 		return (0.0);
    737 	if (rawcpu)
    738 		return (100.0 * fxtofl(k->p_pctcpu));
    739 	return (100.0 * fxtofl(k->p_pctcpu) /
    740 		(1.0 - exp(k->p_swtime * log(ccpu))));
    741 }
    742 
    743 void
    744 pcpu(k, ve, mode)
    745 	struct kinfo_proc2 *k;
    746 	VARENT *ve;
    747 	int mode;
    748 {
    749 	VAR *v;
    750 
    751 	v = ve->var;
    752 	doubleprintorsetwidth(v, getpcpu(k), 1, mode);
    753 }
    754 
    755 double
    756 getpmem(k)
    757 	struct kinfo_proc2 *k;
    758 {
    759 	static int failure;
    760 	double fracmem;
    761 	int szptudot;
    762 
    763 	if (!nlistread)
    764 		failure = (kd) ? donlist() : 1;
    765 	if (failure)
    766 		return (0.0);
    767 
    768 	if ((k->p_flag & P_INMEM) == 0)
    769 		return (0.0);
    770 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
    771 	szptudot = USPACE/getpagesize();
    772 	/* XXX don't have info about shared */
    773 	fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
    774 	return (100.0 * fracmem);
    775 }
    776 
    777 void
    778 pmem(k, ve, mode)
    779 	struct kinfo_proc2 *k;
    780 	VARENT *ve;
    781 	int mode;
    782 {
    783 	VAR *v;
    784 
    785 	v = ve->var;
    786 	doubleprintorsetwidth(v, getpmem(k), 1, mode);
    787 }
    788 
    789 void
    790 pagein(k, ve, mode)
    791 	struct kinfo_proc2 *k;
    792 	VARENT *ve;
    793 	int mode;
    794 {
    795 	VAR *v;
    796 
    797 	v = ve->var;
    798 	intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
    799 }
    800 
    801 void
    802 maxrss(k, ve, mode)
    803 	struct kinfo_proc2 *k;
    804 	VARENT *ve;
    805 	int mode;
    806 {
    807 	VAR *v;
    808 
    809 	v = ve->var;
    810 	/* No need to check width! */
    811 	if (mode == PRINTMODE)
    812 		(void)printf("%*s", v->width, "-");
    813 }
    814 
    815 void
    816 tsize(k, ve, mode)
    817 	struct kinfo_proc2 *k;
    818 	VARENT *ve;
    819 	int mode;
    820 {
    821 	VAR *v;
    822 
    823 	v = ve->var;
    824 	intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
    825 }
    826 
    827 /*
    828  * Generic output routines.  Print fields from various prototype
    829  * structures.
    830  */
    831 static void
    832 printval(bp, v, mode)
    833 	void *bp;
    834 	VAR *v;
    835 	int mode;
    836 {
    837 	static char ofmt[32] = "%";
    838 	int width, vok, fmtlen;
    839 	char *fcp, *cp, *obuf;
    840 	enum type type;
    841 	long long val;
    842 	unsigned long long uval;
    843 
    844 	/*
    845 	 * Note that the "INF127" check is nonsensical for types
    846 	 * that are or can be signed.
    847 	 */
    848 #define	GET(type)		(*(type *)bp)
    849 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
    850 
    851 #define	VSIGN	1
    852 #define	VUNSIGN	2
    853 #define	VPTR	3
    854 
    855 	if (mode == WIDTHMODE) {
    856 		vok = 0;
    857 		switch (v->type) {
    858 		case CHAR:
    859 			val = GET(char);
    860 			vok = VSIGN;
    861 			break;
    862 		case UCHAR:
    863 			uval = CHK_INF127(GET(u_char));
    864 			vok = VUNSIGN;
    865 			break;
    866 		case SHORT:
    867 			val = GET(short);
    868 			vok = VSIGN;
    869 			break;
    870 		case USHORT:
    871 			uval = CHK_INF127(GET(u_short));
    872 			vok = VUNSIGN;
    873 			break;
    874 		case INT32:
    875 			val = GET(int32_t);
    876 			vok = VSIGN;
    877 			break;
    878 		case INT:
    879 			val = GET(int);
    880 			vok = VSIGN;
    881 			break;
    882 		case UINT:
    883 		case UINT32:
    884 			uval = CHK_INF127(GET(u_int));
    885 			vok = VUNSIGN;
    886 			break;
    887 		case LONG:
    888 			val = GET(long);
    889 			vok = VSIGN;
    890 			break;
    891 		case ULONG:
    892 			uval = CHK_INF127(GET(u_long));
    893 			vok = VUNSIGN;
    894 			break;
    895 		case KPTR:
    896 			uval = GET(u_long);
    897 			vok = VPTR;
    898 			break;
    899 		case KPTR24:
    900 			uval = GET(u_long) & 0xffffff;
    901 			vok = VPTR;
    902 			break;
    903 		default:
    904 			/* nothing... */;
    905 		}
    906 		switch (vok) {
    907 		case VSIGN:
    908 			if (val < 0  && val < v->longestn) {
    909 				fmtlen = (int)log10((double)-val) + 2;
    910 				v->longestn = val;
    911 				if (fmtlen > v->width)
    912 					v->width = fmtlen;
    913 			} else if (val > 0 && val > v->longestp) {
    914 				fmtlen = (int)log10((double)val) + 1;
    915 				v->longestp = val;
    916 				if (fmtlen > v->width)
    917 					v->width = fmtlen;
    918 			}
    919 			return;
    920 		case VUNSIGN:
    921 			if (uval > v->longestu) {
    922 				fmtlen = (int)log10((double)uval) + 1;
    923 				v->longestu = uval;
    924 				v->width = fmtlen;
    925 			}
    926 			return;
    927 		case VPTR:
    928 			fmtlen = 0;
    929 			while (uval > 0) {
    930 				uval >>= 4;
    931 				fmtlen++;
    932 			}
    933 			if (fmtlen > v->width)
    934 				v->width = fmtlen;
    935 			return;
    936 		}
    937 	}
    938 
    939 	width = v->width;
    940 	cp = ofmt + 1;
    941 	fcp = v->fmt;
    942 	if (v->flag & LJUST)
    943 		*cp++ = '-';
    944 	*cp++ = '*';
    945 	while ((*cp++ = *fcp++) != '\0')
    946 		continue;
    947 
    948 	switch (v->type) {
    949 	case INT32:
    950 		if (sizeof(int32_t) == sizeof(int))
    951 			type = INT;
    952 		else if (sizeof(int32_t) == sizeof(long))
    953 			type = LONG;
    954 		else
    955 			errx(1, "unknown conversion for type %d", v->type);
    956 		break;
    957 	case UINT32:
    958 		if (sizeof(u_int32_t) == sizeof(u_int))
    959 			type = UINT;
    960 		else if (sizeof(u_int32_t) == sizeof(u_long))
    961 			type = ULONG;
    962 		else
    963 			errx(1, "unknown conversion for type %d", v->type);
    964 		break;
    965 	default:
    966 		type = v->type;
    967 		break;
    968 	}
    969 
    970 	switch (type) {
    971 	case CHAR:
    972 		(void)printf(ofmt, width, GET(char));
    973 		return;
    974 	case UCHAR:
    975 		(void)printf(ofmt, width, CHK_INF127(GET(u_char)));
    976 		return;
    977 	case SHORT:
    978 		(void)printf(ofmt, width, GET(short));
    979 		return;
    980 	case USHORT:
    981 		(void)printf(ofmt, width, CHK_INF127(GET(u_short)));
    982 		return;
    983 	case INT:
    984 		(void)printf(ofmt, width, GET(int));
    985 		return;
    986 	case UINT:
    987 		(void)printf(ofmt, width, CHK_INF127(GET(u_int)));
    988 		return;
    989 	case LONG:
    990 		(void)printf(ofmt, width, GET(long));
    991 		return;
    992 	case ULONG:
    993 		(void)printf(ofmt, width, CHK_INF127(GET(u_long)));
    994 		return;
    995 	case KPTR:
    996 		(void)printf(ofmt, width, GET(u_long));
    997 		return;
    998 	case KPTR24:
    999 		(void)printf(ofmt, width, GET(u_long) & 0xffffff);
   1000 		return;
   1001 	case SIGLIST:
   1002 		{
   1003 			sigset_t *s = (sigset_t *)(void *)bp;
   1004 			size_t i;
   1005 #define SIGSETSIZE	(sizeof(s->__bits) / sizeof(s->__bits[0]))
   1006 			char buf[SIGSETSIZE * 8 + 1];
   1007 
   1008 			for (i = 0; i < SIGSETSIZE; i++)
   1009 				(void)snprintf(&buf[i * 8], 9, "%.8x",
   1010 				    s->__bits[(SIGSETSIZE - 1) - i]);
   1011 
   1012 			/* Skip leading zeroes */
   1013 			for (i = 0; buf[i]; i++)
   1014 				if (buf[i] != '0')
   1015 					break;
   1016 
   1017 			if (buf[i] == '\0')
   1018 				i--;
   1019 			(void)asprintf(&obuf, ofmt, width, &buf[i]);
   1020 		}
   1021 		break;
   1022 	default:
   1023 		errx(1, "unknown type %d", v->type);
   1024 	}
   1025 	if (obuf == NULL)
   1026 		err(1, "%s", "");
   1027 	if (mode == WIDTHMODE) {
   1028 		/* Skip leading spaces. */
   1029 		cp = strrchr(obuf, ' ');
   1030 		if (cp == NULL)
   1031 			cp = obuf;
   1032 		else
   1033 			cp++;	/* skip last space */
   1034 	}
   1035 	else
   1036 		cp = obuf;
   1037 	strprintorsetwidth(v, cp, mode);
   1038 	free(obuf);
   1039 #undef GET
   1040 #undef CHK_INF127
   1041 }
   1042 
   1043 void
   1044 pvar(k, ve, mode)
   1045 	struct kinfo_proc2 *k;
   1046 	VARENT *ve;
   1047 	int mode;
   1048 {
   1049 	VAR *v;
   1050 
   1051 	v = ve->var;
   1052 	printval((char *)k + v->off, v, mode);
   1053 }
   1054