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