#__MINIX: chio mt ps
SUBDIR= cat chmod cp csh date dd df domainname echo ed expr hostname \
- kill ksh ln ls mkdir mv pax pwd rcp rcmd rm rmdir sh \
+ kill ksh ln ls mkdir mv pax ps pwd rcp rcmd rm rmdir sh \
sleep stty sync test
.include <bsd.subdir.mk>
--- /dev/null
+# $NetBSD: Makefile,v 1.29 2011/08/14 10:53:17 christos Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/2/93
+
+PROG= ps
+SRCS= fmt.c keyword.c nlist.c print.c ps.c
+DPADD= ${LIBM} ${LIBKVM}
+LDADD= -lm -lkvm
+
+CWARNFLAGS+= -Wno-format-y2k
+COPTS.print.c = -Wno-format-nonliteral
+
+.include <bsd.prog.mk>
--- /dev/null
+/* $NetBSD: keyword.c,v 1.54 2014/01/15 08:07:53 mlelstv 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 <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: keyword.c,v 1.54 2014/01/15 08:07:53 mlelstv Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/ucred.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kvm.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "ps.h"
+
+static VAR *findvar(const char *);
+static int vcmp(const void *, const void *);
+
+#if 0 /* kernel doesn't calculate these */
+ PUVAR("idrss", "IDRSS", 0, p_uru_idrss, UINT64, PRIu64),
+ PUVAR("isrss", "ISRSS", 0, p_uru_isrss, UINT64, PRId64),
+ PUVAR("ixrss", "IXRSS", 0, p_uru_ixrss, UINT64, PRId64),
+ PUVAR("maxrss", "MAXRSS", 0, p_uru_maxrss, UINT64, PRIu64),
+#endif
+
+/* Compute offset in common structures. */
+#define POFF(x) offsetof(struct kinfo_proc2, x)
+#define LOFF(x) offsetof(struct kinfo_lwp, x)
+
+#define UIDFMT "u"
+#define UID(n1, n2, of) \
+ { .name = n1, .header = n2, .flag = 0, .oproc = pvar, \
+ .off = POFF(of), .type = UINT32, .fmt = UIDFMT }
+#define GID(n1, n2, off) UID(n1, n2, off)
+
+#define PIDFMT "d"
+#define PID(n1, n2, of) \
+ { .name = n1, .header = n2, .flag = 0, .oproc = pvar, \
+ .off = POFF(of), .type = INT32, .fmt = PIDFMT }
+
+#define LVAR(n1, n2, fl, of, ty, fm) \
+ { .name = n1, .header = n2, .flag = (fl) | LWP, .oproc = pvar, \
+ .off = LOFF(of), .type = ty, .fmt = fm }
+#define PVAR(n1, n2, fl, of, ty, fm) \
+ { .name = n1, .header = n2, .flag = (fl) | 0, .oproc = pvar, \
+ .off = POFF(of), .type = ty, .fmt = fm }
+#define PUVAR(n1, n2, fl, of, ty, fm) \
+ { .name = n1, .header = n2, .flag = (fl) | UAREA, .oproc = pvar, \
+ .off = POFF(of), .type = ty, .fmt = fm }
+#define VAR3(n1, n2, fl) \
+ { .name = n1, .header = n2, .flag = fl }
+#define VAR4(n1, n2, fl, op) \
+ { .name = n1, .header = n2, .flag = fl, .oproc = op, }
+#define VAR6(n1, n2, fl, op, of, ty) \
+ { .name = n1, .header = n2, .flag = fl, .oproc = op, \
+ .off = of, .type = ty }
+
+/* NB: table must be sorted, in vi use:
+ * :/^VAR/,/end_sort/! sort -t\" +1
+ * breaking long lines just makes the sort harder
+ *
+ * We support all the fields required by P1003.1-2004 (SUSv3), with
+ * the correct default headers, except for the "tty" field, where the
+ * standard says the header should be "TT", but we have "TTY".
+ */
+VAR var[] = {
+ VAR6("%cpu", "%CPU", 0, pcpu, 0, PCPU),
+ VAR6("%mem", "%MEM", 0, pmem, POFF(p_vm_rssize), INT32),
+ PVAR("acflag", "ACFLG", 0, p_acflag, USHORT, "x"),
+ VAR3("acflg", "acflag", ALIAS),
+ VAR3("args", "command", ALIAS),
+ VAR3("blocked", "sigmask", ALIAS),
+ VAR3("caught", "sigcatch", ALIAS),
+ VAR4("comm", "COMMAND", COMM|ARGV0|LJUST, command),
+ VAR4("command", "COMMAND", COMM|LJUST, command),
+ PVAR("cpu", "CPU", 0, p_estcpu, UINT, "u"),
+ VAR4("cpuid", "CPUID", LWP, cpuid),
+ VAR3("cputime", "time", ALIAS),
+ VAR6("ctime", "CTIME", 0, putimeval, POFF(p_uctime_sec), TIMEVAL),
+ GID("egid", "EGID", p_gid),
+ VAR4("egroup", "EGROUP", LJUST, gname),
+ VAR4("emul", "EMUL", LJUST, emul),
+ VAR6("etime", "ELAPSED", 0, elapsed, POFF(p_ustart_sec), TIMEVAL),
+ UID("euid", "EUID", p_uid),
+ VAR4("euser", "EUSER", LJUST, uname),
+ PVAR("f", "F", 0, p_flag, INT, "x"),
+ VAR3("flags", "f", ALIAS),
+ GID("gid", "GID", p_gid),
+ VAR4("group", "GROUP", LJUST, gname),
+ VAR4("groupnames", "GROUPNAMES", LJUST, groupnames),
+ VAR4("groups", "GROUPS", LJUST, groups),
+ /* holdcnt: unused, left for compat. */
+ LVAR("holdcnt", "HOLDCNT", 0, l_holdcnt, INT, "d"),
+ VAR3("ignored", "sigignore", ALIAS),
+ PUVAR("inblk", "INBLK", 0, p_uru_inblock, UINT64, PRIu64),
+ VAR3("inblock", "inblk", ALIAS),
+ PVAR("jobc", "JOBC", 0, p_jobc, SHORT, "d"),
+ PVAR("ktrace", "KTRACE", 0, p_traceflag, INT, "x"),
+/*XXX*/ PVAR("ktracep", "KTRACEP", 0, p_tracep, KPTR, PRIx64),
+ LVAR("laddr", "LADDR", 0, l_laddr, KPTR, PRIx64),
+ LVAR("lid", "LID", 0, l_lid, INT32, "d"),
+ VAR4("lim", "LIM", 0, maxrss),
+ VAR4("lname", "LNAME", LJUST|LWP, lname),
+ VAR4("login", "LOGIN", LJUST, logname),
+ VAR3("logname", "login", ALIAS),
+ VAR6("lstart", "STARTED", LJUST, lstarted, POFF(p_ustart_sec), UINT32),
+ VAR4("lstate", "STAT", LJUST|LWP, lstate),
+ VAR6("ltime", "LTIME", LWP, lcputime, 0, CPUTIME),
+ PUVAR("majflt", "MAJFLT", 0, p_uru_majflt, UINT64, PRIu64),
+ PUVAR("minflt", "MINFLT", 0, p_uru_minflt, UINT64, PRIu64),
+ PUVAR("msgrcv", "MSGRCV", 0, p_uru_msgrcv, UINT64, PRIu64),
+ PUVAR("msgsnd", "MSGSND", 0, p_uru_msgsnd, UINT64, PRIu64),
+ VAR3("ni", "nice", ALIAS),
+ VAR6("nice", "NI", 0, pnice, POFF(p_nice), UCHAR),
+ PUVAR("nivcsw", "NIVCSW", 0, p_uru_nivcsw, UINT64, PRIu64),
+ PVAR("nlwp", "NLWP", 0, p_nlwps, UINT64, PRId64),
+ VAR3("nsignals", "nsigs", ALIAS),
+ PUVAR("nsigs", "NSIGS", 0, p_uru_nsignals, UINT64, PRIu64),
+ /* nswap: unused, left for compat. */
+ PUVAR("nswap", "NSWAP", 0, p_uru_nswap, UINT64, PRIu64),
+ PUVAR("nvcsw", "NVCSW", 0, p_uru_nvcsw, UINT64, PRIu64),
+/*XXX*/ LVAR("nwchan", "WCHAN", 0, l_wchan, KPTR, PRIx64),
+ PUVAR("oublk", "OUBLK", 0, p_uru_oublock, UINT64, PRIu64),
+ VAR3("oublock", "oublk", ALIAS),
+/*XXX*/ PVAR("p_ru", "P_RU", 0, p_ru, KPTR, PRIx64),
+/*XXX*/ PVAR("paddr", "PADDR", 0, p_paddr, KPTR, PRIx64),
+ PUVAR("pagein", "PAGEIN", 0, p_uru_majflt, UINT64, PRIu64),
+ VAR3("pcpu", "%cpu", ALIAS),
+ VAR3("pending", "sig", ALIAS),
+ PID("pgid", "PGID", p__pgid),
+ PID("pid", "PID", p_pid),
+ VAR3("pmem", "%mem", ALIAS),
+ PID("ppid", "PPID", p_ppid),
+ VAR4("pri", "PRI", LWP, pri),
+ LVAR("re", "RE", INF127, l_swtime, UINT, "u"),
+ GID("rgid", "RGID", p_rgid),
+ VAR4("rgroup", "RGROUP", LJUST, rgname),
+/*XXX*/ LVAR("rlink", "RLINK", 0, l_back, KPTR, PRIx64),
+ PVAR("rlwp", "RLWP", 0, p_nrlwps, UINT64, PRId64),
+ VAR6("rss", "RSS", 0, p_rssize, POFF(p_vm_rssize), INT32),
+ VAR3("rssize", "rsz", ALIAS),
+ VAR6("rsz", "RSZ", 0, rssize, POFF(p_vm_rssize), INT32),
+ UID("ruid", "RUID", p_ruid),
+ VAR4("ruser", "RUSER", LJUST, runame),
+ PVAR("sess", "SESS", 0, p_sess, KPTR24, PRIx64),
+ PID("sid", "SID", p_sid),
+ PVAR("sig", "PENDING", 0, p_siglist, SIGLIST, "s"),
+ PVAR("sigcatch", "CAUGHT", 0, p_sigcatch, SIGLIST, "s"),
+ PVAR("sigignore", "IGNORED", 0, p_sigignore, SIGLIST, "s"),
+ PVAR("sigmask", "BLOCKED", 0, p_sigmask, SIGLIST, "s"),
+ LVAR("sl", "SL", INF127, l_slptime, UINT, "u"),
+ VAR6("start", "STARTED", 0, started, POFF(p_ustart_sec), UINT32),
+ VAR3("stat", "state", ALIAS),
+ VAR4("state", "STAT", LJUST, state),
+ VAR6("stime", "STIME", 0, putimeval, POFF(p_ustime_sec), TIMEVAL),
+ GID("svgid", "SVGID", p_svgid),
+ VAR4("svgroup", "SVGROUP", LJUST, svgname),
+ UID("svuid", "SVUID", p_svuid),
+ VAR4("svuser", "SVUSER", LJUST, svuname),
+ /* "tdev" is UINT32, but we do this for sorting purposes */
+ VAR6("tdev", "TDEV", 0, tdev, POFF(p_tdev), INT32),
+ VAR6("time", "TIME", 0, cputime, 0, CPUTIME),
+ PID("tpgid", "TPGID", p_tpgid),
+ PVAR("tsess", "TSESS", 0, p_tsess, KPTR, PRIx64),
+ VAR6("tsiz", "TSIZ", 0, tsize, POFF(p_vm_tsize), INT32),
+#ifndef __minix
+ VAR6("tt", "TTY", LJUST, tname, POFF(p_tdev), INT32),
+#else /* __minix */
+ VAR6("tt", "TT", LJUST, tname, POFF(p_tdev), INT32),
+#endif /* __minix */
+ VAR6("tty", "TTY", LJUST, longtname, POFF(p_tdev), INT32),
+ LVAR("uaddr", "UADDR", 0, l_addr, KPTR, PRIx64),
+ VAR4("ucomm", "UCOMM", LJUST, ucomm),
+ UID("uid", "UID", p_uid),
+ LVAR("upr", "UPR", 0, l_usrpri, UCHAR, "u"),
+ VAR4("user", "USER", LJUST, uname),
+ VAR3("usrpri", "upr", ALIAS),
+ VAR6("utime", "UTIME", 0, putimeval, POFF(p_uutime_sec), TIMEVAL),
+ VAR3("vsize", "vsz", ALIAS),
+ VAR6("vsz", "VSZ", 0, vsize, 0, VSIZE),
+ VAR4("wchan", "WCHAN", LJUST|LWP, wchan),
+ PVAR("xstat", "XSTAT", 0, p_xstat, USHORT, "x"),
+/* "zzzz" end_sort */
+ { .name = "" },
+};
+
+void
+showkey(void)
+{
+ VAR *v;
+ int i;
+ const char *p;
+ const char *sep;
+
+ i = 0;
+ sep = "";
+ for (v = var; *(p = v->name); ++v) {
+ int len = strlen(p);
+ if (termwidth && (i += len + 1) > termwidth) {
+ i = len;
+ sep = "\n";
+ }
+ (void)printf("%s%s", sep, p);
+ sep = " ";
+ }
+ (void)printf("\n");
+}
+
+/*
+ * Parse the string pp, and insert or append entries to the list
+ * referenced by listptr. If pos in non-null and *pos is non-null, then
+ * *pos specifies where to insert (instead of appending). If pos is
+ * non-null, then a new value is returned through *pos referring to the
+ * last item inserted.
+ */
+static void
+parsevarlist(const char *pp, struct varlist *listptr, struct varent **pos)
+{
+ char *p, *sp, *equalsp;
+
+ /* dup to avoid zapping arguments. We will free sp later. */
+ p = sp = strdup(pp);
+
+ /*
+ * Everything after the first '=' is part of a custom header.
+ * Temporarily replace it with '\0' to simplify other code.
+ */
+ equalsp = strchr(p, '=');
+ if (equalsp)
+ *equalsp = '\0';
+
+#define FMTSEP " \t,\n"
+ while (p && *p) {
+ char *cp;
+ VAR *v;
+ struct varent *vent;
+
+ /*
+ * skip separators before the first keyword, and
+ * look for the separator after the keyword.
+ */
+ for (cp = p; *cp != '\0'; cp++) {
+ p = strpbrk(cp, FMTSEP);
+ if (p != cp)
+ break;
+ }
+ if (*cp == '\0')
+ break;
+ /*
+ * Now cp points to the start of a keyword,
+ * and p is NULL or points past the end of the keyword.
+ *
+ * Terminate the keyword with '\0', or reinstate the
+ * '=' that was removed earlier, if appropriate.
+ */
+ if (p) {
+ *p = '\0';
+ p++;
+ } else if (equalsp) {
+ *equalsp = '=';
+ }
+
+ /*
+ * If findvar() likes the keyword or keyword=header,
+ * add it to our list. If findvar() doesn't like it,
+ * it will print a warning, so we ignore it.
+ */
+ if ((v = findvar(cp)) == NULL)
+ continue;
+ if ((vent = malloc(sizeof(struct varent))) == NULL)
+ err(1, NULL);
+ vent->var = v;
+ if (pos && *pos)
+ SIMPLEQ_INSERT_AFTER(listptr, *pos, vent, next);
+ else {
+ SIMPLEQ_INSERT_TAIL(listptr, vent, next);
+ }
+ if (pos)
+ *pos = vent;
+ }
+ free(sp);
+ if (SIMPLEQ_EMPTY(listptr))
+ errx(1, "no valid keywords");
+}
+
+void
+parsefmt(const char *p)
+{
+
+ parsevarlist(p, &displaylist, NULL);
+}
+
+void
+parsefmt_insert(const char *p, struct varent **pos)
+{
+
+ parsevarlist(p, &displaylist, pos);
+}
+
+void
+parsesort(const char *p)
+{
+
+ parsevarlist(p, &sortlist, NULL);
+}
+
+/* Search through a list for an entry with a specified name. */
+struct varent *
+varlist_find(struct varlist *list, const char *name)
+{
+ struct varent *vent;
+
+ SIMPLEQ_FOREACH(vent, list, next) {
+ if (strcmp(vent->var->name, name) == 0)
+ break;
+ }
+ return vent;
+}
+
+static VAR *
+findvar(const char *p)
+{
+ VAR *v;
+ char *hp;
+
+ hp = strchr(p, '=');
+ if (hp)
+ *hp++ = '\0';
+
+ v = bsearch(p, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp);
+ if (v && v->flag & ALIAS)
+ v = findvar(v->header);
+ if (!v) {
+ warnx("%s: keyword not found", p);
+ eval = 1;
+ return NULL;
+ }
+
+ if (v && hp) {
+ /*
+ * Override the header.
+ *
+ * We need to copy the entry first, and override the
+ * header in the copy, because the same field might be
+ * used multiple times with different headers. We also
+ * need to strdup the header.
+ */
+ struct var *newvar;
+ char *newheader;
+
+ if ((newvar = malloc(sizeof(struct var))) == NULL)
+ err(1, NULL);
+ if ((newheader = strdup(hp)) == NULL)
+ err(1, NULL);
+ memcpy(newvar, v, sizeof(struct var));
+ newvar->header = newheader;
+
+ /*
+ * According to P1003.1-2004, if the header text is null,
+ * such as -o user=, the field width will be at least as
+ * wide as the default header text.
+ */
+ if (*hp == '\0')
+ newvar->width = strlen(v->header);
+
+ v = newvar;
+ }
+ return v;
+}
+
+static int
+vcmp(const void *a, const void *b)
+{
+ return strcmp(a, ((const VAR *)b)->name);
+}
--- /dev/null
+/* $NetBSD: nlist.c,v 1.26 2008/04/28 20:22:51 martin Exp $ */
+
+/*
+ * Copyright (c) 2000 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[] = "@(#)nlist.c 8.4 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: nlist.c,v 1.26 2008/04/28 20:22:51 martin Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <kvm.h>
+#include <math.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ps.h"
+
+struct nlist psnl[] = {
+ { .n_name = "_fscale" },
+#define X_FSCALE 0
+ { .n_name = "_ccpu" },
+#define X_CCPU 1
+ { .n_name = "_physmem" },
+#define X_PHYSMEM 2
+ { .n_name = "_maxslp" },
+#define X_MAXSLP 3
+ { .n_name = NULL }
+};
+
+double ccpu; /* kernel _ccpu variable */
+int nlistread; /* if nlist already read. */
+int mempages; /* number of pages of phys. memory */
+int fscale; /* kernel _fscale variable */
+int maxslp; /* kernel _maxslp variable */
+int uspace; /* kernel USPACE value */
+
+#define kread(x, v) \
+ kvm_read(kd, psnl[x].n_value, (char *)&v, sizeof v) != sizeof(v)
+
+int
+donlist(void)
+{
+ int rval;
+ fixpt_t xccpu;
+
+ rval = 0;
+ nlistread = 1;
+ if (kvm_nlist(kd, psnl)) {
+ nlisterr(psnl);
+ eval = 1;
+ return (1);
+ }
+ if (kread(X_FSCALE, fscale)) {
+ warnx("fscale: %s", kvm_geterr(kd));
+ eval = rval = 1;
+ }
+ if (kread(X_PHYSMEM, mempages)) {
+ warnx("avail_start: %s", kvm_geterr(kd));
+ eval = rval = 1;
+ }
+ if (kread(X_CCPU, xccpu)) {
+ warnx("ccpu: %s", kvm_geterr(kd));
+ eval = rval = 1;
+ }
+ if (kread(X_MAXSLP, maxslp)) {
+ warnx("maxslp: %s", kvm_geterr(kd));
+ eval = rval = 1;
+ }
+ ccpu = (double)xccpu / fscale;
+ return (rval);
+}
+
+int
+donlist_sysctl(void)
+{
+ int mib[2];
+ size_t size;
+ fixpt_t xccpu;
+ uint64_t memsize;
+
+ nlistread = 1;
+ mib[0] = CTL_HW;
+ mib[1] = HW_PHYSMEM64;
+ size = sizeof(memsize);
+ if (sysctl(mib, 2, &memsize, &size, NULL, 0) == 0)
+ mempages = memsize / getpagesize();
+ else
+ mempages = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_FSCALE;
+ size = sizeof(fscale);
+ if (sysctl(mib, 2, &fscale, &size, NULL, 0) == -1)
+ fscale = (1 << 8); /* XXX Hopefully reasonable default */
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_CCPU;
+ size = sizeof(xccpu);
+ if (sysctl(mib, 2, &xccpu, &size, NULL, 0) == -1)
+ ccpu = exp(-1.0 / 20.0); /* XXX Hopefully reasonable default */
+ else
+ ccpu = (double)xccpu / fscale;
+
+ mib[0] = CTL_VM;
+ mib[1] = VM_MAXSLP;
+ size = sizeof(maxslp);
+ if (sysctl(mib, 2, &maxslp, &size, NULL, 0) == -1)
+#ifdef MAXSLP
+ maxslp = MAXSLP;
+#else
+ maxslp = 20; /* XXX Hopefully reasonable default */
+#endif
+
+ mib[0] = CTL_VM;
+ mib[1] = VM_USPACE;
+ size = sizeof(uspace);
+ if (sysctl(mib, 2, &uspace, &size, NULL, 0) == -1)
+#ifdef USPACE
+ uspace = USPACE;
+#else
+ uspace = getpagesize(); /* XXX Hopefully reasonable default */
+#endif
+
+ return 0;
+}
+
+void
+nlisterr(struct nlist nl[])
+{
+ int i;
+
+ (void)fprintf(stderr, "ps: nlist: can't find following symbols:");
+ for (i = 0; nl[i].n_name != NULL; i++)
+ if (nl[i].n_value == 0)
+ (void)fprintf(stderr, " %s", nl[i].n_name);
+ (void)fprintf(stderr, "\n");
+}
--- /dev/null
+/* $NetBSD: print.c,v 1.123 2014/11/15 01:58:34 joerg 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.123 2014/11/15 01:58:34 joerg 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki;
+ VAR *v;
+ int left;
+ char **argv, **p, *name;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ ki = arg;
+ 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) {
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki;
+ VAR *v;
+ int left, i;
+ char buf[16], *p;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ ki = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *ki;
+ VAR *v;
+ int left, i;
+ const char *p;
+
+ if (mode == WIDTHMODE)
+ return;
+
+ ki = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, k->p_comm, mode);
+}
+
+void
+emul(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, k->p_ename, mode);
+}
+
+void
+logname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, k->p_login, mode);
+}
+
+void
+state(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ int flag, is_zombie;
+ char *cp;
+ VAR *v;
+ char buf[16];
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *k;
+ int flag;
+ char *cp;
+ VAR *v;
+ char buf[16];
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ intprintorsetwidth(v, k->p_nice - NZERO, mode);
+}
+
+void
+pri(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l;
+ VAR *v;
+
+ l = arg;
+ v = ve->var;
+ intprintorsetwidth(v, l->l_priority, mode);
+}
+
+void
+uname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_uid, 0), mode);
+}
+
+void
+runame(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_ruid, 0), mode);
+}
+
+void
+svuname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, user_from_uid(k->p_svuid, 0), mode);
+}
+
+void
+gname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_gid, 0), mode);
+}
+
+void
+rgname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_rgid, 0), mode);
+}
+
+void
+svgname(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ strprintorsetwidth(v, group_from_gid(k->p_svgid, 0), mode);
+}
+
+void
+tdev(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ dev_t dev;
+ char buff[16];
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ dev_t dev;
+ const char *ttname;
+ int noctty;
+
+ k = arg;
+ 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 {
+#ifdef __minix
+ /* Actually shorten TTY names. "console" is *really* long. */
+ if (strcmp(ttname, "console") == 0)
+ ttname = "co";
+ else if (strncmp(ttname, "tty", 3) == 0 && ttname[3] != '\0')
+ ttname += 3;
+ else if (strncmp(ttname, "pts/", 4) == 0 && ttname[4] != '\0')
+ ttname += 4; /* this is what FreeBSD does */
+#endif /* __minix */
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ dev_t dev;
+ const char *ttname;
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ time_t startt;
+ struct tm *tp;
+ char buf[100], *cp;
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ time_t startt;
+ char buf[100];
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ int32_t origseconds, secs, mins, hours, days;
+ int fmtlen, printed_something;
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l;
+ VAR *v;
+ char *buf;
+
+ l = arg;
+ v = ve->var;
+ if (l->l_wchan) {
+ if (l->l_wmesg[0]) {
+ strprintorsetwidth(v, l->l_wmesg, mode);
+ v->width = min(v->width, KI_WMESGLEN);
+ } else {
+ (void)asprintf(&buf, "%-*" PRIx64, v->width,
+ l->l_wchan);
+ if (buf == NULL)
+ err(1, "%s", "");
+ strprintorsetwidth(v, buf, mode);
+ v->width = min(v->width, KI_WMESGLEN);
+ free(buf);
+ }
+ } else {
+ if (mode == PRINTMODE)
+ (void)printf("%-*s", v->width, "-");
+ }
+}
+
+#define pgtok(a) (((a)*(size_t)getpagesize())/1024)
+
+void
+vsize(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ intprintorsetwidth(v, pgtok(k->p_vm_msize), mode);
+}
+
+void
+rssize(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ /* XXX don't have info about shared */
+ intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
+}
+
+void
+p_rssize(void *arg, VARENT *ve, enum mode mode) /* doesn't account for text */
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ intprintorsetwidth(v, pgtok(k->p_vm_rssize), mode);
+}
+
+void
+cpuid(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l;
+ VAR *v;
+
+ l = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ int32_t secs;
+ int32_t psecs; /* "parts" of a second. first micro, then centi */
+
+ k = arg;
+ 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l;
+ VAR *v;
+ int32_t secs;
+ int32_t psecs; /* "parts" of a second. first micro, then centi */
+
+ l = arg;
+ v = ve->var;
+
+ secs = l->l_rtime_sec;
+ psecs = l->l_rtime_usec;
+
+ cputime1(secs, psecs, v, mode);
+}
+
+double
+getpcpu(const struct kinfo_proc2 *k)
+{
+ static int failure;
+
+ if (!nlistread)
+ failure = (kd) ? donlist() : 1;
+ if (failure)
+ return (0.0);
+
+#define fxtofl(fixpt) ((double)(fixpt) / fscale)
+
+ if (k->p_swtime == 0 || k->p_realstat == SZOMB)
+ return (0.0);
+ if (rawcpu)
+ return (100.0 * fxtofl(k->p_pctcpu));
+ return (100.0 * fxtofl(k->p_pctcpu) /
+ (1.0 - exp(k->p_swtime * log(ccpu))));
+}
+
+void
+pcpu(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+ double dbl;
+
+ k = arg;
+ v = ve->var;
+ dbl = getpcpu(k);
+ doubleprintorsetwidth(v, dbl, (dbl >= 99.95) ? 0 : 1, mode);
+}
+
+double
+getpmem(const struct kinfo_proc2 *k)
+{
+ static int failure;
+ double fracmem;
+ int szptudot;
+
+ if (!nlistread)
+ failure = (kd) ? donlist() : 1;
+ if (failure)
+ return (0.0);
+
+ /* 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ doubleprintorsetwidth(v, getpmem(k), 1, mode);
+}
+
+void
+pagein(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ v = ve->var;
+ intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
+}
+
+void
+maxrss(void *arg, 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_proc2 *k;
+ VAR *v;
+
+ k = arg;
+ 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(1, "unknown type %d", v->type);
+ }
+#undef GET
+#undef CHK_INF127
+}
+
+void
+pvar(void *arg, VARENT *ve, enum mode mode)
+{
+ VAR *v;
+
+ v = ve->var;
+ if (v->flag & UAREA && !((struct kinfo_proc2 *)arg)->p_uvalid) {
+ if (mode == PRINTMODE)
+ (void)printf("%*s", v->width, "-");
+ return;
+ }
+
+ (void)printval((char *)arg + v->off, v, mode);
+}
+
+void
+putimeval(void *arg, VARENT *ve, enum mode mode)
+{
+ VAR *v = ve->var;
+ struct kinfo_proc2 *k = arg;
+ ulong secs = *(uint32_t *)((char *)arg + v->off);
+ ulong usec = *(uint32_t *)((char *)arg + 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(void *arg, VARENT *ve, enum mode mode)
+{
+ struct kinfo_lwp *l;
+ VAR *v;
+
+ l = arg;
+ 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, "-");
+ }
+}
--- /dev/null
+.\" $NetBSD: ps.1,v 1.103 2014/01/15 09:24:31 wiz Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1991, 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.
+.\"
+.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
+.\"
+.Dd January 15, 2014
+.Dt PS 1
+.Os
+.Sh NAME
+.Nm ps
+.Nd process status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaCcehjlmrSsTuvwx
+.Op Fl k Ar key
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl O Ar fmt
+.Op Fl o Ar fmt
+.Op Fl p Ar pid
+.Op Fl t Ar tty
+.Op Fl U Ar user
+.Op Fl W Ar swap
+.Nm
+.Fl L
+.Sh DESCRIPTION
+.Nm
+displays a header line followed by lines containing information about
+running processes.
+By default, the display includes only processes that have
+controlling terminals and are owned by your uid.
+The default sort order of controlling terminal and
+(among processes with the same controlling terminal) process
+.Tn ID
+may be changed using the
+.Fl k , Fl m ,
+or
+.Fl r
+options.
+.Pp
+The information displayed for each process
+is selected based on a set of keywords (see the
+.Fl L ,
+.Fl O ,
+and
+.Fl o
+options).
+The default output format includes, for each process, the process'
+.Tn ID ,
+controlling terminal, CPU time (including both user and system time),
+state, and associated command.
+.Pp
+The options are as follows:
+.Bl -tag -width XNXsystemXX
+.It Fl A
+Display information about all processes.
+This is equivalent to
+.Fl a Fl x .
+.It Fl a
+Display information about other users' processes as well as your own.
+Note that this does not display information about processes
+without controlling terminals.
+.It Fl C
+Change the way the CPU percentage is calculated by using a
+.Dq raw
+CPU calculation that ignores
+.Dq resident
+time (this normally has no effect).
+.It Fl c
+Do not display full command with arguments, but only the
+executable name.
+This may be somewhat confusing; for example, all
+.Xr sh 1
+scripts will show as
+.Dq sh .
+.It Fl e
+Display the environment as well.
+The environment for other
+users' processes can only be displayed by the super-user.
+.It Fl h
+Repeat the information header as often as necessary to guarantee one
+header per page of information.
+.It Fl j
+Print information associated with the following keywords:
+.Ar user , pid , ppid , pgid , sess , jobc , state , tt , time ,
+and
+.Ar command .
+.It Fl k Ar key
+Sort the output using the space or comma separated list of keywords.
+Multiple sort keys may be specified, using any of the
+.Fl k , Fl m ,
+or
+.Fl r
+options.
+The default sort order is equivalent to
+.Fl k Ar tdev,pid .
+.It Fl L
+List the set of available keywords.
+.It Fl l
+Display information associated with the following keywords:
+.Ar uid , pid , ppid , cpu , pri , nice , vsz , rss , wchan , state ,
+.Ar tt , time ,
+and
+.Ar command .
+.It Fl M Ar core
+Extract values from the specified core file instead of the running system.
+.It Fl m
+Sort by memory usage.
+This is equivalent to
+.Fl k Ar vsz .
+.It Fl N Ar system
+Extract the name list from the specified system instead of the default,
+.Dq Pa /netbsd .
+Ignored unless
+.Fl M
+is specified.
+.It Fl O Ar fmt
+Display information associated with the space or comma separated list
+of keywords specified.
+The
+.Fl O
+option does not suppress the default display;
+it inserts additional keywords just after the
+.Ar pid
+keyword in the default display, or after the
+.Ar pid
+keyword (if any) in a non-default display specified before the
+first use of the
+.Fl O
+flag.
+Keywords inserted by multiple
+.Fl O
+options will be adjacent.
+.Pp
+An equals sign
+.Pq Dq \&=
+followed by a customised header string may be appended to a keyword,
+as described in more detail under the
+.Fl o
+option.
+.It Fl o Ar fmt
+Display information associated with the space or comma separated list
+of keywords specified.
+Use of the
+.Fl o
+option suppresses the set of keywords that would be displayed by default,
+or appends to the set of keywords specified by other options.
+.Pp
+An equals sign
+.Pq Dq \&=
+followed by a customised header string may be appended to a keyword.
+This causes the printed header to use the specified string instead of
+the default header associated with the keyword.
+.Pp
+Everything after the first equals sign is part of the customised
+header text, and this may include embedded spaces
+.Pq Dq " " ,
+commas
+.Pq Dq \&, ,
+or equals signs
+.Pq Dq \&= .
+To specify multiple keywords with customised headers, use multiple
+.Fl o
+or
+.Fl O
+options.
+.Pp
+If all the keywords to be displayed have customised headers,
+and all the customised headers are entirely empty,
+then the header line is not printed at all.
+.It Fl p Ar pid
+Display information associated with the specified process
+.Tn ID .
+.It Fl r
+Sort by current CPU usage.
+This is equivalent to
+.Fl k Ar %cpu .
+.It Fl S
+Change the way the process time is calculated by summing all exited
+children to their parent process.
+.It Fl s
+Display one line for each LWP, rather than one line for each process,
+and display information associated with the following keywords:
+.Ar uid , pid , ppid , cpu , lid , nlwp , pri , nice , vsz , rss ,
+.Ar wchan , lstate , tt , time ,
+and
+.Ar command .
+.It Fl T
+Display information about processes attached to the device associated
+with the standard input.
+.It Fl t Ar tty
+Display information about processes attached to the specified terminal
+device.
+Use a question mark
+.Pq Dq \&?
+for processes not attached to a
+terminal device and a minus sign
+.Pq Dq -
+for processes that have
+been revoked from their terminal device.
+.It Fl U Ar user
+Display processes belonging to the specified user,
+given either as a user name or a uid.
+.It Fl u
+Display information associated with the following keywords:
+.Ar user , pid , %cpu , %mem , vsz , rss , tt , state , start , time ,
+and
+.Ar command .
+The
+.Fl u
+option implies the
+.Fl r
+option.
+.It Fl v
+Display information associated with the following keywords:
+.Ar pid , state , time , sl , re , pagein , vsz , rss , lim , tsiz ,
+.Ar %cpu , %mem ,
+and
+.Ar command .
+The
+.Fl v
+option implies the
+.Fl m
+option.
+.It Fl W Ar swap
+Extract swap information from the specified file instead of the default,
+.Dq Pa /dev/drum .
+Ignored unless
+.Fl M
+is specified.
+.It Fl w
+Use 132 columns to display information instead of the default, which
+is your window size.
+If the
+.Fl w
+option is specified more than once,
+.Nm
+will use as many columns as necessary without regard to your window size.
+.It Fl x
+Also display information about processes without controlling terminals.
+.El
+.Pp
+A complete list of the available keywords are listed below.
+Some of these keywords are further specified as follows:
+.Bl -tag -width indent
+.It Ar %cpu
+The CPU utilization of the process; this is a decaying average over up to
+a minute of previous (real) time.
+Since the time base over which this is computed varies (since processes may
+be very young) it is possible for the sum of all
+.Tn %CPU
+fields to exceed 100%.
+.It Ar %mem
+The percentage of real memory used by this process.
+.It Ar flags
+The flags (in hexadecimal) associated with the process as in
+the include file
+.In sys/proc.h :
+.Bl -column P_NOCLDSTOP P_NOCLDSTOP compact
+.It Dv "P_ADVLOCK" Ta No "0x00000001 process may hold a POSIX advisory lock"
+.It Dv "P_CONTROLT" Ta No "0x00000002 process has a controlling terminal"
+.It Dv "P_NOCLDSTOP" Ta No "0x00000008 no" Dv SIGCHLD No when children stop
+.It Dv "P_PPWAIT" Ta No "0x00000010 parent is waiting for child to exec/exit"
+.It Dv "P_PROFIL" Ta No "0x00000020 process has started profiling"
+.It Dv "P_SELECT" Ta No "0x00000040 selecting; wakeup/waiting danger"
+.It Dv "P_SINTR" Ta No "0x00000080 sleep is interruptible"
+.It Dv "P_SUGID" Ta No "0x00000100 process had set id privileges since last exec"
+.It Dv "P_SYSTEM" Ta No "0x00000200 system process: no sigs or stats"
+.It Dv "P_TIMEOUT" Ta No "0x00000400 timing out during sleep"
+.It Dv "P_TRACED" Ta No "0x00000800 process is being traced"
+.It Dv "P_WAITED" Ta No "0x00001000 debugging process has waited for child"
+.It Dv "P_WEXIT" Ta No "0x00002000 working on exiting"
+.It Dv "P_EXEC" Ta No "0x00004000 process called" Xr execve 2
+.It Dv "P_OWEUPC" Ta No "0x00008000 owe process an addupc() call at next ast"
+.\" the routine addupc is not documented in the man pages
+.It Dv "P_FSTRACE" Ta No "0x00010000 tracing via file system"
+.It Dv "P_NOCLDWAIT" Ta No "0x00020000 no zombies when children die"
+.It Dv "P_32" Ta No "0x00040000 32-bit process (used on 64-bit kernels)"
+.It Dv "P_BIGLOCK" Ta No "0x00080000 process needs kernel ``big lock'' to run"
+.It Dv "P_INEXEC" Ta No "0x00100000 process is exec'ing and cannot be traced"
+.El
+.It Ar lim
+The soft limit on memory used, specified via a call to
+.Xr setrlimit 2 .
+.It Ar lstart
+The exact time the command started, using the
+.Dq \&%c
+format described in
+.Xr strftime 3 .
+.It Ar nice
+The process scheduling increment (see
+.Xr setpriority 2 ) .
+.It Ar rss
+the real memory (resident set) size of the process (in 1024 byte units).
+.It Ar start
+The time the command started.
+If the command started less than 24 hours ago, the start time is
+displayed using the
+.Dq %l:%M%p
+format described in
+.Xr strftime 3 .
+If the command started less than 7 days ago, the start time is
+displayed using the
+.Dq %a%p
+format.
+Otherwise, the start time is displayed using the
+.Dq %e%b%y
+format.
+.It Ar state
+The state is given by a sequence of letters, for example,
+.Dq Tn RNs .
+The first letter indicates the run state of the process:
+.Pp
+.Bl -tag -width indent -compact
+.It D
+Marks a process in device or other short term, uninterruptible wait.
+.It I
+Marks a process that is idle (sleeping interruptibly for longer than about
+.Dv MAXSLP
+(default 20) seconds).
+.It O
+Marks a process running on a processor.
+.It R
+Marks a runnable process, or one that is in the process of creation.
+.It S
+Marks a process that is sleeping interruptibly for less than about
+.Dv MAXSLP
+(default 20) seconds.
+.It T
+Marks a stopped process.
+.It U
+Marks a suspended process.
+.It Z
+Marks a dead process that has exited, but not been waited for (a
+.Dq zombie ) .
+.El
+.Pp
+Additional characters after these, if any, indicate additional state
+information:
+.Pp
+.Bl -tag -width indent -compact
+.It +
+The process is in the foreground process group of its control terminal.
+.It -
+The LWP is detached (can't be waited for).
+.It \*[Lt]
+The process has raised
+.Tn CPU
+scheduling priority.
+.It a
+The process is using scheduler activations (deprecated).
+.It E
+The process is in the process of exiting.
+.It K
+The process is a kernel thread or system process.
+.It l
+The process has multiple LWPs.
+.It N
+The process is niced (has reduced
+.Tn CPU
+scheduling priority) (see
+.Xr setpriority 2 ) .
+.It s
+The process is a session leader.
+.It V
+The process is suspended during a
+.Xr vfork 2 .
+.It X
+The process is being traced or debugged.
+.El
+.It Ar tt
+An abbreviation for the pathname of the controlling terminal, if any.
+The abbreviation consists of the two letters following
+.Dq Pa /dev/tty
+or, for the console,
+.Dq co .
+This is followed by a
+.Dq \&-
+if the process can no longer reach that
+controlling terminal (i.e., it has been revoked).
+.It Ar wchan
+The event (an address in the system) on which a process waits.
+When printed numerically, the initial part of the address is
+trimmed off and the result is printed in hex, for example, 0x80324000 prints
+as 324000.
+.El
+.Pp
+When printing using the
+.Ar command
+keyword, a process that has exited and has a parent that has not yet
+waited for the process (in other words, a zombie) is listed as
+.Dq Aq defunct ,
+and a process which is blocked while trying to exit is listed as
+.Dq Aq exiting .
+.Pp
+.Nm
+will try to locate the processes' argument vector from the user
+area in order to print the command name and arguments.
+This method is not reliable because a process is allowed to destroy this
+information.
+The
+.Ar ucomm
+(accounting) keyword will always contain the real command name as
+contained in the process structure's
+.Va p_comm
+field.
+.Pp
+If the command vector cannot be located (usually because it has not
+been set, as is the case of system processes and/or kernel threads)
+the command name is printed within square brackets.
+.Pp
+To indicate that the argument vector has been tampered with,
+.Nm
+will append the real command name to the output within parentheses
+if the basename of the first argument in the argument vector
+does not match the contents of the real command name.
+.Pp
+In addition,
+.Nm
+checks for the following two situations and does not append the
+real command name parenthesized:
+.Bl -tag -width indent
+.It -shellname
+The login process traditionally adds a
+.Sq -
+in front of the shell name to indicate a login shell.
+.Nm
+will not append parenthesized the command name if it matches with
+the name in the first argument of the argument vector, skipping
+the leading
+.Sq - .
+.It daemonname: current-activity
+Daemon processes frequently report their current activity by setting
+their name to be like
+.Dq daemonname: current-activity .
+.Nm
+will not append parenthesized the command name, if the string preceding the
+.Sq \&:
+in the first argument of the argument vector matches the command name.
+.El
+.Sh KEYWORDS
+The following is a complete list of the available keywords and their
+meanings.
+Several of them have aliases (keywords which are synonyms).
+.Pp
+.Bl -tag -width groupnames -compact
+.It Ar %cpu
+percentage CPU usage (alias
+.Ar pcpu )
+.It Ar %mem
+percentage memory usage (alias
+.Ar pmem )
+.It Ar acflag
+accounting flag (alias
+.Ar acflg )
+.It Ar comm
+command (the argv[0] value)
+.It Ar command
+command and arguments (alias
+.Ar args )
+.It Ar cpu
+short-term CPU usage factor (for scheduling)
+.It Ar cpuid
+CPU number the current process or lwp is running on.
+.It Ar ctime
+accumulated CPU time of all children that have exited
+.It Ar egid
+effective group id
+.It Ar egroup
+group name (from egid)
+.It Ar emul
+emulation name
+.It Ar etime
+elapsed time since the process was started, in the form
+.Li [[dd-]hh:]mm:ss
+.It Ar euid
+effective user id
+.It Ar euser
+user name (from euid)
+.It Ar flags
+the process flags, in hexadecimal (alias
+.Ar f )
+.It Ar gid
+effective group id
+.It Ar group
+group name (from gid)
+.It Ar groupnames
+group names (from group access list)
+.It Ar groups
+group access list
+.It Ar inblk
+total blocks read (alias
+.Ar inblock )
+.It Ar jobc
+job control count
+.It Ar ktrace
+tracing flags
+.It Ar ktracep
+tracing vnode
+.It Ar laddr
+kernel virtual address of the
+.Tn "struct lwp"
+belonging to the LWP.
+.It Ar lid
+ID of the LWP
+.It Ar lim
+memory use limit
+.It Ar lname
+descriptive name of the LWP
+.It Ar logname
+login name of user who started the process (alias
+.Ar login )
+.It Ar lstart
+time started
+.It Ar lstate
+symbolic LWP state
+.It Ar ltime
+CPU time of the LWP
+.It Ar majflt
+total page faults
+.It Ar minflt
+total page reclaims
+.It Ar msgrcv
+total messages received (reads from pipes/sockets)
+.It Ar msgsnd
+total messages sent (writes on pipes/sockets)
+.It Ar nice
+nice value (alias
+.Ar ni )
+.It Ar nivcsw
+total involuntary context switches
+.It Ar nlwp
+number of LWPs in the process
+.It Ar nsigs
+total signals taken (alias
+.Ar nsignals )
+.It Ar nvcsw
+total voluntary context switches
+.It Ar nwchan
+wait channel (as an address)
+.It Ar oublk
+total blocks written (alias
+.Ar oublock )
+.It Ar p_ru
+resource usage pointer (valid only for zombie)
+.It Ar paddr
+kernel virtual address of the
+.Tn "struct proc"
+belonging to the process.
+.It Ar pagein
+pageins (same as majflt)
+.It Ar pgid
+process group number
+.It Ar pid
+process
+.Tn ID
+.It Ar ppid
+parent process
+.Tn ID
+.It Ar pri
+scheduling priority
+.It Ar re
+core residency time (in seconds; 127 = infinity)
+.It Ar rgid
+real group
+.Tn ID
+.It Ar rlink
+reverse link on run queue, or 0
+.It Ar rlwp
+number of LWPs on a processor or run queue
+.It Ar rss
+resident set size
+.It Ar rsz
+resident set size + (text size / text use count) (alias
+.Ar rssize )
+.It Ar ruid
+real user
+.Tn ID
+.It Ar ruser
+user name (from ruid)
+.It Ar sess
+session pointer
+.It Ar sid
+session
+.Tn ID
+.It Ar sig
+pending signals (alias
+.Ar pending )
+.It Ar sigcatch
+caught signals (alias
+.Ar caught )
+.It Ar sigignore
+ignored signals (alias
+.Ar ignored )
+.It Ar sigmask
+blocked signals (alias
+.Ar blocked )
+.It Ar sl
+sleep time (in seconds; 127 = infinity)
+.It Ar start
+time started
+.It Ar state
+symbolic process state (alias
+.Ar stat )
+.It Ar stime
+accumulated system CPU time
+.It Ar svgid
+saved gid from a setgid executable
+.It Ar svgroup
+group name (from svgid)
+.It Ar svuid
+saved uid from a setuid executable
+.It Ar svuser
+user name (from svuid)
+.It Ar tdev
+control terminal device number
+.It Ar time
+accumulated CPU time, user + system (alias
+.Ar cputime )
+.It Ar tpgid
+control terminal process group
+.Tn ID
+.It Ar tsess
+control terminal session pointer
+.It Ar tsiz
+text size (in Kbytes)
+.It Ar tt
+control terminal name (two letter abbreviation)
+.It Ar tty
+full name of control terminal
+.It Ar uaddr
+kernel virtual address of the
+.Tn "struct user"
+belonging to the LWP.
+.It Ar ucomm
+name to be used for accounting
+.It Ar uid
+effective user
+.Tn ID
+.It Ar upr
+scheduling priority on return from system call (alias
+.Ar usrpri )
+.It Ar user
+user name (from uid)
+.It Ar utime
+accumulated user CPU time
+.It Ar vsz
+virtual size in Kbytes (alias
+.Ar vsize )
+.It Ar wchan
+wait channel (as a symbolic name)
+.It Ar xstat
+exit or stop status (valid only for stopped or zombie process)
+.El
+.Sh FILES
+.Bl -tag -width /var/run/kvm.db -compact
+.It Pa /dev
+special files and device names
+.It Pa /dev/drum
+default swap device
+.It Pa /var/run/dev.cdb
+/dev name database
+.It Pa /var/db/kvm.db
+system name list database
+.It Pa /netbsd
+default system name list
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr pgrep 1 ,
+.Xr pkill 1 ,
+.Xr sh 1 ,
+.Xr w 1 ,
+.Xr kvm 3 ,
+.Xr strftime 3 ,
+.Xr dev_mkdb 8 ,
+.Xr pstat 8
+.Sh BUGS
+Since
+.Nm
+cannot run faster than the system and is run as any other scheduled
+process, the information it displays can never be exact.
--- /dev/null
+/* $NetBSD: ps.c,v 1.83 2015/06/16 22:31:08 christos Exp $ */
+
+/*
+ * Copyright (c) 2000-2008 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
+__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: ps.c,v 1.83 2015/06/16 22:31:08 christos 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/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <stddef.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <locale.h>
+#include <nlist.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ps.h"
+
+/*
+ * ARGOPTS must contain all option characters that take arguments
+ * (except for 't'!) - it is used in kludge_oldps_options()
+ */
+#define GETOPTSTR "aAcCeghjk:LlM:mN:O:o:p:rSsTt:U:uvW:wx"
+#define ARGOPTS "kMNOopUW"
+
+struct kinfo_proc2 *kinfo;
+struct varlist displaylist = SIMPLEQ_HEAD_INITIALIZER(displaylist);
+struct varlist sortlist = SIMPLEQ_HEAD_INITIALIZER(sortlist);
+
+int eval; /* exit value */
+int rawcpu; /* -C */
+int sumrusage; /* -S */
+int termwidth; /* width of screen (0 == infinity) */
+int totwidth; /* calculated width of requested variables */
+
+int needcomm, needenv, commandonly;
+uid_t myuid;
+
+static struct kinfo_lwp
+ *pick_representative_lwp(struct kinfo_proc2 *,
+ struct kinfo_lwp *, int);
+static struct kinfo_proc2
+ *getkinfo_kvm(kvm_t *, int, int, int *);
+static char *kludge_oldps_options(char *);
+static int pscomp(const void *, const void *);
+static void scanvars(void);
+__dead static void usage(void);
+static int parsenum(const char *, const char *);
+int main(int, char *[]);
+
+char dfmt[] = "pid tt state time command";
+char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
+char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
+char sfmt[] = "uid pid ppid cpu lid nlwp pri nice vsz rss wchan lstate tt "
+ "ltime command";
+char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
+char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
+
+const char *default_fmt = dfmt;
+
+struct varent *Opos = NULL; /* -O flag inserts after this point */
+
+kvm_t *kd;
+
+static long long
+ttyname2dev(const char *ttname, int *xflg, int *what)
+{
+ struct stat sb;
+ const char *ttypath;
+ char pathbuf[MAXPATHLEN];
+
+ ttypath = NULL;
+ if (strcmp(ttname, "?") == 0) {
+ *xflg = 1;
+ return KERN_PROC_TTY_NODEV;
+ }
+ if (strcmp(ttname, "-") == 0)
+ return KERN_PROC_TTY_REVOKE;
+
+ if (strcmp(ttname, "co") == 0)
+ ttypath = _PATH_CONSOLE;
+ else if (strncmp(ttname, "pts/", 4) == 0 ||
+ strncmp(ttname, "tty", 3) == 0) {
+ (void)snprintf(pathbuf,
+ sizeof(pathbuf), "%s%s", _PATH_DEV, ttname);
+ ttypath = pathbuf;
+ } else if (*ttname != '/') {
+ (void)snprintf(pathbuf,
+ sizeof(pathbuf), "%s%s", _PATH_TTY, ttname);
+ ttypath = pathbuf;
+ } else
+ ttypath = ttname;
+ *what = KERN_PROC_TTY;
+ if (stat(ttypath, &sb) == -1) {
+ devmajor_t pts;
+ int serrno;
+
+ serrno = errno;
+ pts = getdevmajor("pts", S_IFCHR);
+ if (pts != NODEVMAJOR && strncmp(ttname, "pts/", 4) == 0) {
+ int ptsminor = atoi(ttname + 4);
+
+ snprintf(pathbuf, sizeof(pathbuf), "pts/%d", ptsminor);
+ if (strcmp(pathbuf, ttname) == 0 && ptsminor >= 0)
+ return makedev(pts, ptsminor);
+ }
+ errno = serrno;
+ err(1, "%s", ttypath);
+ }
+ if (!S_ISCHR(sb.st_mode))
+ errx(1, "%s: not a terminal", ttypath);
+ return sb.st_rdev;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct varent *vent;
+ struct winsize ws;
+ struct kinfo_lwp *kl, *l;
+ int ch, i, j, fmt, lineno, nentries, nlwps;
+ long long flag;
+ int prtheader, wflag, what, xflg, showlwps;
+ char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
+ char *ttname;
+
+ setprogname(argv[0]);
+ (void)setlocale(LC_ALL, "");
+
+ if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) ||
+ ws.ws_col == 0)
+ termwidth = 79;
+ else
+ termwidth = ws.ws_col - 1;
+
+ if (argc > 1)
+ argv[1] = kludge_oldps_options(argv[1]);
+
+ fmt = prtheader = wflag = xflg = showlwps = 0;
+ what = KERN_PROC_UID;
+ flag = myuid = getuid();
+ memf = nlistf = swapf = NULL;
+
+ while ((ch = getopt(argc, argv, GETOPTSTR)) != -1)
+ switch((char)ch) {
+ case 'A':
+ /* "-A" shows all processes, like "-ax" */
+ xflg = 1;
+ /*FALLTHROUGH*/
+ case 'a':
+ what = KERN_PROC_ALL;
+ flag = 0;
+ break;
+ case 'c':
+ commandonly = 1;
+ break;
+ case 'e': /* XXX set ufmt */
+ needenv = 1;
+ break;
+ case 'C':
+ rawcpu = 1;
+ break;
+ case 'g':
+ break; /* no-op */
+ case 'h':
+ prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
+ break;
+ case 'j':
+ parsefmt(jfmt);
+ fmt = 1;
+ jfmt[0] = '\0';
+ break;
+ case 'k':
+ parsesort(optarg);
+ break;
+ case 'K':
+ break; /* no-op - was dontuseprocfs */
+ case 'L':
+ showkey();
+ exit(0);
+ /* NOTREACHED */
+ case 'l':
+ parsefmt(lfmt);
+ fmt = 1;
+ lfmt[0] = '\0';
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'm':
+ parsesort("vsz");
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'O':
+ /*
+ * If this is not the first -O option, insert
+ * just after the previous one.
+ *
+ * If there is no format yet, start with the default
+ * format, and insert after the pid column.
+ *
+ * If there is already a format, insert after
+ * the pid column, or at the end if there's no
+ * pid column.
+ */
+ if (!Opos) {
+ if (!fmt)
+ parsefmt(default_fmt);
+ Opos = varlist_find(&displaylist, "pid");
+ }
+ parsefmt_insert(optarg, &Opos);
+ fmt = 1;
+ break;
+ case 'o':
+ parsefmt(optarg);
+ fmt = 1;
+ break;
+ case 'p':
+ what = KERN_PROC_PID;
+ flag = parsenum(optarg, "process id");
+ xflg = 1;
+ break;
+ case 'r':
+ parsesort("%cpu");
+ break;
+ case 'S':
+ sumrusage = 1;
+ break;
+ case 's':
+ /* -L was already taken... */
+ showlwps = 1;
+ default_fmt = sfmt;
+ break;
+ case 'T':
+ if ((ttname = ttyname(STDIN_FILENO)) == NULL)
+ errx(1, "stdin: not a terminal");
+ flag = ttyname2dev(ttname, &xflg, &what);
+ break;
+ case 't':
+ flag = ttyname2dev(optarg, &xflg, &what);
+ break;
+ case 'U':
+ if (*optarg != '\0') {
+ struct passwd *pw;
+
+ what = KERN_PROC_UID;
+ pw = getpwnam(optarg);
+ if (pw == NULL) {
+ flag = parsenum(optarg, "user name");
+ } else
+ flag = pw->pw_uid;
+ }
+ break;
+ case 'u':
+ parsefmt(ufmt);
+ parsesort("%cpu");
+ fmt = 1;
+ ufmt[0] = '\0';
+ break;
+ case 'v':
+ parsefmt(vfmt);
+ parsesort("vsz");
+ fmt = 1;
+ vfmt[0] = '\0';
+ break;
+ case 'W':
+ swapf = optarg;
+ break;
+ case 'w':
+ if (wflag)
+ termwidth = UNLIMITED;
+ else if (termwidth < 131)
+ termwidth = 131;
+ wflag++;
+ break;
+ case 'x':
+ xflg = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ nlistf = *argv;
+ if (*++argv) {
+ memf = *argv;
+ if (*++argv)
+ swapf = *argv;
+ }
+ }
+#endif
+
+ if (memf == NULL) {
+ kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
+ donlist_sysctl();
+ } else
+ kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
+
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+
+ if (!fmt)
+ parsefmt(default_fmt);
+
+ /* Add default sort criteria */
+ parsesort("tdev,pid");
+ SIMPLEQ_FOREACH(vent, &sortlist, next) {
+ if (vent->var->flag & LWP || vent->var->type == UNSPECIFIED)
+ warnx("Cannot sort on %s, sort key ignored",
+ vent->var->name);
+ }
+
+ /*
+ * scan requested variables, noting what structures are needed.
+ */
+ scanvars();
+
+ /*
+ * select procs
+ */
+ if (!(kinfo = getkinfo_kvm(kd, what, flag, &nentries)))
+ err(1, "%s", kvm_geterr(kd));
+ if (nentries == 0) {
+ printheader();
+ exit(1);
+ }
+ /*
+ * sort proc list
+ */
+ qsort(kinfo, nentries, sizeof(struct kinfo_proc2), pscomp);
+ /*
+ * For each proc, call each variable output function in
+ * "setwidth" mode to determine the widest element of
+ * the column.
+ */
+
+ for (i = 0; i < nentries; i++) {
+ struct kinfo_proc2 *ki = &kinfo[i];
+
+ if (xflg == 0 && (ki->p_tdev == (uint32_t)NODEV ||
+ (ki->p_flag & P_CONTROLT) == 0))
+ continue;
+
+ kl = kvm_getlwps(kd, ki->p_pid, ki->p_paddr,
+ sizeof(struct kinfo_lwp), &nlwps);
+ if (kl == 0)
+ nlwps = 0;
+ if (showlwps == 0) {
+ l = pick_representative_lwp(ki, kl, nlwps);
+ SIMPLEQ_FOREACH(vent, &displaylist, next)
+ OUTPUT(vent, ki, l, WIDTHMODE);
+ } else {
+ /* The printing is done with the loops
+ * reversed, but here we don't need that,
+ * and this improves the code locality a bit.
+ */
+ SIMPLEQ_FOREACH(vent, &displaylist, next)
+ for (j = 0; j < nlwps; j++)
+ OUTPUT(vent, ki, &kl[j], WIDTHMODE);
+ }
+ }
+ /*
+ * Print header - AFTER determining process field widths.
+ * printheader() also adds up the total width of all
+ * fields the first time it's called.
+ */
+ printheader();
+ /*
+ * For each proc, call each variable output function in
+ * print mode.
+ */
+ for (i = lineno = 0; i < nentries; i++) {
+ struct kinfo_proc2 *ki = &kinfo[i];
+
+ if (xflg == 0 && (ki->p_tdev == (uint32_t)NODEV ||
+ (ki->p_flag & P_CONTROLT ) == 0))
+ continue;
+ kl = kvm_getlwps(kd, ki->p_pid, (u_long)ki->p_paddr,
+ sizeof(struct kinfo_lwp), &nlwps);
+ if (kl == 0)
+ nlwps = 0;
+ if (showlwps == 0) {
+ l = pick_representative_lwp(ki, kl, nlwps);
+ SIMPLEQ_FOREACH(vent, &displaylist, next) {
+ OUTPUT(vent, ki, l, PRINTMODE);
+ if (SIMPLEQ_NEXT(vent, next) != NULL)
+ (void)putchar(' ');
+ }
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ } else {
+ for (j = 0; j < nlwps; j++) {
+ SIMPLEQ_FOREACH(vent, &displaylist, next) {
+ OUTPUT(vent, ki, &kl[j], PRINTMODE);
+ if (SIMPLEQ_NEXT(vent, next) != NULL)
+ (void)putchar(' ');
+ }
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ }
+ }
+ }
+ exit(eval);
+ /* NOTREACHED */
+}
+
+static struct kinfo_lwp *
+pick_representative_lwp(struct kinfo_proc2 *ki, struct kinfo_lwp *kl, int nlwps)
+{
+ int i, onproc, running, sleeping, stopped, suspended;
+ static struct kinfo_lwp zero_lwp;
+
+ if (kl == 0)
+ return &zero_lwp;
+
+ /* Trivial case: only one LWP */
+ if (nlwps == 1)
+ return kl;
+
+ switch (ki->p_realstat) {
+ case SSTOP:
+ case SACTIVE:
+ /* Pick the most live LWP */
+ onproc = running = sleeping = stopped = suspended = -1;
+ for (i = 0; i < nlwps; i++) {
+ switch (kl[i].l_stat) {
+ case LSONPROC:
+ onproc = i;
+ break;
+ case LSRUN:
+ running = i;
+ break;
+ case LSSLEEP:
+ sleeping = i;
+ break;
+ case LSSTOP:
+ stopped = i;
+ break;
+ case LSSUSPENDED:
+ suspended = i;
+ break;
+ }
+ }
+ if (onproc != -1)
+ return &kl[onproc];
+ if (running != -1)
+ return &kl[running];
+ if (sleeping != -1)
+ return &kl[sleeping];
+ if (stopped != -1)
+ return &kl[stopped];
+ if (suspended != -1)
+ return &kl[suspended];
+ break;
+ case SZOMB:
+ /* First will do */
+ return kl;
+ break;
+ }
+ /* Error condition! */
+ warnx("Inconsistent LWP state for process %d", ki->p_pid);
+ return kl;
+}
+
+
+static struct kinfo_proc2 *
+getkinfo_kvm(kvm_t *kdp, int what, int flag, int *nentriesp)
+{
+
+ return (kvm_getproc2(kdp, what, flag, sizeof(struct kinfo_proc2),
+ nentriesp));
+}
+
+static void
+scanvars(void)
+{
+ struct varent *vent;
+ VAR *v;
+
+ SIMPLEQ_FOREACH(vent, &displaylist, next) {
+ v = vent->var;
+ if (v->flag & COMM) {
+ needcomm = 1;
+ break;
+ }
+ }
+}
+
+static int
+pscomp(const void *a, const void *b)
+{
+ const struct kinfo_proc2 *ka = (const struct kinfo_proc2 *)a;
+ const struct kinfo_proc2 *kb = (const struct kinfo_proc2 *)b;
+
+ int i;
+ int64_t i64;
+ VAR *v;
+ struct varent *ve;
+ const sigset_t *sa, *sb;
+
+#define V_SIZE(k) ((k)->p_vm_msize)
+#define RDIFF_N(t, n) \
+ if (((const t *)((const char *)ka + v->off))[n] > ((const t *)((const char *)kb + v->off))[n]) \
+ return 1; \
+ if (((const t *)((const char *)ka + v->off))[n] < ((const t *)((const char *)kb + v->off))[n]) \
+ return -1;
+
+#define RDIFF(type) RDIFF_N(type, 0); continue
+
+ SIMPLEQ_FOREACH(ve, &sortlist, next) {
+ v = ve->var;
+ if (v->flag & LWP)
+ /* LWP structure not available (yet) */
+ continue;
+ /* Sort on pvar() fields, + a few others */
+ switch (v->type) {
+ case CHAR:
+ RDIFF(char);
+ case UCHAR:
+ RDIFF(u_char);
+ case SHORT:
+ RDIFF(short);
+ case USHORT:
+ RDIFF(ushort);
+ case INT:
+ RDIFF(int);
+ case UINT:
+ RDIFF(uint);
+ case LONG:
+ RDIFF(long);
+ case ULONG:
+ RDIFF(ulong);
+ case INT32:
+ RDIFF(int32_t);
+ case UINT32:
+ RDIFF(uint32_t);
+ case SIGLIST:
+ sa = (const void *)((const char *)a + v->off);
+ sb = (const void *)((const char *)b + v->off);
+ i = 0;
+ do {
+ if (sa->__bits[i] > sb->__bits[i])
+ return 1;
+ if (sa->__bits[i] < sb->__bits[i])
+ return -1;
+ i++;
+ } while (i < (int)__arraycount(sa->__bits));
+ continue;
+ case INT64:
+ RDIFF(int64_t);
+ case KPTR:
+ case KPTR24:
+ case UINT64:
+ RDIFF(uint64_t);
+ case TIMEVAL:
+ /* compare xxx_sec then xxx_usec */
+ RDIFF_N(uint32_t, 0);
+ RDIFF_N(uint32_t, 1);
+ continue;
+ case CPUTIME:
+ i64 = ka->p_rtime_sec * 1000000 + ka->p_rtime_usec;
+ i64 -= kb->p_rtime_sec * 1000000 + kb->p_rtime_usec;
+ if (sumrusage) {
+ i64 += ka->p_uctime_sec * 1000000
+ + ka->p_uctime_usec;
+ i64 -= kb->p_uctime_sec * 1000000
+ + kb->p_uctime_usec;
+ }
+ if (i64 != 0)
+ return i64 > 0 ? 1 : -1;
+ continue;
+ case PCPU:
+ i = getpcpu(kb) - getpcpu(ka);
+ if (i != 0)
+ return i;
+ continue;
+ case VSIZE:
+ i = V_SIZE(kb) - V_SIZE(ka);
+ if (i != 0)
+ return i;
+ continue;
+
+ default:
+ /* Ignore everything else */
+ break;
+ }
+ }
+ return 0;
+
+#undef VSIZE
+}
+
+/*
+ * ICK (all for getopt), would rather hide the ugliness
+ * here than taint the main code.
+ *
+ * ps foo -> ps -foo
+ * ps 34 -> ps -p34
+ *
+ * The old convention that 't' with no trailing tty arg means the user's
+ * tty, is only supported if argv[1] doesn't begin with a '-'. This same
+ * feature is available with the option 'T', which takes no argument.
+ */
+static char *
+kludge_oldps_options(char *s)
+{
+ size_t len;
+ char *newopts, *ns, *cp;
+
+ len = strlen(s);
+ if ((newopts = ns = malloc(len + 3)) == NULL)
+ err(1, NULL);
+ /*
+ * options begin with '-'
+ */
+ if (*s != '-')
+ *ns++ = '-'; /* add option flag */
+ /*
+ * gaze to end of argv[1]
+ */
+ cp = s + len - 1;
+ /*
+ * if the last letter is a 't' flag and there are no other option
+ * characters that take arguments (eg U, p, o) in the option
+ * string and the option string doesn't start with a '-' then
+ * convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
+ */
+ if (*cp == 't' && *s != '-' && strpbrk(s, ARGOPTS) == NULL)
+ *cp = 'T';
+ else {
+ /*
+ * otherwise check for trailing number, which *may* be a
+ * pid.
+ */
+ while (cp >= s && isdigit((unsigned char)*cp))
+ --cp;
+ }
+ cp++;
+ memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */
+ ns += cp - s;
+ /*
+ * if there's a trailing number, and not a preceding 'p' (pid) or
+ * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
+ */
+ if (isdigit((unsigned char)*cp) &&
+ (cp == s || (cp[-1] != 'U' && cp[-1] != 't' && cp[-1] != 'p' &&
+ cp[-1] != '/' && (cp - 1 == s || cp[-2] != 't'))))
+ *ns++ = 'p';
+ /* and append the number */
+ (void)strcpy(ns, cp); /* XXX strcpy is safe here */
+
+ return (newopts);
+}
+
+static int
+parsenum(const char *str, const char *msg)
+{
+ char *ep;
+ unsigned long ul;
+
+ ul = strtoul(str, &ep, 0);
+
+ if (*str == '\0' || *ep != '\0')
+ errx(1, "Invalid %s: `%s'", msg, str);
+
+ if (ul > INT_MAX)
+ errx(1, "Out of range %s: `%s'", msg, str);
+
+ return (int)ul;
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage:\t%s\n\t %s\n\t%s\n",
+ "ps [-AaCcehjlmrSsTuvwx] [-k key] [-M core] [-N system] [-O fmt]",
+ "[-o fmt] [-p pid] [-t tty] [-U user] [-W swap]",
+ "ps -L");
+ exit(1);
+ /* NOTREACHED */
+}
./bin/pax minix-base
./bin/printconfig minix-base
./bin/printroot minix-base
+./bin/ps minix-base
./bin/pwd minix-base
./bin/rcmd minix-base
./bin/rcp minix-base
./usr/bin/printf minix-base
./usr/bin/profile minix-base
./usr/bin/progressbar minix-base
-./usr/bin/ps minix-base
+./usr/bin/ps minix-base obsolete
./usr/bin/pwhash minix-base
./usr/bin/ramdisk minix-base
./usr/bin/rarpd minix-base
mount mt netconf \
nonamed \
postinstall prep printroot \
- profile progressbar pr_routes ps pwdauth \
+ profile progressbar pr_routes pwdauth \
ramdisk rarpd rawspeed readclock \
remsync rget rlogin \
rotate service setup \
+++ /dev/null
-# Makefile for the process status utility.
-#
-
-PROG= ps
-
-.include <bsd.prog.mk>
+++ /dev/null
-.TH PS 1
-.SH NAME
-ps \- process status
-.SH SYNOPSIS
-\fBps \fR[\fR[\fB\-\fR]\fBalxE\fR]
-.br
-.de FL
-.TP
-\\fB\\$1\\fR
-\\$2
-..
-.de EX
-.TP 20
-\\fB\\$1\\fR
-# \\$2
-..
-.SH OPTIONS
-.TP 5
-.B \-a
-# Print all processes with controlling terminals
-.TP 5
-.B \-l
-# Give long listing
-.TP 5
-.B \-x
-# Include processes without a terminal
-.TP 5
-.B \-E
-# Print kernel endpoint numbers where pids are normally printed
-.SH EXAMPLES
-.TP 20
-.B ps
-# Show user's own processes in short format
-.TP 20
-.B ps \-axlE
-# Print all processes and tasks in long format
-.TP 20
-.B ps \axlE
-# Same -- the '\-' is optional
-.SH DESCRIPTION
-.PP
-\fIPs\fR prints the status of active processes. Normally only the caller's own
-processes are listed in short format (the PID, TTY, TIME and CMD fields as
-explained below). The long listing contains:
-.PP
- ST
- State:
- R: runnable
- W: waiting (on a message)
- S: sleeping (i.e.,suspended on PM or VFS)
- Z: zombie
- T: stopped
-.PP
- UID, PID, PPID, PGRP
- The user, process, parent process and process group ID's.
-.PP
- SZ
- Size of the process in kilobytes.
-.PP
- RECV
- Process/task on which a receiving process is waiting or sleeping.
-.PP
- TTY
- Controlling tty for the process.
-.PP
- TIME
- Process' cumulative (user + system) execution time.
-.PP
- CMD Command line arguments of the process.
-.PP
-.PP
-The \fI/proc\fR file system is used to obtain the process information.
-Terminal names in \fI/dev\fR are used to generate the
-mnemonic names in the TTY column, so \fIps\fR is independent of terminal naming
-conventions.
-.SH NOTES
-The '\-' option prefix is not required.
-For marginal compatibility with System V usage, the hidden option
-.B \-e
-means the same as
-.BR \-ax ,
-and
-.B \-f
-is the same as
-.BR \-l .
-
-.\" edited by ASW 2004-12-14
-
+++ /dev/null
-/* ps - print status Author: Peter Valkenburg */
-/* Modified for ProcFS by Alen Stojanov and David van Moolenbroek */
-
-/* Ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
- *
- * This is a V7 ps(1) look-alike for MINIX >= 1.5.0.
- * It does not support the 'k' option (i.e. cannot read memory from core file).
- * If you want to compile this for non-IBM PC architectures, the header files
- * require that you have your CHIP, MACHINE etc. defined.
- * Full syntax:
- * ps [-][aeflx]
- * Option `a' gives all processes, `l' for detailed info, `x' includes even
- * processes without a terminal.
- * The `f' and `e' options were added by Kees Bot for the convenience of
- * Solaris users accustomed to these options. The `e' option is equivalent to
- * `a' and `f' is equivalent to -l. These do not appear in the usage message.
- */
-
-/* Some technical comments on this implementation:
- *
- * Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
- * absent, RECV which replaces WCHAN, and PGRP that is an extra.
- * The info is obtained from the following fields of proc, mproc and fproc:
- * ST - kernel status field, p_rts_flags; pm status field, mp_flags (R if
- * p_rts_flags is 0; Z if mp_flags == ZOMBIE; T if mp_flags == STOPPED;
- * else W).
- * UID - pm eff uid field, mp_effuid
- * PID - pm pid field, mp_pid
- * PPID - pm parent process index field, mp_parent (used as index in proc).
- * PGRP - pm process group field, mp_procgrp
- * SZ - memory size, including common and shared memory
- * RECV - kernel process index field for message receiving, p_getfrom
- * If sleeping, pm's mp_flags, or fs's fp_task are used for more info.
- * TTY - fs controlling tty device field, fp_tty.
- * TIME - kernel user + system times fields, user_time + sys_time
- * CMD - system process index (converted to mnemonic name by using the p_name
- * field), or user process argument list (obtained by reading the stack
- * frame; the resulting address is used to get the argument vector from
- * user space and converted into a concatenated argument list).
- */
-
-#define _MINIX_SYSTEM 1
-
-#include <minix/config.h>
-#include <minix/endpoint.h>
-#include <minix/paths.h>
-#include <minix/procfs.h>
-#include <limits.h>
-#include <sys/types.h>
-
-#include <minix/const.h>
-#include <minix/type.h>
-#include <minix/dmap.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <ttyent.h>
-
-
-/*----- ps's local stuff below this line ------*/
-
-/* Structure for tty name info. */
-typedef struct {
- char tty_name[NAME_MAX + 1]; /* file name in /dev */
- dev_t tty_dev; /* major/minor pair */
-} ttyinfo_t;
-
-ttyinfo_t *ttyinfo; /* ttyinfo holds actual tty info */
-size_t n_ttyinfo; /* Number of tty info slots */
-
-u32_t system_hz; /* system clock frequency */
-unsigned int nr_procs; /* maximum number of processes */
-unsigned int nr_tasks; /* maximum number of tasks */
-
-struct pstat *ptable; /* table with process information */
-
-/* Macro to convert endpoints to slots into ptable */
-#define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks)
-
-/* Macro to convert memory offsets to rounded kilo-units */
-#define off_to_k(off) ((unsigned) (((off) + 512) / 1024))
-
-
-/* Short and long listing formats:
- *
- * PID TTY TIME CMD
- * ppppp tttmmm:ss cccccccccc...
- *
- * ST UID PID PPID PGRP SZ RECV TTY TIME CMD
- * s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
- */
-#define S_HEADER " PID TTY TIME CMD\n"
-#define S_FORMAT "%5s %3s %s %s\n"
-#define L_HEADER "ST UID PID PPID PGRP SZ RECV TTY TIME CMD\n"
-#define L_FORMAT " %c %3d %5s %5d %5d %6d %12s %3s %s %s\n"
-
-
-struct pstat { /* structure filled by pstat() */
- struct pstat *ps_next; /* next in process list */
- int ps_task; /* is this process a task or not? */
- int ps_endpt; /* process endpoint (NONE means unused slot) */
- dev_t ps_dev; /* major/minor of controlling tty */
- uid_t ps_ruid; /* real uid */
- uid_t ps_euid; /* effective uid */
- pid_t ps_pid; /* process id */
- pid_t ps_ppid; /* parent process id */
- int ps_pgrp; /* process group id */
- char ps_state; /* process state */
- char ps_pstate; /* sleep state */
- char ps_fstate; /* VFS block state */
- int ps_ftask; /* VFS suspend task (endpoint) */
- vir_bytes ps_memory; /* memory usage */
- int ps_recv; /* process number to receive from (endpoint) */
- unsigned int ps_utime; /* accumulated user time */
- unsigned int ps_stime; /* accumulated system time */
- char ps_name[PROC_NAME_LEN+1];/* process name */
- char *ps_args; /* concatenated argument string */
-};
-
-int main(int argc, char *argv []);
-void plist(void);
-int addrread(int fd, phys_clicks base, vir_bytes addr, char *buf, int
- nbytes );
-void usage(const char *pname );
-void err(const char *s );
-int gettynames(void);
-
-
-/*
- * Tname returns mnemonic string for dev_nr. This is "?" for maj/min pairs that
- * are not found. It uses the ttyinfo array (prepared by gettynames).
- * Tname assumes that the first three letters of the tty's name can be omitted
- * and returns the rest (except for the console, which yields "co").
- */
-static char *tname(dev_t dev_nr)
-{
- unsigned int i;
-
- if (major(dev_nr) == TTY_MAJOR && minor(dev_nr) == 0) return "co";
-
- for (i = 0; i < n_ttyinfo && ttyinfo[i].tty_name[0] != '\0'; i++)
- if (ttyinfo[i].tty_dev == dev_nr)
- return ttyinfo[i].tty_name + 3;
-
- return "?";
-}
-
-/* Find a task by its endpoint. */
-static struct pstat *findtask(endpoint_t endpt)
-{
- struct pstat *ps;
- unsigned int slot;
-
- slot = SLOT_NR(endpt);
-
- if (slot >= nr_tasks + nr_procs)
- return NULL;
-
- ps = &ptable[slot];
-
- if (ps != NULL && ps->ps_endpt == (int) endpt)
- return ps;
-
- return NULL;
-}
-
-/* Return canonical task name of the given endpoint. */
-static char *taskname(endpoint_t endpt)
-{
- struct pstat *ps;
-
- ps = findtask(endpt);
-
- return ps ? ps->ps_name : "???";
-}
-
-/* Prrecv prints the RECV field for process with pstat buffer pointer ps.
- * This is either "ANY", "taskname", or "(blockreason) taskname".
- */
-static char *prrecv(struct pstat *ps)
-{
- char *blkstr, *task; /* reason for blocking and task */
- static char recvstr[20];
-
- if (ps->ps_recv == ANY) return "ANY";
-
- task = taskname(ps->ps_recv);
- if (ps->ps_state != STATE_SLEEP) return task;
-
- blkstr = "?";
- if (ps->ps_recv == PM_PROC_NR) {
- switch (ps->ps_pstate) {
- case PSTATE_WAITING: blkstr = "wait"; break;
- case PSTATE_SIGSUSP: blkstr = "sigsusp"; break;
- }
- } else if (ps->ps_recv == VFS_PROC_NR) {
- switch (ps->ps_fstate) {
- case FSTATE_PIPE: blkstr = "pipe"; break;
- case FSTATE_LOCK: blkstr = "flock"; break;
- case FSTATE_POPEN: blkstr = "popen"; break;
- case FSTATE_SELECT: blkstr = "select"; break;
- case FSTATE_TASK: blkstr = taskname(ps->ps_ftask); break;
- default: blkstr = "??"; break;
- }
- }
- (void) sprintf(recvstr, "(%s) %s", blkstr, task);
- return recvstr;
-}
-
-static void getkinfo(void)
-{
- FILE *fp;
-
- if ((fp = fopen("kinfo", "r")) == NULL)
- err("Unable to open " _PATH_PROC "kinfo");
-
- if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2)
- err("Unable to read from " _PATH_PROC "kinfo");
-
- fclose(fp);
-}
-
-/* Main interprets arguments, gathers information, and prints a process list.
- */
-int main(argc, argv)
-int argc;
-char *argv[];
-{
- int i;
- unsigned int n;
- struct pstat *ps;
- int uid = getuid(); /* real uid of caller */
- char *opt;
- int opt_all = FALSE; /* -a */
- int opt_long = FALSE; /* -l */
- int opt_notty = FALSE; /* -x */
- int opt_endpoint = FALSE; /* -E */
- char pid[2 + sizeof(pid_t) * 3];
- unsigned long ustime;
- char cpu[sizeof(clock_t) * 3 + 1 + 2];
-
- /* Parse arguments; a '-' need not be present (V7/BSD compatability) */
- for (i = 1; i < argc; i++) {
- opt = argv[i];
- if (opt[0] == '-') opt++;
- while (*opt != 0) switch (*opt++) {
- case 'a': opt_all = TRUE; break;
- case 'E': opt_endpoint = TRUE; break;
- case 'e': opt_all = opt_notty = TRUE; break;
- case 'f':
- case 'l': opt_long = TRUE; break;
- case 'x': opt_notty = TRUE; break;
- default: usage(argv[0]);
- }
- }
-
- if (gettynames() == -1) err("Can't get tty names");
-
- if (chdir(_PATH_PROC) != 0) err("Can't chdir to /proc");
-
- /* Get information from the proc file system */
- system_hz = (u32_t) sysconf(_SC_CLK_TCK);
-
- getkinfo();
-
- plist();
-
- /* Now loop through process table and handle each entry */
- printf("%s", opt_long ? L_HEADER : S_HEADER);
- for (n = 0; n < nr_procs + nr_tasks; n++) {
- ps = &ptable[n];
- if (ps->ps_endpt == NONE)
- continue;
-
- if ((opt_all || ps->ps_euid == uid || ps->ps_ruid == uid) &&
- (opt_notty || major(ps->ps_dev) == TTY_MAJOR)) {
- if (ps->ps_task) {
- sprintf(pid, "(%d)", ps->ps_pid);
- } else {
- sprintf(pid, "%d",
- opt_endpoint ? ps->ps_endpt : ps->ps_pid);
- }
-
- ustime = (ps->ps_utime + ps->ps_stime) / system_hz;
- if (ustime < 60 * 60) {
- sprintf(cpu, "%2lu:%02lu", ustime / 60, ustime % 60);
- } else
- if (ustime < 100L * 60 * 60) {
- ustime /= 60;
- sprintf(cpu, "%2luh%02lu", ustime / 60, ustime % 60);
- } else {
- sprintf(cpu, "%4luh", ustime / 3600);
- }
-
- if (opt_long) printf(L_FORMAT,
- ps->ps_state,
- ps->ps_euid, pid, ps->ps_ppid,
- ps->ps_pgrp,
- off_to_k(ps->ps_memory),
- (ps->ps_recv != NONE ? prrecv(ps) : ""),
- tname((dev_t) ps->ps_dev),
- cpu,
- ps->ps_args != NULL ? ps->ps_args : ps->ps_name
- );
- else
- printf(S_FORMAT,
- pid, tname((dev_t) ps->ps_dev),
- cpu,
- ps->ps_args != NULL ? ps->ps_args : ps->ps_name
- );
- }
- }
- return(0);
-}
-
-/* Get_args obtains the command line of a process. */
-char *get_args(struct pstat *ps)
-{
- char path[PATH_MAX], buf[4096];
- ssize_t i, n;
- int fd;
-
- /* Get a reasonable subset of the contents of the 'cmdline' file from procfs.
- * It contains all arguments, separated and terminated by null characters.
- */
- sprintf(path, "%d/cmdline", ps->ps_pid);
-
- fd = open(path, O_RDONLY);
- if (fd < 0) return NULL;
-
- n = read(fd, buf, sizeof(buf));
- if (n <= 0) {
- close(fd);
-
- return NULL;
- }
-
- close(fd);
-
- /* Replace all argument separating null characters with spaces. */
- for (i = 0; i < n-1; i++)
- if (buf[i] == '\0')
- buf[i] = ' ';
-
- /* The last character should already be null, except if it got cut off. */
- buf[n-1] = '\0';
-
- return strdup(buf);
-}
-
-/* Pstat obtains the actual information for the given process, and stores it
- * in the pstat structure. The outside world may change while we are doing
- * this, so nothing is reported in case any of the calls fail.
- */
-int pstat(struct pstat *ps, pid_t pid)
-{
- FILE *fp;
- int version, ruid, euid, dev;
- char type, path[PATH_MAX], name[256];
-
- ps->ps_pid = pid;
- ps->ps_next = NULL;
-
- sprintf(path, "%d/psinfo", pid);
-
- if ((fp = fopen(path, "r")) == NULL)
- return -1;
-
- if (fscanf(fp, "%d", &version) != 1) {
- fclose(fp);
- return -1;
- }
-
- /* The psinfo file's version must match what we expect. */
- if (version != PSINFO_VERSION) {
- fputs("procfs version mismatch!\n", stderr);
- exit(1);
- }
-
- if (fscanf(fp, " %c %d %255s %c %d %*d %u %u %*u %*u",
- &type, &ps->ps_endpt, name, &ps->ps_state,
- &ps->ps_recv, &ps->ps_utime, &ps->ps_stime) != 7) {
-
- fclose(fp);
- return -1;
- }
-
- strncpy(ps->ps_name, name, sizeof(ps->ps_name)-1);
- ps->ps_name[sizeof(ps->ps_name)-1] = 0;
-
- ps->ps_task = type == TYPE_TASK;
-
- if (!ps->ps_task) {
- if (fscanf(fp, " %lu %*u %*u %c %d %u %u %u %*d %c %d %u",
- &ps->ps_memory, &ps->ps_pstate, &ps->ps_ppid,
- &ruid, &euid, &ps->ps_pgrp, &ps->ps_fstate,
- &ps->ps_ftask, &dev) != 9) {
-
- fclose(fp);
- return -1;
- }
-
- ps->ps_ruid = ruid;
- ps->ps_euid = euid;
- ps->ps_dev = dev;
- } else {
- ps->ps_memory = 0L;
- ps->ps_pstate = PSTATE_NONE;
- ps->ps_ppid = 0;
- ps->ps_ruid = 0;
- ps->ps_euid = 0;
- ps->ps_pgrp = 0;
- ps->ps_fstate = FSTATE_NONE;
- ps->ps_ftask = NONE;
- ps->ps_dev = NO_DEV;
- }
-
- fclose(fp);
-
- if (ps->ps_state == STATE_ZOMBIE)
- ps->ps_args = "<defunct>";
- else if (!ps->ps_task)
- ps->ps_args = get_args(ps);
- else
- ps->ps_args = NULL;
-
- return 0;
-}
-
-/* Plist creates a list of processes with status information. */
-void plist(void)
-{
- DIR *p_dir;
- struct dirent *p_ent;
- struct pstat pbuf;
- pid_t pid;
- char *end;
- unsigned int slot;
-
- /* Allocate a table for process information. Initialize all slots' endpoints
- * to NONE, indicating those slots are not used.
- */
- if ((ptable = malloc((nr_tasks + nr_procs) * sizeof(struct pstat))) == NULL)
- err("Out of memory!");
-
- for (slot = 0; slot < nr_tasks + nr_procs; slot++)
- ptable[slot].ps_endpt = NONE;
-
- /* Fill in the table slots for all existing processes, by retrieving all PID
- * entries from the /proc directory.
- */
- p_dir = opendir(".");
-
- if (p_dir == NULL) err("Can't open " _PATH_PROC);
-
- p_ent = readdir(p_dir);
- while (p_ent != NULL) {
- pid = strtol(p_ent->d_name, &end, 10);
-
- if (!end[0] && pid != 0 && !pstat(&pbuf, pid)) {
- slot = SLOT_NR(pbuf.ps_endpt);
-
- if (slot < nr_tasks + nr_procs)
- memcpy(&ptable[slot], &pbuf, sizeof(pbuf));
- }
-
- p_ent = readdir(p_dir);
- }
-
- closedir(p_dir);
-}
-
-void usage(const char *pname)
-{
- fprintf(stderr, "Usage: %s [-][aeflx]\n", pname);
- exit(1);
-}
-
-void err(const char *s)
-{
- extern int errno;
-
- if (errno == 0)
- fprintf(stderr, "ps: %s\n", s);
- else
- fprintf(stderr, "ps: %s: %s\n", s, strerror(errno));
-
- exit(2);
-}
-
-/* Fill ttyinfo by fstatting character specials in /dev. */
-int gettynames(void)
-{
- static char dev_path[] = "/dev/";
- struct stat statbuf;
- static char path[sizeof(dev_path) + NAME_MAX];
- unsigned int index;
- struct ttyent *ttyp;
-
- index = 0;
- while ((ttyp = getttyent()) != NULL) {
- strcpy(path, dev_path);
- strcat(path, ttyp->ty_name);
- if (stat(path, &statbuf) == -1 || !S_ISCHR(statbuf.st_mode))
- continue;
- if (index >= n_ttyinfo) {
- n_ttyinfo= (index+16) * 2;
- ttyinfo = realloc(ttyinfo, n_ttyinfo * sizeof(ttyinfo[0]));
- if (ttyinfo == NULL) err("Out of memory");
- }
- ttyinfo[index].tty_dev = statbuf.st_rdev;
- strcpy(ttyinfo[index].tty_name, ttyp->ty_name);
- index++;
- }
- endttyent();
- while (index < n_ttyinfo) ttyinfo[index++].tty_dev= 0;
-
- return 0;
-}