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