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