xref: /openbsd/bin/ps/print.c (revision 8932bfb7)
1 /*	$OpenBSD: print.c,v 1.48 2011/04/10 03:20:58 guenther Exp $	*/
2 /*	$NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1990, 1993, 1994
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/proc.h>
37 #include <sys/stat.h>
38 
39 #include <sys/ucred.h>
40 #include <sys/sysctl.h>
41 #include <uvm/uvm_extern.h>
42 
43 #include <err.h>
44 #include <grp.h>
45 #include <kvm.h>
46 #include <math.h>
47 #include <nlist.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <tzfile.h>
53 #include <unistd.h>
54 #include <pwd.h>
55 
56 #include "ps.h"
57 
58 extern kvm_t *kd;
59 extern int needenv, needcomm, neednlist, commandonly;
60 
61 static char *cmdpart(char *);
62 
63 #define	min(a,b)	((a) < (b) ? (a) : (b))
64 
65 static char *
66 cmdpart(char *arg0)
67 {
68 	char *cp;
69 
70 	return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
71 }
72 
73 void
74 printheader(void)
75 {
76 	VAR *v;
77 	struct varent *vent;
78 
79 	for (vent = vhead; vent; vent = vent->next) {
80 		v = vent->var;
81 		if (v->flag & LJUST) {
82 			if (vent->next == NULL)	/* last one */
83 				(void)printf("%s", v->header);
84 			else
85 				(void)printf("%-*s", v->width, v->header);
86 		} else
87 			(void)printf("%*s", v->width, v->header);
88 		if (vent->next != NULL)
89 			(void)putchar(' ');
90 	}
91 	(void)putchar('\n');
92 }
93 
94 void
95 command(const struct kinfo_proc *kp, VARENT *ve)
96 {
97 	VAR *v;
98 	int left, wantspace = 0;
99 	char **argv, **p;
100 
101 	v = ve->var;
102 	if (ve->next != NULL || termwidth != UNLIMITED) {
103 		if (ve->next == NULL) {
104 			left = termwidth - (totwidth - v->width);
105 			if (left < 1) /* already wrapped, just use std width */
106 				left = v->width;
107 		} else
108 			left = v->width;
109 	} else
110 		left = -1;
111 	if (needenv && kd != NULL) {
112 		argv = kvm_getenvv(kd, kp, termwidth);
113 		if ((p = argv) != NULL) {
114 			while (*p) {
115 				fmt_puts(*p, &left);
116 				p++;
117 				if (*p)
118 					fmt_putc(' ', &left);
119 				else
120 					wantspace = 1;
121 			}
122 		}
123 	} else
124 		argv = NULL;
125 	if (needcomm) {
126 		if (!commandonly) {
127 			if (kd != NULL) {
128 				argv = kvm_getargv(kd, kp, termwidth);
129 				if ((p = argv) != NULL) {
130 					if (wantspace) {
131 						fmt_putc(' ', &left);
132 						wantspace = 0;
133 					}
134 					while (*p) {
135 						fmt_puts(*p, &left);
136 						p++;
137 						if (*p)
138 							fmt_putc(' ', &left);
139 						else
140 							wantspace = 1;
141 					}
142 				}
143 			}
144 			if (argv == NULL || argv[0] == '\0' ||
145 			    strcmp(cmdpart(argv[0]), kp->p_comm)) {
146 				if (wantspace) {
147 					fmt_putc(' ', &left);
148 					wantspace = 0;
149 				}
150 				fmt_putc('(', &left);
151 				fmt_puts(kp->p_comm, &left);
152 				fmt_putc(')', &left);
153 			}
154 		} else {
155 			if (wantspace) {
156 				fmt_putc(' ', &left);
157 				wantspace = 0;
158 			}
159 			fmt_puts(kp->p_comm, &left);
160 		}
161 	}
162 	if (ve->next && left > 0) {
163 		if (wantspace) {
164 			fmt_putc(' ', &left);
165 			wantspace = 0;
166 		}
167 		printf("%*s", left, "");
168 	}
169 }
170 
171 void
172 ucomm(const struct kinfo_proc *kp, VARENT *ve)
173 {
174 	VAR *v;
175 
176 	v = ve->var;
177 	(void)printf("%-*s", v->width, kp->p_comm);
178 }
179 
180 void
181 logname(const struct kinfo_proc *kp, VARENT *ve)
182 {
183 	VAR *v;
184 
185 	v = ve->var;
186 	if (kp->p_login[0]) {
187 		int n = min(v->width, MAXLOGNAME);
188 		(void)printf("%-*.*s", n, n, kp->p_login);
189 		if (v->width > n)
190 			(void)printf("%*s", v->width - n, "");
191 	} else
192 		(void)printf("%-*s", v->width, "-");
193 }
194 
195 #define pgtok(a)	(((unsigned long long)(a)*getpagesize())/1024)
196 
197 void
198 state(const struct kinfo_proc *kp, VARENT *ve)
199 {
200 	extern int ncpu;
201 	int flag;
202 	char *cp, state = '\0';
203 	VAR *v;
204 	char buf[16];
205 
206 	v = ve->var;
207 	flag = kp->p_flag;
208 	cp = buf;
209 
210 	switch (kp->p_stat) {
211 
212 	case SSTOP:
213 		*cp = 'T';
214 		break;
215 
216 	case SSLEEP:
217 		if (flag & P_SINTR)	/* interruptible (long) */
218 			*cp = kp->p_slptime >= maxslp ? 'I' : 'S';
219 		else
220 			*cp = 'D';
221 		break;
222 
223 	case SRUN:
224 	case SIDL:
225 	case SONPROC:
226 		state = *cp = 'R';
227 		break;
228 
229 	case SZOMB:
230 		*cp = 'Z';
231 		break;
232 
233 	default:
234 		*cp = '?';
235 	}
236 	cp++;
237 
238 	if (kp->p_nice < NZERO)
239 		*cp++ = '<';
240 	else if (kp->p_nice > NZERO)
241 		*cp++ = 'N';
242 	if (flag & P_TRACED)
243 		*cp++ = 'X';
244 	if (flag & P_SYSTRACE)
245 		*cp++ = 'x';
246 	if (flag & P_WEXIT && kp->p_stat != SZOMB)
247 		*cp++ = 'E';
248 	if (flag & P_PPWAIT)
249 		*cp++ = 'V';
250 	if (flag & P_SYSTEM)
251 		*cp++ = 'K';
252 	if ((flag & P_SYSTEM) == 0 &&
253 	    kp->p_rlim_rss_cur / 1024 < pgtok(kp->p_vm_rssize))
254 		*cp++ = '>';
255 	if (kp->p_eflag & EPROC_SLEADER)
256 		*cp++ = 's';
257 	if ((flag & P_CONTROLT) && kp->p__pgid == kp->p_tpgid)
258 		*cp++ = '+';
259 	*cp = '\0';
260 
261 	if (state == 'R' && ncpu && kp->p_cpuid != KI_NOCPU) {
262 		char pbuf[16];
263 
264 		snprintf(pbuf, sizeof pbuf, "/%llu", kp->p_cpuid);
265 		*++cp = '\0';
266 		strlcat(buf, pbuf, sizeof buf);
267 		cp = buf + strlen(buf);
268 	}
269 
270 	(void)printf("%-*s", v->width, buf);
271 }
272 
273 void
274 pri(const struct kinfo_proc *kp, VARENT *ve)
275 {
276 	VAR *v;
277 
278 	v = ve->var;
279 	(void)printf("%*d", v->width, kp->p_priority - PZERO);
280 }
281 
282 void
283 pnice(const struct kinfo_proc *kp, VARENT *ve)
284 {
285 	VAR *v;
286 	v = ve->var;
287 	(void)printf("%*d", v->width, kp->p_nice - NZERO);
288 }
289 
290 void
291 euname(const struct kinfo_proc *kp, VARENT *ve)
292 {
293 	VAR *v;
294 
295 	v = ve->var;
296 	(void)printf("%-*s",
297 	    (int)v->width, user_from_uid(kp->p_uid, 0));
298 }
299 
300 void
301 runame(const struct kinfo_proc *kp, VARENT *ve)
302 {
303 	VAR *v;
304 
305 	v = ve->var;
306 	(void)printf("%-*s",
307 	    (int)v->width, user_from_uid(kp->p_ruid, 0));
308 }
309 
310 void
311 gname(const struct kinfo_proc *kp, VARENT *ve)
312 {
313 	VAR *v;
314 
315 	v = ve->var;
316 	(void)printf("%-*s",
317 	    (int)v->width, group_from_gid(kp->p_gid, 0));
318 }
319 
320 void
321 rgname(const struct kinfo_proc *kp, VARENT *ve)
322 {
323 	VAR *v;
324 
325 	v = ve->var;
326 	(void)printf("%-*s",
327 	    (int)v->width, group_from_gid(kp->p_rgid, 0));
328 }
329 
330 void
331 tdev(const struct kinfo_proc *kp, VARENT *ve)
332 {
333 	VAR *v;
334 	dev_t dev;
335 	char buff[16];
336 
337 	v = ve->var;
338 	dev = kp->p_tdev;
339 	if (dev == NODEV)
340 		(void)printf("%*s", v->width, "??");
341 	else {
342 		(void)snprintf(buff, sizeof(buff),
343 		    "%d/%d", major(dev), minor(dev));
344 		(void)printf("%*s", v->width, buff);
345 	}
346 }
347 
348 void
349 tname(const struct kinfo_proc *kp, VARENT *ve)
350 {
351 	VAR *v;
352 	dev_t dev;
353 	char *ttname;
354 
355 	v = ve->var;
356 	dev = kp->p_tdev;
357 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
358 		(void)printf("%-*s", v->width, "??");
359 	else {
360 		if (strncmp(ttname, "tty", 3) == 0)
361 			ttname += 3;
362 		(void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
363 			kp->p_eflag & EPROC_CTTY ? ' ' : '-');
364 	}
365 }
366 
367 void
368 longtname(const struct kinfo_proc *kp, VARENT *ve)
369 {
370 	VAR *v;
371 	dev_t dev;
372 	char *ttname;
373 
374 	v = ve->var;
375 	dev = kp->p_tdev;
376 	if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
377 		(void)printf("%-*s", v->width, "??");
378 	else
379 		(void)printf("%-*s", v->width, ttname);
380 }
381 
382 void
383 started(const struct kinfo_proc *kp, VARENT *ve)
384 {
385 	VAR *v;
386 	static time_t now;
387 	time_t startt;
388 	struct tm *tp;
389 	char buf[100];
390 
391 	v = ve->var;
392 	if (!kp->p_uvalid) {
393 		(void)printf("%-*s", v->width, "-");
394 		return;
395 	}
396 
397 	startt = kp->p_ustart_sec;
398 	tp = localtime(&startt);
399 	if (!now)
400 		(void)time(&now);
401 	if (now - kp->p_ustart_sec < 24 * SECSPERHOUR) {
402 		(void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp);
403 	} else if (now - kp->p_ustart_sec < 7 * SECSPERDAY) {
404 		(void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp);
405 	} else
406 		(void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
407 	(void)printf("%-*s", v->width, buf);
408 }
409 
410 void
411 lstarted(const struct kinfo_proc *kp, VARENT *ve)
412 {
413 	VAR *v;
414 	time_t startt;
415 	char buf[100];
416 
417 	v = ve->var;
418 	if (!kp->p_uvalid) {
419 		(void)printf("%-*s", v->width, "-");
420 		return;
421 	}
422 	startt = kp->p_ustart_sec;
423 	(void)strftime(buf, sizeof(buf) -1, "%c",
424 	    localtime(&startt));
425 	(void)printf("%-*s", v->width, buf);
426 }
427 
428 void
429 wchan(const struct kinfo_proc *kp, VARENT *ve)
430 {
431 	VAR *v;
432 
433 	v = ve->var;
434 	if (kp->p_wchan) {
435 		(void)printf("%-*s", (int)v->width, kp->p_wmesg);
436 	} else
437 		(void)printf("%-*s", v->width, "-");
438 }
439 
440 void
441 vsize(const struct kinfo_proc *kp, VARENT *ve)
442 {
443 	VAR *v;
444 
445 	v = ve->var;
446 	(void)printf("%*llu", v->width,
447 	    pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize));
448 }
449 
450 void
451 rssize(const struct kinfo_proc *kp, VARENT *ve)
452 {
453 	VAR *v;
454 
455 	v = ve->var;
456 	/* XXX don't have info about shared */
457 	(void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
458 	    pgtok(kp->p_vm_rssize));
459 }
460 
461 void
462 p_rssize(const struct kinfo_proc *kp, VARENT *ve)
463 {
464 	VAR *v;
465 
466 	v = ve->var;
467 	(void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 :
468 	    pgtok(kp->p_vm_rssize));
469 }
470 
471 void
472 cputime(const struct kinfo_proc *kp, VARENT *ve)
473 {
474 	VAR *v;
475 	long secs;
476 	long psecs;	/* "parts" of a second. first micro, then centi */
477 	char obuff[128];
478 
479 	v = ve->var;
480 	if (kp->p_stat == SZOMB || !kp->p_uvalid) {
481 		secs = 0;
482 		psecs = 0;
483 	} else {
484 		/*
485 		 * This counts time spent handling interrupts.  We could
486 		 * fix this, but it is not 100% trivial (and interrupt
487 		 * time fractions only work on the sparc anyway).	XXX
488 		 */
489 		secs = kp->p_rtime_sec;
490 		psecs = kp->p_rtime_usec;
491 		if (sumrusage) {
492 			secs += kp->p_uctime_sec;
493 			psecs += kp->p_uctime_usec;
494 		}
495 		/*
496 		 * round and scale to 100's
497 		 */
498 		psecs = (psecs + 5000) / 10000;
499 		secs += psecs / 100;
500 		psecs = psecs % 100;
501 	}
502 	(void)snprintf(obuff, sizeof(obuff),
503 	    "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
504 	(void)printf("%*s", v->width, obuff);
505 }
506 
507 double
508 getpcpu(const struct kinfo_proc *kp)
509 {
510 	double d;
511 
512 	if (fscale == 0)
513 		return (0.0);
514 
515 #define	fxtofl(fixpt)	((double)(fixpt) / fscale)
516 
517 	/* XXX - I don't like this */
518 	if (kp->p_swtime == 0)
519 		return (0.0);
520 	if (rawcpu)
521 		return (100.0 * fxtofl(kp->p_pctcpu));
522 
523 	d = kp->p_swtime * log(fxtofl(ccpu));
524 	if (d < -700.0)
525 		d = 0.0;		/* avoid IEEE underflow */
526 	else
527 		d = exp(d);
528 	if (d == 1.0)
529 		return (0.0);
530 	return (100.0 * fxtofl(kp->p_pctcpu) /
531 		(1.0 - d));
532 }
533 
534 void
535 pcpu(const struct kinfo_proc *kp, VARENT *ve)
536 {
537 	VAR *v;
538 
539 	v = ve->var;
540 	(void)printf("%*.1f", v->width, getpcpu(kp));
541 }
542 
543 double
544 getpmem(const struct kinfo_proc *kp)
545 {
546 	double fracmem;
547 	int szptudot;
548 
549 	if (mempages == 0)
550 		return (0.0);
551 
552 	if (kp->p_flag & P_SYSTEM)
553 		return (0.0);
554 	/* XXX want pmap ptpages, segtab, etc. (per architecture) */
555 	szptudot = USPACE/getpagesize();
556 	/* XXX don't have info about shared */
557 	fracmem = ((float)kp->p_vm_rssize + szptudot)/mempages;
558 	return (100.0 * fracmem);
559 }
560 
561 void
562 pmem(const struct kinfo_proc *kp, VARENT *ve)
563 {
564 	VAR *v;
565 
566 	v = ve->var;
567 	(void)printf("%*.1f", v->width, getpmem(kp));
568 }
569 
570 void
571 pagein(const struct kinfo_proc *kp, VARENT *ve)
572 {
573 	VAR *v;
574 
575 	v = ve->var;
576 	(void)printf("%*llu", v->width,
577 	    kp->p_uvalid ? kp->p_uru_majflt : 0);
578 }
579 
580 void
581 maxrss(const struct kinfo_proc *kp, VARENT *ve)
582 {
583 	VAR *v;
584 
585 	v = ve->var;
586 	(void)printf("%*llu", v->width, kp->p_rlim_rss_cur / 1024);
587 }
588 
589 void
590 tsize(const struct kinfo_proc *kp, VARENT *ve)
591 {
592 	VAR *v;
593 
594 	v = ve->var;
595 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_tsize));
596 }
597 
598 void
599 dsize(const struct kinfo_proc *kp, VARENT *ve)
600 {
601 	VAR *v;
602 
603 	v = ve->var;
604 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_dsize));
605 }
606 
607 void
608 ssize(const struct kinfo_proc *kp, VARENT *ve)
609 {
610 	VAR *v;
611 
612 	v = ve->var;
613 	(void)printf("%*llu", v->width, pgtok(kp->p_vm_ssize));
614 }
615 
616 /*
617  * Generic output routines.  Print fields from various prototype
618  * structures.
619  */
620 static void
621 printval(char *bp, VAR *v)
622 {
623 	char ofmt[32];
624 
625 	snprintf(ofmt, sizeof(ofmt), "%%%s*%s", (v->flag & LJUST) ? "-" : "",
626 	    v->fmt);
627 
628 	/*
629 	 * Note that the "INF127" check is nonsensical for types
630 	 * that are or can be signed.
631 	 */
632 #define	GET(type)		(*(type *)bp)
633 #define	CHK_INF127(n)		(((n) > 127) && (v->flag & INF127) ? 127 : (n))
634 
635 	switch (v->type) {
636 	case INT8:
637 		(void)printf(ofmt, v->width, GET(int8_t));
638 		break;
639 	case UINT8:
640 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int8_t)));
641 		break;
642 	case INT16:
643 		(void)printf(ofmt, v->width, GET(int16_t));
644 		break;
645 	case UINT16:
646 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int16_t)));
647 		break;
648 	case INT32:
649 		(void)printf(ofmt, v->width, GET(int32_t));
650 		break;
651 	case UINT32:
652 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int32_t)));
653 		break;
654 	case INT64:
655 		(void)printf(ofmt, v->width, GET(int64_t));
656 		break;
657 	case UINT64:
658 		(void)printf(ofmt, v->width, CHK_INF127(GET(u_int64_t)));
659 		break;
660 	default:
661 		errx(1, "unknown type %d", v->type);
662 	}
663 #undef GET
664 #undef CHK_INF127
665 }
666 
667 void
668 pvar(const struct kinfo_proc *kp, VARENT *ve)
669 {
670 	VAR *v;
671 
672 	v = ve->var;
673 	if ((v->flag & USER) && !kp->p_uvalid)
674 		(void)printf("%*s", v->width, "-");
675 	else
676 		printval((char *)kp + v->off, v);
677 }
678 
679 void
680 emulname(const struct kinfo_proc *kp, VARENT *ve)
681 {
682 	VAR *v;
683 
684 	v = ve->var;
685 
686 	(void)printf("%-*s", (int)v->width, kp->p_emul);
687 }
688