summaryrefslogtreecommitdiff
path: root/bin/ps/print.c
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-01 22:55:37 +0000
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-03 18:22:05 -0600
commit5b57d28ffb6e1ef86b50f7d05d977826eae89bfe (patch)
tree154a22fe556b49e6927197336f8bf91b12eacd5e /bin/ps/print.c
downloaduserland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.gz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.bz2
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.xz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.zip
initial population
Diffstat (limited to 'bin/ps/print.c')
-rw-r--r--bin/ps/print.c1413
1 files changed, 1413 insertions, 0 deletions
diff --git a/bin/ps/print.c b/bin/ps/print.c
new file mode 100644
index 0000000..e725ef0
--- /dev/null
+++ b/bin/ps/print.c
@@ -0,0 +1,1413 @@
+/* $NetBSD: print.c,v 1.130 2018/09/19 15:20:39 maxv Exp $ */
+
+/*
+ * Copyright (c) 2000, 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * 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 <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
+#else
+__RCSID("$NetBSD: print.c,v 1.130 2018/09/19 15:20:39 maxv Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/ucred.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <grp.h>
+#include <kvm.h>
+#include <math.h>
+#include <nlist.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+#include "ps.h"
+
+static char *cmdpart(char *);
+static void printval(void *, VAR *, enum mode);
+static int titlecmp(char *, char **);
+
+static void doubleprintorsetwidth(VAR *, double, int, enum mode);
+static void intprintorsetwidth(VAR *, int, enum mode);
+static void strprintorsetwidth(VAR *, const char *, enum mode);
+
+static time_t now;
+
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+
+static int
+iwidth(u_int64_t v)
+{
+ u_int64_t nlim, lim;
+ int w = 1;
+
+ for (lim = 10; v >= lim; lim = nlim) {
+ nlim = lim * 10;
+ w++;
+ if (nlim < lim)
+ break;
+ }
+ return w;
+}
+
+static char *
+cmdpart(char *arg0)
+{
+ char *cp;
+
+ return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
+}
+
+void
+printheader(void)
+{
+ int len;
+ VAR *v;
+ struct varent *vent;
+ static int firsttime = 1;
+ static int noheader = 0;
+
+ /*
+ * If all the columns have user-specified null headers,
+ * don't print the blank header line at all.
+ */
+ if (firsttime) {
+ SIMPLEQ_FOREACH(vent, &displaylist, next) {
+ if (vent->var->header[0])
+ break;
+ }
+ if (vent == NULL) {
+ noheader = 1;
+ firsttime = 0;
+ }
+
+ }
+ if (noheader)
+ return;
+
+ SIMPLEQ_FOREACH(vent, &displaylist, next) {
+ v = vent->var;
+ if (firsttime) {
+ len = strlen(v->header);
+ if (len > v->width)
+ v->width = len;
+ totwidth += v->width + 1; /* +1 for space */
+ }
+ if (v->flag & LJUST) {
+ if (SIMPLEQ_NEXT(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 (SIMPLEQ_NEXT(vent, next) != NULL)
+ (void)putchar(' ');
+ }
+ (void)putchar('\n');
+ if (firsttime) {
+ firsttime = 0;
+ totwidth--; /* take off last space */
+ }
+}
+
+/*
+ * Return 1 if the command name in the argument vector (u-area) does
+ * not match the command name (p_comm)
+ */
+static int
+titlecmp(char *name, char **argv)
+{
+ char *title;
+ int namelen;
+
+
+ /* no argument vector == no match; system processes/threads do that */
+ if (argv == 0 || argv[0] == 0)
+ return (1);
+
+ title = cmdpart(argv[0]);
+
+ /* the basename matches */
+ if (!strcmp(name, title))
+ return (0);
+
+ /* handle login shells, by skipping the leading - */
+ if (title[0] == '-' && !strcmp(name, title + 1))
+ return (0);
+
+ namelen = strlen(name);
+
+ /* handle daemons that report activity as daemonname: activity */
+ if (argv[1] == 0 &&
+ !strncmp(name, title, namelen) &&
+ title[namelen + 0] == ':' &&
+ title[namelen + 1] == ' ')
+ return (0);
+
+ return (1);
+}
+
+static void
+doubleprintorsetwidth(VAR *v, double val, int prec, enum mode mode)
+{
+ int fmtlen;
+
+ if (mode == WIDTHMODE) {
+ if (val < 0.0 && val < v->longestnd) {
+ fmtlen = (int)log10(-val) + prec + 2;
+ v->longestnd = val;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ } else if (val > 0.0 && val > v->longestpd) {
+ fmtlen = (int)log10(val) + prec + 1;
+ v->longestpd = val;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ } else {
+ (void)printf("%*.*f", v->width, prec, val);
+ }
+}
+
+static void
+intprintorsetwidth(VAR *v, int val, enum mode mode)
+{
+ int fmtlen;
+
+ if (mode == WIDTHMODE) {
+ if (val < 0 && val < v->longestn) {
+ v->longestn = val;
+ fmtlen = iwidth(-val) + 1;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ } else if (val > 0 && val > v->longestp) {
+ v->longestp = val;
+ fmtlen = iwidth(val);
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ } else
+ (void)printf("%*d", v->width, val);
+}
+
+static void
+strprintorsetwidth(VAR *v, const char *str, enum mode mode)
+{
+ int len;
+
+ if (mode == WIDTHMODE) {
+ len = strlen(str);
+ if (len > v->width)
+ v->width = len;
+ } else {
+ if (v->flag & LJUST)
+ (void)printf("%-*.*s", v->width, v->width, str);
+ else
+ (void)printf("%*.*s", v->width, v->width, str);
+ }
+}
+
+void
+command(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki = pi->ki;
+ VAR *v;
+ int left;
+ char **argv, **p, *name;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ v = ve->var;
+ if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
+ if (SIMPLEQ_NEXT(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 = -1;
+ if (needenv && kd) {
+ argv = kvm_getenvv2(kd, ki, termwidth);
+ if ((p = argv) != NULL) {
+ while (*p) {
+ fmt_puts(*p, &left);
+ p++;
+ fmt_putc(' ', &left);
+ }
+ }
+ }
+ if (needcomm) {
+ if (pi->prefix)
+ (void)fmt_puts(pi->prefix, &left);
+ name = ki->p_comm;
+ if (!commandonly) {
+ argv = kvm_getargv2(kd, ki, termwidth);
+ if ((p = argv) != NULL) {
+ while (*p) {
+ fmt_puts(*p, &left);
+ p++;
+ fmt_putc(' ', &left);
+ if (v->flag & ARGV0)
+ break;
+ }
+ if (!(v->flag & ARGV0) &&
+ titlecmp(name, argv)) {
+ /*
+ * append the real command name within
+ * parentheses, if the command name
+ * does not match the one in the
+ * argument vector
+ */
+ fmt_putc('(', &left);
+ fmt_puts(name, &left);
+ fmt_putc(')', &left);
+ }
+ } else {
+ /*
+ * Commands that don't set an argv vector
+ * are printed with square brackets if they
+ * are system commands. Otherwise they are
+ * printed within parentheses.
+ */
+ if (ki->p_flag & P_SYSTEM) {
+ fmt_putc('[', &left);
+ fmt_puts(name, &left);
+ fmt_putc(']', &left);
+ } else {
+ fmt_putc('(', &left);
+ fmt_puts(name, &left);
+ fmt_putc(')', &left);
+ }
+ }
+ } else {
+ fmt_puts(name, &left);
+ }
+ }
+ if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
+ (void)printf("%*s", left, "");
+}
+
+void
+groups(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki = pi->ki;
+ VAR *v;
+ int left, i;
+ char buf[16], *p;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ v = ve->var;
+ if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
+ if (SIMPLEQ_NEXT(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 = -1;
+
+ if (ki->p_ngroups == 0)
+ fmt_putc('-', &left);
+
+ for (i = 0; i < ki->p_ngroups; i++) {
+ (void)snprintf(buf, sizeof(buf), "%d", ki->p_groups[i]);
+ if (i)
+ fmt_putc(' ', &left);
+ for (p = &buf[0]; *p; p++)
+ fmt_putc(*p, &left);
+ }
+
+ if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
+ (void)printf("%*s", left, "");
+}
+
+void
+groupnames(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki = pi->ki;
+ VAR *v;
+ int left, i;
+ const char *p;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ v = ve->var;
+ if (SIMPLEQ_NEXT(ve, next) != NULL || termwidth != UNLIMITED) {
+ if (SIMPLEQ_NEXT(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 = -1;
+
+ if (ki->p_ngroups == 0)
+ fmt_putc('-', &left);
+
+ for (i = 0; i < ki->p_ngroups; i++) {
+ if (i)
+ fmt_putc(' ', &left);
+ for (p = group_from_gid(ki->p_groups[i], 0); *p; p++)
+ fmt_putc(*p, &left);
+ }
+
+ if (SIMPLEQ_NEXT(ve, next) != NULL && left > 0)
+ (void)printf("%*s", left, "");
+}
+
+void
+ucomm(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ char buf[MAXPATHLEN], *p;
+ VAR *v;
+
+ v = ve->var;
+ if (pi->prefix)
+ snprintf(p = buf, sizeof(buf), "%s%s", pi->prefix, k->p_comm);
+ else
+ p = k->p_comm;
+ strprintorsetwidth(v, p, mode);
+}
+
+void
+emul(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, k->p_ename, mode);
+}
+
+void
+logname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, k->p_login, mode);
+}
+
+void
+state(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ int flag, is_zombie;
+ char *cp;
+ VAR *v;
+ char buf[16];
+
+ is_zombie = 0;
+ v = ve->var;
+ flag = k->p_flag;
+ cp = buf;
+
+ /*
+ * NOTE: There are historical letters, which are no longer used:
+ *
+ * - W: indicated that process is swapped out.
+ * - L: indicated non-zero l_holdcnt (i.e. that process was
+ * prevented from swapping-out.
+ *
+ * These letters should not be used for new states to avoid
+ * conflicts with old applications which might depend on them.
+ */
+ switch (k->p_stat) {
+
+ case LSSTOP:
+ *cp = 'T';
+ break;
+
+ case LSSLEEP:
+ if (flag & L_SINTR) /* interruptable (long) */
+ *cp = (int)k->p_slptime >= maxslp ? 'I' : 'S';
+ else
+ *cp = 'D';
+ break;
+
+ case LSRUN:
+ case LSIDL:
+ *cp = 'R';
+ break;
+
+ case LSONPROC:
+ *cp = 'O';
+ break;
+
+ case LSZOMB:
+ *cp = 'Z';
+ is_zombie = 1;
+ break;
+
+ case LSSUSPENDED:
+ *cp = 'U';
+ break;
+
+ default:
+ *cp = '?';
+ }
+ cp++;
+ if (k->p_nice < NZERO)
+ *cp++ = '<';
+ else if (k->p_nice > NZERO)
+ *cp++ = 'N';
+ if (flag & P_TRACED)
+ *cp++ = 'X';
+ if (flag & P_WEXIT && !is_zombie)
+ *cp++ = 'E';
+ if (flag & P_PPWAIT)
+ *cp++ = 'V';
+ if (flag & P_SYSTEM)
+ *cp++ = 'K';
+ if (k->p_eflag & EPROC_SLEADER)
+ *cp++ = 's';
+ if (flag & P_SA)
+ *cp++ = 'a';
+ else if (k->p_nlwps > 1)
+ *cp++ = 'l';
+ if ((flag & P_CONTROLT) && k->p__pgid == k->p_tpgid)
+ *cp++ = '+';
+ *cp = '\0';
+ strprintorsetwidth(v, buf, mode);
+}
+
+void
+lstate(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *k = pi->li;
+ int flag;
+ char *cp;
+ VAR *v;
+ char buf[16];
+
+ v = ve->var;
+ flag = k->l_flag;
+ cp = buf;
+
+ switch (k->l_stat) {
+
+ case LSSTOP:
+ *cp = 'T';
+ break;
+
+ case LSSLEEP:
+ if (flag & L_SINTR) /* interruptible (long) */
+ *cp = (int)k->l_slptime >= maxslp ? 'I' : 'S';
+ else
+ *cp = 'D';
+ break;
+
+ case LSRUN:
+ case LSIDL:
+ *cp = 'R';
+ break;
+
+ case LSONPROC:
+ *cp = 'O';
+ break;
+
+ case LSZOMB:
+ case LSDEAD:
+ *cp = 'Z';
+ break;
+
+ case LSSUSPENDED:
+ *cp = 'U';
+ break;
+
+ default:
+ *cp = '?';
+ }
+ cp++;
+ if (flag & L_SYSTEM)
+ *cp++ = 'K';
+ if (flag & L_SA)
+ *cp++ = 'a';
+ if (flag & L_DETACHED)
+ *cp++ = '-';
+ *cp = '\0';
+ strprintorsetwidth(v, buf, mode);
+}
+
+void
+pnice(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, k->p_nice - NZERO, mode);
+}
+
+void
+pri(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l = pi->li;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, l->l_priority, mode);
+}
+
+void
+usrname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
+}
+
+void
+runame(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
+}
+
+void
+svuname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
+}
+
+void
+gname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
+}
+
+void
+rgname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
+}
+
+void
+svgname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
+}
+
+void
+tdev(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ dev_t dev;
+ char buff[16];
+
+ v = ve->var;
+ dev = k->p_tdev;
+ if (dev == NODEV) {
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "?");
+ else
+ if (v->width < 2)
+ v->width = 2;
+ } else {
+ (void)snprintf(buff, sizeof(buff),
+ "%lld/%lld", (long long)major(dev), (long long)minor(dev));
+ strprintorsetwidth(v, buff, mode);
+ }
+}
+
+void
+tname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ dev_t dev;
+ const char *ttname;
+ int noctty;
+
+ v = ve->var;
+ dev = k->p_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
+ if (mode == PRINTMODE)
+ (void)printf("%-*s", v->width, "?");
+ else
+ if (v->width < 2)
+ v->width = 2;
+ } else {
+ noctty = !(k->p_eflag & EPROC_CTTY) ? 1 : 0;
+ if (mode == WIDTHMODE) {
+ int fmtlen;
+
+ fmtlen = strlen(ttname) + noctty;
+ if (v->width < fmtlen)
+ v->width = fmtlen;
+ } else {
+ if (noctty)
+ (void)printf("%-*s-", v->width - 1, ttname);
+ else
+ (void)printf("%-*s", v->width, ttname);
+ }
+ }
+}
+
+void
+longtname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ dev_t dev;
+ const char *ttname;
+
+ v = ve->var;
+ dev = k->p_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
+ if (mode == PRINTMODE)
+ (void)printf("%-*s", v->width, "?");
+ else
+ if (v->width < 2)
+ v->width = 2;
+ } else {
+ strprintorsetwidth(v, ttname, mode);
+ }
+}
+
+void
+started(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ time_t startt;
+ struct tm *tp;
+ char buf[100], *cp;
+
+ v = ve->var;
+ if (!k->p_uvalid) {
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+ return;
+ }
+
+ startt = k->p_ustart_sec;
+ tp = localtime(&startt);
+ if (now == 0)
+ (void)time(&now);
+ if (now - k->p_ustart_sec < SECSPERDAY)
+ /* I *hate* SCCS... */
+ (void)strftime(buf, sizeof(buf) - 1, "%l:%" "M%p", tp);
+ else if (now - k->p_ustart_sec < DAYSPERWEEK * SECSPERDAY)
+ /* I *hate* SCCS... */
+ (void)strftime(buf, sizeof(buf) - 1, "%a%" "I%p", tp);
+ else
+ (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
+ /* %e and %l can start with a space. */
+ cp = buf;
+ if (*cp == ' ')
+ cp++;
+ strprintorsetwidth(v, cp, mode);
+}
+
+void
+lstarted(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ time_t startt;
+ char buf[100];
+
+ v = ve->var;
+ if (!k->p_uvalid) {
+ /*
+ * Minimum width is less than header - we don't
+ * need to check it every time.
+ */
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+ return;
+ }
+ startt = k->p_ustart_sec;
+
+ /* assume all times are the same length */
+ if (mode != WIDTHMODE || v->width == 0) {
+ (void)strftime(buf, sizeof(buf) -1, "%c",
+ localtime(&startt));
+ strprintorsetwidth(v, buf, mode);
+ }
+}
+
+void
+elapsed(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ int32_t origseconds, secs, mins, hours, days;
+ int fmtlen, printed_something;
+
+ v = ve->var;
+ if (k->p_uvalid == 0) {
+ origseconds = 0;
+ } else {
+ if (now == 0)
+ (void)time(&now);
+ origseconds = now - k->p_ustart_sec;
+ if (origseconds < 0) {
+ /*
+ * Don't try to be fancy if the machine's
+ * clock has been rewound to before the
+ * process "started".
+ */
+ origseconds = 0;
+ }
+ }
+
+ secs = origseconds;
+ mins = secs / SECSPERMIN;
+ secs %= SECSPERMIN;
+ hours = mins / MINSPERHOUR;
+ mins %= MINSPERHOUR;
+ days = hours / HOURSPERDAY;
+ hours %= HOURSPERDAY;
+
+ if (mode == WIDTHMODE) {
+ if (origseconds == 0)
+ /* non-zero so fmtlen is calculated at least once */
+ origseconds = 1;
+
+ if (origseconds > v->longestp) {
+ v->longestp = origseconds;
+
+ if (days > 0) {
+ /* +9 for "-hh:mm:ss" */
+ fmtlen = iwidth(days) + 9;
+ } else if (hours > 0) {
+ /* +6 for "mm:ss" */
+ fmtlen = iwidth(hours) + 6;
+ } else {
+ /* +3 for ":ss" */
+ fmtlen = iwidth(mins) + 3;
+ }
+
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ } else {
+ printed_something = 0;
+ fmtlen = v->width;
+
+ if (days > 0) {
+ (void)printf("%*d", fmtlen - 9, days);
+ printed_something = 1;
+ } else if (fmtlen > 9) {
+ (void)printf("%*s", fmtlen - 9, "");
+ }
+ if (fmtlen > 9)
+ fmtlen = 9;
+
+ if (printed_something) {
+ (void)printf("-%.*d", fmtlen - 7, hours);
+ printed_something = 1;
+ } else if (hours > 0) {
+ (void)printf("%*d", fmtlen - 6, hours);
+ printed_something = 1;
+ } else if (fmtlen > 6) {
+ (void)printf("%*s", fmtlen - 6, "");
+ }
+ if (fmtlen > 6)
+ fmtlen = 6;
+
+ /* Don't need to set fmtlen or printed_something any more... */
+ if (printed_something) {
+ (void)printf(":%.*d", fmtlen - 4, mins);
+ } else if (mins > 0) {
+ (void)printf("%*d", fmtlen - 3, mins);
+ } else if (fmtlen > 3) {
+ (void)printf("%*s", fmtlen - 3, "0");
+ }
+
+ (void)printf(":%.2d", secs);
+ }
+}
+
+void
+wchan(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l = pi->li;
+ VAR *v;
+
+ v = ve->var;
+ if (l->l_wmesg[0]) {
+ strprintorsetwidth(v, l->l_wmesg, mode);
+ v->width = min(v->width, KI_WMESGLEN);
+ } else {
+ if (mode == PRINTMODE)
+ (void)printf("%-*s", v->width, "-");
+ }
+}
+
+#define pgtok(a) (((a)*(size_t)getpagesize())/1024)
+
+void
+vsize(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, pgtok(k->p_vm_msize), mode);
+}
+
+void
+rssize(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ /* XXX don't have info about shared */
+ intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
+}
+
+void
+p_rssize(struct pinfo *pi, VARENT *ve, enum mode mode) /* doesn't account for text */
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
+}
+
+void
+cpuid(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l = pi->li;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, l->l_cpuid, mode);
+}
+
+static void
+cputime1(int32_t secs, int32_t psecs, VAR *v, enum mode mode)
+{
+ int fmtlen;
+
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+
+ if (mode == WIDTHMODE) {
+ /*
+ * Ugg, this is the only field where a value of 0 is longer
+ * than the column title.
+ * Use SECSPERMIN, because secs is divided by that when
+ * passed to iwidth().
+ */
+ if (secs == 0)
+ secs = SECSPERMIN;
+
+ if (secs > v->longestp) {
+ v->longestp = secs;
+ /* "+6" for the ":%02ld.%02ld" in the printf() below */
+ fmtlen = iwidth(secs / SECSPERMIN) + 6;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ } else {
+ (void)printf("%*ld:%02ld.%02ld", v->width - 6,
+ (long)(secs / SECSPERMIN), (long)(secs % SECSPERMIN),
+ (long)psecs);
+ }
+}
+
+void
+cputime(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+ int32_t secs;
+ int32_t psecs; /* "parts" of a second. first micro, then centi */
+
+ v = ve->var;
+
+ /*
+ * This counts time spent handling interrupts. We could
+ * fix this, but it is not 100% trivial (and interrupt
+ * time fractions only work on the sparc anyway). XXX
+ */
+ secs = k->p_rtime_sec;
+ psecs = k->p_rtime_usec;
+ if (sumrusage) {
+ secs += k->p_uctime_sec;
+ psecs += k->p_uctime_usec;
+ }
+
+ cputime1(secs, psecs, v, mode);
+}
+
+void
+lcputime(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l = pi->li;
+ VAR *v;
+ int32_t secs;
+ int32_t psecs; /* "parts" of a second. first micro, then centi */
+
+ v = ve->var;
+
+ secs = l->l_rtime_sec;
+ psecs = l->l_rtime_usec;
+
+ cputime1(secs, psecs, v, mode);
+}
+
+void
+pcpu(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ VAR *v;
+ double dbl;
+
+ v = ve->var;
+ dbl = pi->pcpu;
+ doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode);
+}
+
+double
+getpmem(const struct kinfo_proc2 *k)
+{
+ double fracmem;
+ int szptudot;
+
+ if (!nlistread)
+ donlist();
+
+ /* XXX want pmap ptpages, segtab, etc. (per architecture) */
+ szptudot = uspace/getpagesize();
+ /* XXX don't have info about shared */
+ fracmem = ((float)k->p_vm_rssize + szptudot)/mempages;
+ return (100.0 * fracmem);
+}
+
+void
+pmem(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ doubleprintorsetwidth(v, getpmem(k), 1, mode);
+}
+
+void
+pagein(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
+}
+
+void
+maxrss(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ VAR *v;
+
+ v = ve->var;
+ /* No need to check width! */
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+tsize(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k = pi->ki;
+ VAR *v;
+
+ v = ve->var;
+ intprintorsetwidth(v, pgtok(k->p_vm_tsize), mode);
+}
+
+/*
+ * Generic output routines. Print fields from various prototype
+ * structures.
+ */
+static void
+printval(void *bp, VAR *v, enum mode mode)
+{
+ static char ofmt[32] = "%";
+ int width, vok, fmtlen;
+ const char *fcp;
+ char *cp;
+ int64_t val;
+ u_int64_t uval;
+
+ val = 0; /* XXXGCC -Wuninitialized [hpcarm] */
+ uval = 0; /* XXXGCC -Wuninitialized [hpcarm] */
+
+ /*
+ * 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))
+
+#define VSIGN 1
+#define VUNSIGN 2
+#define VPTR 3
+
+ if (mode == WIDTHMODE) {
+ vok = 0;
+ switch (v->type) {
+ case CHAR:
+ val = GET(char);
+ vok = VSIGN;
+ break;
+ case UCHAR:
+ uval = CHK_INF127(GET(u_char));
+ vok = VUNSIGN;
+ break;
+ case SHORT:
+ val = GET(short);
+ vok = VSIGN;
+ break;
+ case USHORT:
+ uval = CHK_INF127(GET(u_short));
+ vok = VUNSIGN;
+ break;
+ case INT32:
+ val = GET(int32_t);
+ vok = VSIGN;
+ break;
+ case INT:
+ val = GET(int);
+ vok = VSIGN;
+ break;
+ case UINT:
+ case UINT32:
+ uval = CHK_INF127(GET(u_int));
+ vok = VUNSIGN;
+ break;
+ case LONG:
+ val = GET(long);
+ vok = VSIGN;
+ break;
+ case ULONG:
+ uval = CHK_INF127(GET(u_long));
+ vok = VUNSIGN;
+ break;
+ case KPTR:
+ uval = GET(u_int64_t);
+ vok = VPTR;
+ break;
+ case KPTR24:
+ uval = GET(u_int64_t);
+ uval &= 0xffffff;
+ vok = VPTR;
+ break;
+ case INT64:
+ val = GET(int64_t);
+ vok = VSIGN;
+ break;
+ case UINT64:
+ uval = CHK_INF127(GET(u_int64_t));
+ vok = VUNSIGN;
+ break;
+
+ case SIGLIST:
+ default:
+ /* nothing... */;
+ }
+ switch (vok) {
+ case VSIGN:
+ if (val < 0 && val < v->longestn) {
+ v->longestn = val;
+ fmtlen = iwidth(-val) + 1;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ } else if (val > 0 && val > v->longestp) {
+ v->longestp = val;
+ fmtlen = iwidth(val);
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ return;
+ case VUNSIGN:
+ if (uval > v->longestu) {
+ v->longestu = uval;
+ v->width = iwidth(uval);
+ }
+ return;
+ case VPTR:
+ fmtlen = 0;
+ while (uval > 0) {
+ uval >>= 4;
+ fmtlen++;
+ }
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ return;
+ }
+ }
+
+ width = v->width;
+ cp = ofmt + 1;
+ fcp = v->fmt;
+ if (v->flag & LJUST)
+ *cp++ = '-';
+ *cp++ = '*';
+ while ((*cp++ = *fcp++) != '\0')
+ continue;
+
+ switch (v->type) {
+ case CHAR:
+ (void)printf(ofmt, width, GET(char));
+ return;
+ case UCHAR:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_char)));
+ return;
+ case SHORT:
+ (void)printf(ofmt, width, GET(short));
+ return;
+ case USHORT:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_short)));
+ return;
+ case INT:
+ (void)printf(ofmt, width, GET(int));
+ return;
+ case UINT:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_int)));
+ return;
+ case LONG:
+ (void)printf(ofmt, width, GET(long));
+ return;
+ case ULONG:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_long)));
+ return;
+ case KPTR:
+ (void)printf(ofmt, width, GET(u_int64_t));
+ return;
+ case KPTR24:
+ (void)printf(ofmt, width, GET(u_int64_t) & 0xffffff);
+ return;
+ case INT32:
+ (void)printf(ofmt, width, GET(int32_t));
+ return;
+ case UINT32:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_int32_t)));
+ return;
+ case SIGLIST:
+ {
+ sigset_t *s = (sigset_t *)(void *)bp;
+ size_t i;
+#define SIGSETSIZE (sizeof(s->__bits) / sizeof(s->__bits[0]))
+ char buf[SIGSETSIZE * 8 + 1];
+
+ for (i = 0; i < SIGSETSIZE; i++)
+ (void)snprintf(&buf[i * 8], 9, "%.8x",
+ s->__bits[(SIGSETSIZE - 1) - i]);
+
+ /* Skip leading zeroes */
+ for (i = 0; buf[i] == '0'; i++)
+ continue;
+
+ if (buf[i] == '\0')
+ i--;
+ strprintorsetwidth(v, buf + i, mode);
+#undef SIGSETSIZE
+ }
+ return;
+ case INT64:
+ (void)printf(ofmt, width, GET(int64_t));
+ return;
+ case UINT64:
+ (void)printf(ofmt, width, CHK_INF127(GET(u_int64_t)));
+ return;
+ default:
+ errx(EXIT_FAILURE, "unknown type %d", v->type);
+ }
+#undef GET
+#undef CHK_INF127
+}
+
+void
+pvar(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ VAR *v = ve->var;
+ char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
+
+ if ((v->flag & UAREA) && !pi->ki->p_uvalid) {
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+ return;
+ }
+
+ (void)printval(b + v->off, v, mode);
+}
+
+void
+putimeval(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ VAR *v = ve->var;
+ struct kinfo_proc2 *k = pi->ki;
+ char *b = (v->flag & LWP) ? (char *)pi->li : (char *)pi->ki;
+ ulong secs = *(uint32_t *)(b + v->off);
+ ulong usec = *(uint32_t *)(b + v->off + sizeof (uint32_t));
+ int fmtlen;
+
+ if (!k->p_uvalid) {
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+ return;
+ }
+
+ if (mode == WIDTHMODE) {
+ if (secs == 0)
+ /* non-zero so fmtlen is calculated at least once */
+ secs = 1;
+ if (secs > v->longestu) {
+ v->longestu = secs;
+ if (secs <= 999)
+ /* sss.ssssss */
+ fmtlen = iwidth(secs) + 6 + 1;
+ else
+ /* hh:mm:ss.ss */
+ fmtlen = iwidth((secs + 1) / SECSPERHOUR)
+ + 2 + 1 + 2 + 1 + 2 + 1;
+ if (fmtlen > v->width)
+ v->width = fmtlen;
+ }
+ return;
+ }
+
+ if (secs < 999)
+ (void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
+ else {
+ uint h, m;
+ usec += 5000;
+ if (usec >= 1000000) {
+ usec -= 1000000;
+ secs++;
+ }
+ m = secs / SECSPERMIN;
+ secs -= m * SECSPERMIN;
+ h = m / MINSPERHOUR;
+ m -= h * MINSPERHOUR;
+ (void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs,
+ usec / 10000u );
+ }
+}
+
+void
+lname(struct pinfo *pi, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l = pi->li;
+ VAR *v;
+
+ v = ve->var;
+ if (l->l_name[0] != '\0') {
+ strprintorsetwidth(v, l->l_name, mode);
+ v->width = min(v->width, KI_LNAMELEN);
+ } else {
+ if (mode == PRINTMODE)
+ (void)printf("%-*s", v->width, "-");
+ }
+}