/* $OpenBSD: print.c,v 1.89 2024/04/28 16:43:15 florian Exp $ */ /* $NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $ */ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include /* PZERO NODEV */ #include #include #include #include #include #define PLEDGENAMES #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ps.h" extern kvm_t *kd; extern int needenv, needcomm, neednlist, commandonly; int mbswprint(const char *, int, int); /* utf8.c */ static char *cmdpart(char *); #define min(a,b) ((a) < (b) ? (a) : (b)) static char * cmdpart(char *arg0) { char *cp; return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); } void printheader(void) { VAR *v; struct varent *vent; if (!needheader) return; for (vent = vhead; vent; vent = vent->next) { v = vent->var; if (v->flag & LJUST) { if (vent->next == NULL) /* last one */ (void)printf("%s", v->header); else (void)printf("%-*s", v->width, v->header); } else (void)printf("%*s", v->width, v->header); if (vent->next != NULL) (void)putchar(' '); } (void)putchar('\n'); } static int print_comm_name(const struct kinfo_proc *kp, int left, int trail) { left -= mbswprint(kp->p_comm, left, trail); if (left > 1 && kp->p_name[0] != '\0') { putchar('/'); left--; left -= mbswprint(kp->p_name, left, trail); } return left; } void command(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; int left, wantspace = 0; char **p; /* * Determine the available number of display columns. * Always decrement and check after writing. * No check is needed before mbswprint() * and after writing the last data, though. */ v = ve->var; if (ve->next != NULL || termwidth != UNLIMITED) { if (ve->next == NULL) { left = termwidth - (totwidth - v->width); if (left < 1) /* already wrapped, just use std width */ left = v->width; } else left = v->width; } else left = INT_MAX; if (needenv && kd != NULL) { char **envp = kvm_getenvv(kd, kp, termwidth); if ((p = envp) != NULL) { while (*p) { if (wantspace) { putchar(' '); left--; } left -= mbswprint(*p, left, 0); if (left == 0) return; p++; wantspace = 1; } } } if (needcomm) { if (pi->prefix) left -= mbswprint(pi->prefix, left, 0); if (!commandonly) { char **argv = NULL; if (kd != NULL) { argv = kvm_getargv(kd, kp, termwidth); if ((p = argv) != NULL) { while (*p) { if (wantspace) { putchar(' '); left--; } left -= mbswprint(*p, left, 0); if (left == 0) return; p++; wantspace = 1; } } } if (argv == NULL || argv[0] == NULL || kp->p_name[0] != '\0' || strcmp(cmdpart(argv[0]), kp->p_comm)) { if (wantspace) { putchar(' '); if (--left == 0) return; } putchar('('); left--; left = print_comm_name(kp, left, 0); if (left == 0) return; putchar(')'); left--; } } else { if (wantspace) { putchar(' '); left--; } left = print_comm_name(kp, left, 0); } } if (ve->next != NULL) while (left-- > 0) putchar(' '); } void ucomm(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; mbswprint(kp->p_comm, ve->var->width, ve->next != NULL); } void curwd(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; int name[] = { CTL_KERN, KERN_PROC_CWD, kp->p_pid }; char path[PATH_MAX]; size_t pathlen = sizeof path; if (!kvm_sysctl_only || sysctl(name, 3, path, &pathlen, NULL, 0) != 0) *path = '\0'; mbswprint(path, ve->var->width, ve->next != NULL); } void logname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; if (kp->p_login[0]) { int n = min(v->width, LOGIN_NAME_MAX); mbswprint(kp->p_login, n, ve->next != NULL); if (ve->next != NULL) while (n++ < v->width) putchar(' '); } else (void)printf("%-*s", v->width, "-"); } #define pgtok(a) (((unsigned long long)(a)*getpagesize())/1024) void printstate(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; int flag; char *cp, state = '\0'; VAR *v; char buf[16]; v = ve->var; flag = kp->p_flag; cp = buf; switch (kp->p_stat) { case SSTOP: *cp = 'T'; break; case SSLEEP: if (flag & P_SINTR) /* interruptible (long) */ *cp = kp->p_slptime >= maxslp ? 'I' : 'S'; else *cp = 'D'; break; case SRUN: case SIDL: case SONPROC: state = *cp = 'R'; break; case SDEAD: *cp = 'Z'; break; default: *cp = '?'; } cp++; if (kp->p_nice < NZERO) *cp++ = '<'; else if (kp->p_nice > NZERO) *cp++ = 'N'; if (kp->p_psflags & PS_TRACED) *cp++ = 'X'; if ((kp->p_psflags & (PS_EXITING | PS_ZOMBIE)) == PS_EXITING) *cp++ = 'E'; if (kp->p_psflags & PS_ISPWAIT) *cp++ = 'V'; if (flag & P_SYSTEM) *cp++ = 'K'; if ((flag & P_SYSTEM) == 0 && kp->p_rlim_rss_cur / 1024 < pgtok(kp->p_vm_rssize)) *cp++ = '>'; if (kp->p_eflag & EPROC_SLEADER) *cp++ = 's'; if ((kp->p_psflags & PS_CONTROLT) && kp->p__pgid == kp->p_tpgid) *cp++ = '+'; if (kp->p_psflags & PS_PLEDGE) *cp++ = 'p'; if (kp->p_eflag & EPROC_UNVEIL) { if (kp->p_eflag & EPROC_LKUNVEIL) *cp++ = 'U'; else *cp++ = 'u'; } if (kp->p_psflags & PS_CHROOT) *cp++ = 'c'; *cp = '\0'; if (state == 'R' && kp->p_cpuid != KI_NOCPU) { char pbuf[16]; snprintf(pbuf, sizeof pbuf, "/%llu", kp->p_cpuid); *++cp = '\0'; strlcat(buf, pbuf, sizeof buf); cp = buf + strlen(buf); } (void)printf("%-*s", v->width, buf); } void printpledge(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; int i; VAR *v; char buf[1024]; v = ve->var; buf[0] = '\0'; for (i = 0; pledgenames[i].bits != 0; i++) { if (pledgenames[i].bits & kp->p_pledge) { if (*buf != '\0') strlcat(buf, ",", sizeof buf); strlcat(buf, pledgenames[i].name, sizeof buf); } } (void)printf("%-*s", v->width, buf); } void pri(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*d", v->width, kp->p_priority - PZERO); } void pnice(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*d", v->width, kp->p_nice - NZERO); } void euname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; mbswprint(user_from_uid(kp->p_uid, 0), ve->var->width, ve->next != NULL); } void runame(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; mbswprint(user_from_uid(kp->p_ruid, 0), ve->var->width, ve->next != NULL); } void gname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; mbswprint(group_from_gid(kp->p_gid, 0), ve->var->width, ve->next != NULL); } void rgname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; mbswprint(group_from_gid(kp->p_rgid, 0), ve->var->width, ve->next != NULL); } void supgid(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; char buf[1024]; char *p = buf; ssize_t size = sizeof(buf); int i, len; for (i = 0; i < kp->p_ngroups; i++) { len = snprintf(p, size, "%s%u", p == buf ? "" : ",", kp->p_groups[i]); if (len < 0 || len >= size) break; p += len; size -= len; } (void)printf("%-*s", ve->var->width, buf); } void supgrp(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; char buf[1024]; char *p = buf; ssize_t size = sizeof(buf); int i, len; for (i = 0; i < kp->p_ngroups; i++) { len = snprintf(p, size, "%s%s", p == buf ? "" : ",", group_from_gid(kp->p_groups[i], 0)); if (len < 0 || len >= size) break; p += len; size -= len; } (void)printf("%-*s", ve->var->width, buf); } void tdev(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; dev_t dev; v = ve->var; dev = kp->p_tdev; if (dev == NODEV) (void)printf("%*s", v->width, "??"); else { char buff[10+1+10+1]; (void)snprintf(buff, sizeof(buff), "%u/%u", major(dev), minor(dev)); (void)printf("%*s", v->width, buff); } } void tname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; dev_t dev; char *ttname; v = ve->var; dev = kp->p_tdev; if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) (void)printf("%-*s", v->width, "??"); else { if (strncmp(ttname, "tty", 3) == 0) ttname += 3; (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, kp->p_eflag & EPROC_CTTY ? ' ' : '-'); } } void longtname(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; dev_t dev; char *ttname; v = ve->var; dev = kp->p_tdev; if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) (void)printf("%-*s", v->width, "??"); else (void)printf("%-*s", v->width, ttname); } void started(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; static time_t now; time_t startt; struct tm *tp; char buf[100]; v = ve->var; if (!kp->p_uvalid) { (void)printf("%-*s", v->width, "-"); return; } #define SECSPERHOUR (60 * 60) #define SECSPERDAY (24 * 60 * 60) startt = kp->p_ustart_sec; tp = localtime(&startt); if (tp == NULL) { (void)printf("%-*s", v->width, "-"); return; } if (!now) (void)time(&now); if (now - kp->p_ustart_sec < 12 * SECSPERHOUR) { (void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp); } else if (now - kp->p_ustart_sec < 7 * SECSPERDAY) { (void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp); } else (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); (void)printf("%-*s", v->width, buf); } void lstarted(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; time_t startt; char buf[100]; v = ve->var; if (!kp->p_uvalid) { (void)printf("%-*s", v->width, "-"); return; } startt = kp->p_ustart_sec; (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&startt)); (void)printf("%-*s", v->width, buf); } void elapsed(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; static time_t now; time_t secs; char buf[64]; long days, hours, minutes, seconds; v = ve->var; if (!kp->p_uvalid) { (void)printf("%*s", v->width, "-"); return; } if (!now) (void)time(&now); secs = now - kp->p_ustart_sec; if (secs < 0) { (void)printf("%*s", v->width, "-"); return; } days = secs / SECSPERDAY; secs %= SECSPERDAY; hours = secs / SECSPERHOUR; secs %= SECSPERHOUR; minutes = secs / 60; seconds = secs % 60; if (days > 0) (void)snprintf(buf, sizeof(buf), "%ld-%02ld:%02ld:%02ld", days, hours, minutes, seconds); else if (hours > 0) (void)snprintf(buf, sizeof(buf), "%02ld:%02ld:%02ld", hours, minutes, seconds); else (void)snprintf(buf, sizeof(buf), "%02ld:%02ld", minutes, seconds); (void)printf("%*s", v->width, buf); } void wchan(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; if (kp->p_wmesg[0]) { (void)printf("%-*s", (int)v->width, kp->p_wmesg); } else (void)printf("%-*s", v->width, "-"); } void vsize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, pgtok(kp->p_vm_dsize + kp->p_vm_ssize + kp->p_vm_tsize)); } void rssize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; /* XXX don't have info about shared */ (void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 : pgtok(kp->p_vm_rssize)); } void p_rssize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, (kp->p_flag & P_SYSTEM) ? 0 : pgtok(kp->p_vm_rssize)); } void cputime(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; long secs; long psecs; /* "parts" of a second. first micro, then centi */ char obuff[128]; v = ve->var; if (kp->p_stat == SDEAD || !kp->p_uvalid) { secs = 0; psecs = 0; } else { /* * This counts time spent handling interrupts. XXX */ secs = kp->p_rtime_sec; psecs = kp->p_rtime_usec; if (sumrusage) { secs += kp->p_uctime_sec; psecs += kp->p_uctime_usec; } /* * round and scale to 100's */ psecs = (psecs + 5000) / 10000; secs += psecs / 100; psecs = psecs % 100; } (void)snprintf(obuff, sizeof(obuff), "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); (void)printf("%*s", v->width, obuff); } double getpcpu(const struct kinfo_proc *kp) { if (fscale == 0) return (0.0); #define fxtofl(fixpt) ((double)(fixpt) / fscale) return (100.0 * fxtofl(kp->p_pctcpu)); } void pcpu(const struct pinfo *pi, VARENT *ve) { VAR *v; v = ve->var; (void)printf("%*.1f", v->width, getpcpu(pi->ki)); } double getpmem(const struct kinfo_proc *kp) { double fracmem; if (mempages == 0) return (0.0); if (kp->p_flag & P_SYSTEM) return (0.0); /* XXX don't have info about shared */ fracmem = ((float)kp->p_vm_rssize)/mempages; return (100.0 * fracmem); } void pmem(const struct pinfo *pi, VARENT *ve) { VAR *v; v = ve->var; (void)printf("%*.1f", v->width, getpmem(pi->ki)); } void pagein(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, kp->p_uvalid ? kp->p_uru_majflt : 0); } void maxrss(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, kp->p_rlim_rss_cur / 1024); } void tsize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, pgtok(kp->p_vm_tsize)); } void dsize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, pgtok(kp->p_vm_dsize)); } void ssize(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; (void)printf("%*llu", v->width, pgtok(kp->p_vm_ssize)); } /* * Generic output routines. Print fields from various prototype * structures. */ static void printval(char *bp, VAR *v) { char ofmt[32]; snprintf(ofmt, sizeof(ofmt), "%%%s*%s", (v->flag & LJUST) ? "-" : "", v->fmt); /* * Note that the "INF127" check is nonsensical for types * that are or can be signed. */ #define GET(type) (*(type *)bp) #define CHK_INF127(n) (((n) > 127) && (v->flag & INF127) ? 127 : (n)) switch (v->type) { case INT8: (void)printf(ofmt, v->width, GET(int8_t)); break; case UINT8: (void)printf(ofmt, v->width, CHK_INF127(GET(u_int8_t))); break; case INT16: (void)printf(ofmt, v->width, GET(int16_t)); break; case UINT16: (void)printf(ofmt, v->width, CHK_INF127(GET(u_int16_t))); break; case INT32: (void)printf(ofmt, v->width, GET(int32_t)); break; case UINT32: (void)printf(ofmt, v->width, CHK_INF127(GET(u_int32_t))); break; case INT64: (void)printf(ofmt, v->width, GET(int64_t)); break; case UINT64: (void)printf(ofmt, v->width, CHK_INF127(GET(u_int64_t))); break; default: errx(1, "unknown type %d", v->type); } #undef GET #undef CHK_INF127 } void pvar(const struct pinfo *pi, VARENT *ve) { const struct kinfo_proc *kp = pi->ki; VAR *v; v = ve->var; if ((v->flag & USER) && !kp->p_uvalid) (void)printf("%*s", v->width, "-"); else printval((char *)kp + v->off, v); }