From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- adv_cmds/ps/entitlements.plist | 10 + adv_cmds/ps/extern.h | 98 +++ adv_cmds/ps/fmt.c | 132 ++++ adv_cmds/ps/keyword.c | 340 ++++++++++ adv_cmds/ps/nlist.c | 86 +++ adv_cmds/ps/print.c | 1225 +++++++++++++++++++++++++++++++++++ adv_cmds/ps/ps.1 | 663 +++++++++++++++++++ adv_cmds/ps/ps.c | 1373 ++++++++++++++++++++++++++++++++++++++++ adv_cmds/ps/ps.h | 131 ++++ adv_cmds/ps/tasks.c | 246 +++++++ 10 files changed, 4304 insertions(+) create mode 100644 adv_cmds/ps/entitlements.plist create mode 100644 adv_cmds/ps/extern.h create mode 100644 adv_cmds/ps/fmt.c create mode 100644 adv_cmds/ps/keyword.c create mode 100644 adv_cmds/ps/nlist.c create mode 100644 adv_cmds/ps/print.c create mode 100644 adv_cmds/ps/ps.1 create mode 100644 adv_cmds/ps/ps.c create mode 100644 adv_cmds/ps/ps.h create mode 100644 adv_cmds/ps/tasks.c (limited to 'adv_cmds/ps') diff --git a/adv_cmds/ps/entitlements.plist b/adv_cmds/ps/entitlements.plist new file mode 100644 index 0000000..eaaf1de --- /dev/null +++ b/adv_cmds/ps/entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.system-task-ports + + task_for_pid-allow + + + diff --git a/adv_cmds/ps/extern.h b/adv_cmds/ps/extern.h new file mode 100644 index 0000000..d3f6503 --- /dev/null +++ b/adv_cmds/ps/extern.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 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. + * 4. 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. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + * $FreeBSD: extern.h,v 1.8 1998/05/25 05:07:17 steve Exp $ + */ + +struct kinfo; +struct nlist; +struct var; +struct varent; + +extern fixpt_t ccpu; +extern int cflag, eval, fscale, nlistread, rawcpu; +#ifdef __APPLE__ +extern uint64_t mempages; +#else +extern unsigned long mempages; +#endif +extern time_t now; +extern int showthreads, sumrusage, termwidth, totwidth; +extern STAILQ_HEAD(velisthead, varent) varlist; + +__BEGIN_DECLS +int get_task_info(KINFO *); +void command(KINFO *, VARENT *); +void just_command(KINFO *, VARENT *); +void args(KINFO *, VARENT *); +int s_command(KINFO *); +int s_just_command(KINFO *); +int s_args(KINFO *); +void cputime(KINFO *, VARENT *); +void pstime(KINFO *, VARENT *); +void p_etime(KINFO *, VARENT *); +int s_etime(KINFO *); +void putime(KINFO *, VARENT *); +int donlist(void); +void evar(KINFO *, VARENT *); +VARENT *find_varentry(VAR *); +const char *fmt_argv(char **, char *, size_t); +int getpcpu(KINFO *); +double getpmem(KINFO *); +void logname(KINFO *, VARENT *); +void longtname(KINFO *, VARENT *); +void lstarted(KINFO *, VARENT *); +void maxrss(KINFO *, VARENT *); +void nlisterr(struct nlist *); +void p_rssize(KINFO *, VARENT *); +void pagein(KINFO *, VARENT *); +void parsefmt(const char *, int); +void pcpu(KINFO *, VARENT *); +void pmem(KINFO *, VARENT *); +void pri(KINFO *, VARENT *); +void rtprior(KINFO *, VARENT *); +void printheader(void); +void pvar(KINFO *, VARENT *); +void runame(KINFO *, VARENT *); +void rvar(KINFO *, VARENT *); +int s_runame(KINFO *); +int s_uname(KINFO *); +void showkey(void); +void started(KINFO *, VARENT *); +void state(KINFO *, VARENT *); +void tdev(KINFO *, VARENT *); +void tname(KINFO *, VARENT *); +void tsize(KINFO *, VARENT *); +void ucomm(KINFO *, VARENT *); +void uname(KINFO *, VARENT *); +void uvar(KINFO *, VARENT *); +void vsize(KINFO *, VARENT *); +void wchan(KINFO *, VARENT *); +void wq(KINFO *, VARENT *); +__END_DECLS diff --git a/adv_cmds/ps/fmt.c b/adv_cmds/ps/fmt.c new file mode 100644 index 0000000..26ba3dc --- /dev/null +++ b/adv_cmds/ps/fmt.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 1992, 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. + * 4. 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94"; +#endif +#endif + +#include +__FBSDID("$FreeBSD: src/bin/ps/fmt.c,v 1.34 2004/06/22 02:18:29 gad Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps.h" + +static char *cmdpart(char *); +static char *shquote(char **); + +static char * +shquote(char **argv) +{ + long arg_max; + static size_t buf_size; + size_t len; + char **p, *dst, *src; + static char *buf = NULL; + + if (buf == NULL) { + if ((arg_max = sysconf(_SC_ARG_MAX)) == -1) + errx(1, "sysconf _SC_ARG_MAX failed"); + if (arg_max >= LONG_MAX / 4 || arg_max >= (long)(SIZE_MAX / 4)) + errx(1, "sysconf _SC_ARG_MAX preposterously large"); + buf_size = 4 * arg_max + 1; + if ((buf = malloc(buf_size)) == NULL) + errx(1, "malloc failed"); + } + + if (*argv == NULL) { + buf[0] = '\0'; + return (buf); + } + dst = buf; + for (p = argv; (src = *p++) != NULL; ) { + if (*src == '\0') + continue; + len = (buf_size - 1 - (dst - buf)) / 4; + strvisx(dst, src, strlen(src) < len ? strlen(src) : len, + VIS_NL | VIS_CSTYLE); + while (*dst != '\0') + dst++; + if ((buf_size - 1 - (dst - buf)) / 4 > 0) + *dst++ = ' '; + } + /* Chop off trailing space */ + if (dst != buf && dst[-1] == ' ') + dst--; + *dst = '\0'; + return (buf); +} + +static char * +cmdpart(char *arg0) +{ + char *cp; + + return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); +} + +const char * +fmt_argv(char **argv, char *cmd, size_t maxlen) +{ + size_t len; + char *ap, *cp; + + if (argv == NULL || argv[0] == NULL) { + if (cmd == NULL) + return (""); + ap = NULL; + len = maxlen + 3; + } else { + ap = shquote(argv); + len = strlen(ap) + maxlen + 4; + } + cp = malloc(len); + if (cp == NULL) + errx(1, "malloc failed"); + if (ap == NULL) + sprintf(cp, "[%.*s]", (int)maxlen, cmd); + else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0) + sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd); + else + strcpy(cp, ap); + return (cp); +} diff --git a/adv_cmds/ps/keyword.c b/adv_cmds/ps/keyword.c new file mode 100644 index 0000000..ff311b4 --- /dev/null +++ b/adv_cmds/ps/keyword.c @@ -0,0 +1,340 @@ +/*- + * 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. + * 4. 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94"; +#else +static const char rcsid[] = + "$FreeBSD: keyword.c,v 1.23 1999/01/26 02:38:09 julian Exp $"; +#endif /* not lint */ +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ps.h" + +VAR *findvar(char *, int, char **header); +static int vcmp(const void *, const void *); + +/* Compute offset in common structures. */ +#define POFF(x) offsetof(struct extern_proc, x) +#define EOFF(x) offsetof(struct eproc, x) +#define UOFF(x) offsetof(struct usave, x) +#define ROFF(x) offsetof(struct rusage, x) + +#define EMULLEN 13 /* enough for "FreeBSD ELF32" */ +#define LWPFMT "d" +#define LWPLEN 6 +#define NLWPFMT "d" +#define NLWPLEN 4 +#ifdef __APPLE__ +#define UIDFMT "d" +#else +#define UIDFMT "u" +#endif +#define UIDLEN 5 +#define PIDFMT "d" +#define PIDLEN 5 +#define USERLEN 16 + +/* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */ +static VAR var[] = { + /* 4133537: 5 characters to accomodate 100% or more */ + {"%cpu", "%CPU", NULL, 0, pcpu, NULL, 5, 0, CHAR, NULL, 0}, + {"%mem", "%MEM", NULL, 0, pmem, NULL, 4}, + {"acflag", "ACFLG", + NULL, 0, pvar, NULL, 3, POFF(p_acflag), USHORT, "x"}, + {"acflg", "", "acflag"}, + {"args", "ARGS", NULL, COMM|LJUST|USER|DSIZ, args, s_args, 64}, + {"blocked", "", "sigmask"}, + {"caught", "", "sigcatch"}, + {"comm", "COMM", NULL, COMM|LJUST|USER|DSIZ, just_command, s_just_command, 16}, + {"command", "COMMAND", NULL, COMM|LJUST|USER|DSIZ, command, s_command, 16}, + {"cpu", "CPU", NULL, 0, pvar, NULL, 3, POFF(p_estcpu), UINT, "d"}, + {"cputime", "", "time"}, + {"etime", "ELAPSED", NULL, USER|DSIZ, p_etime, s_etime, 20}, + /* 5861775: Make F column 8 characters. */ + {"f", "F", NULL, 0, pvar, NULL, 8, POFF(p_flag), INT, "x"}, + {"flags", "", "f"}, + {"gid", "GID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_gid), + UINT, UIDFMT}, + {"group", "GROUP", "gid"}, + {"ignored", "", "sigignore"}, + {"inblk", "INBLK", + NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld"}, + {"inblock", "", "inblk"}, + {"jobc", "JOBC", NULL, 0, evar, NULL, 4, EOFF(e_jobc), SHORT, "d"}, + {"ktrace", "KTRACE", + NULL, 0, pvar, NULL, 8, POFF(p_traceflag), INT, "x"}, + {"ktracep", "KTRACEP", + NULL, 0, pvar, NULL, 8, POFF(p_tracep), LONG, "lx"}, + {"lim", "LIM", NULL, 0, maxrss, NULL, 5}, + {"login", "LOGIN", NULL, LJUST, logname, NULL, MAXLOGNAME-1}, + {"logname", "", "login"}, + {"lstart", "STARTED", NULL, LJUST|USER, lstarted, NULL, 28}, + {"majflt", "MAJFLT", + NULL, USER, rvar, NULL, 4, ROFF(ru_majflt), LONG, "ld"}, + {"minflt", "MINFLT", + NULL, USER, rvar, NULL, 4, ROFF(ru_minflt), LONG, "ld"}, + {"msgrcv", "MSGRCV", + NULL, USER, rvar, NULL, 4, ROFF(ru_msgrcv), LONG, "ld"}, + {"msgsnd", "MSGSND", + NULL, USER, rvar, NULL, 4, ROFF(ru_msgsnd), LONG, "ld"}, + {"ni", "", "nice"}, + {"nice", "NI", NULL, 0, pvar, NULL, 2, POFF(p_nice), CHAR, "d"}, + {"nivcsw", "NIVCSW", + NULL, USER, rvar, NULL, 5, ROFF(ru_nivcsw), LONG, "ld"}, + {"nsignals", "", "nsigs"}, + {"nsigs", "NSIGS", + NULL, USER, rvar, NULL, 4, ROFF(ru_nsignals), LONG, "ld"}, + {"nswap", "NSWAP", + NULL, USER, rvar, NULL, 4, ROFF(ru_nswap), LONG, "ld"}, + {"nvcsw", "NVCSW", + NULL, USER, rvar, NULL, 5, ROFF(ru_nvcsw), LONG, "ld"}, + {"nwchan", "WCHAN", NULL, 0, pvar, NULL, 6, POFF(p_wchan), KPTR, "lx"}, + {"oublk", "OUBLK", + NULL, USER, rvar, NULL, 4, ROFF(ru_oublock), LONG, "ld"}, + {"oublock", "", "oublk"}, + {"p_ru", "P_RU", NULL, 0, pvar, NULL, 6, POFF(p_ru), KPTR, "lx"}, + {"paddr", "PADDR", NULL, 0, evar, NULL, sizeof(void *) * 2, EOFF(e_paddr), KPTR, "lx"}, + {"pagein", "PAGEIN", NULL, USER, pagein, NULL, 6}, + {"pcpu", "", "%cpu"}, + {"pending", "", "sig"}, + {"pgid", "PGID", + NULL, 0, evar, NULL, PIDLEN, EOFF(e_pgid), UINT, PIDFMT}, + {"pid", "PID", NULL, 0, pvar, NULL, PIDLEN, POFF(p_pid), UINT, PIDFMT}, + {"pmem", "", "%mem"}, + {"ppid", "PPID", + NULL, 0, evar, NULL, PIDLEN, EOFF(e_ppid), UINT, PIDFMT}, + {"pri", "PRI", NULL, 0, pri, NULL, 3}, + {"pstime", "", "stime"}, + {"putime", "", "utime"}, + {"re", "RE", NULL, 0, pvar, NULL, 3, POFF(p_swtime), UINT, "d"}, + {"rgid", "RGID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_rgid), + UINT, UIDFMT}, + {"rgroup", "RGROUP", "rgid"}, + {"rss", "RSS", NULL, 0, p_rssize, NULL, 6}, +#if FIXME + {"rtprio", "RTPRIO", NULL, 0, rtprior, NULL, 7, POFF(p_rtprio)}, +#endif /* FIXME */ + {"ruid", "RUID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_ruid), + UINT, UIDFMT}, + {"ruser", "RUSER", NULL, LJUST|DSIZ, runame, s_runame, USERLEN}, + {"sess", "SESS", NULL, 0, evar, NULL, 6, EOFF(e_sess), KPTR, "lx"}, + {"sig", "PENDING", NULL, 0, pvar, NULL, 8, POFF(p_siglist), INT, "x"}, +#if FIXME + {"sigcatch", "CAUGHT", + NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigcatch), UINT, "x"}, + {"sigignore", "IGNORED", + NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigignore), UINT, "x"}, +#endif /* FIXME */ + {"sigmask", "BLOCKED", + NULL, 0, pvar, NULL, 8, POFF(p_sigmask), UINT, "x"}, + {"sl", "SL", NULL, 0, pvar, NULL, 3, POFF(p_slptime), UINT, "d"}, + {"start", "STARTED", NULL, LJUST|USER, started, NULL, 7}, + {"stat", "", "state"}, + {"state", "STAT", NULL, 0, state, NULL, 4}, + {"stime", "STIME", NULL, USER, pstime, NULL, 9}, + {"svgid", "SVGID", NULL, 0, + evar, NULL, UIDLEN, EOFF(e_pcred.p_svgid), UINT, UIDFMT}, + {"svuid", "SVUID", NULL, 0, + evar, NULL, UIDLEN, EOFF(e_pcred.p_svuid), UINT, UIDFMT}, + {"tdev", "TDEV", NULL, 0, tdev, NULL, 4}, + {"time", "TIME", NULL, USER, cputime, NULL, 9}, + {"tpgid", "TPGID", + NULL, 0, evar, NULL, 4, EOFF(e_tpgid), UINT, PIDFMT}, + {"tsess", "TSESS", NULL, 0, evar, NULL, 6, EOFF(e_tsess), KPTR, "lx"}, + {"tsiz", "TSIZ", NULL, 0, tsize, NULL, 8}, + {"tt", "TT ", NULL, 0, tname, NULL, 5}, + {"tty", "TTY", NULL, LJUST, longtname, NULL, 8}, + {"ucomm", "UCOMM", NULL, LJUST, ucomm, NULL, MAXCOMLEN}, + {"uid", "UID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_uid), + UINT, UIDFMT}, + {"upr", "UPR", NULL, 0, pvar, NULL, 3, POFF(p_usrpri), CHAR, "d"}, + {"user", "USER", NULL, LJUST|DSIZ, uname, s_uname, USERLEN}, + {"usrpri", "", "upr"}, + {"utime", "UTIME", NULL, USER, putime, NULL, 9}, + {"vsize", "", "vsz"}, + {"vsz", "VSZ", NULL, 0, vsize, NULL, 8}, + {"wchan", "WCHAN", NULL, LJUST, wchan, NULL, 6}, + {"wq", "WQ", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"wqb", "WQB", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"wql", "WQL", NULL, 0, wq, NULL, 3, 0, CHAR, NULL, 0}, + {"wqr", "WQR", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"xstat", "XSTAT", NULL, 0, pvar, NULL, 4, POFF(p_xstat), USHORT, "x"}, + {""}, +}; + +void +showkey(void) +{ + VAR *v; + int i; + const char *p, *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"); +} + +void +parsefmt(const char *p, int user) +{ + char *tempstr, *tempstr1; + +#define FMTSEP " \t,\n" + tempstr1 = tempstr = strdup(p); + while (tempstr && *tempstr) { + char *cp, *hp; + VAR *v; + struct varent *vent; + +#ifndef __APPLE__ + /* + * If an item contains an equals sign, it specifies a column + * header, may contain embedded separator characters and + * is always the last item. + */ + if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=') +#endif /* !__APPLE__ */ + while ((cp = strsep(&tempstr, FMTSEP)) != NULL && + *cp == '\0') + /* void */; +#ifndef __APPLE__ + else { + cp = tempstr; + tempstr = NULL; + } +#endif /* !__APPLE__ */ + if (cp == NULL || !(v = findvar(cp, user, &hp))) + continue; + if (!user) { + /* + * If the user is NOT adding this field manually, + * get on with our lives if this VAR is already + * represented in the list. + */ + vent = find_varentry(v); + if (vent != NULL) + continue; + } + if ((vent = malloc(sizeof(struct varent))) == NULL) + errx(1, "malloc failed"); + vent->header = v->header; + if (hp) { + hp = strdup(hp); + if (hp) + vent->header = hp; + } + vent->var = malloc(sizeof(*vent->var)); + if (vent->var == NULL) + errx(1, "malloc failed"); + memcpy(vent->var, v, sizeof(*vent->var)); + STAILQ_INSERT_TAIL(&varlist, vent, next_ve); + } + free(tempstr1); + if (STAILQ_EMPTY(&varlist)) { + warnx("no valid keywords; valid keywords:"); + showkey(); + exit(1); + } +} + +VAR * +findvar(char *p, int user, char **header) +{ + size_t rflen; + VAR *v, key; + char *hp, *realfmt; + + hp = strchr(p, '='); + if (hp) + *hp++ = '\0'; + + key.name = p; + v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp); + + if (v && v->alias) { + /* + * If the user specified an alternate-header for this + * (aliased) format-name, then we need to copy that + * alternate-header when making the recursive call to + * process the alias. + */ + if (hp == NULL) + parsefmt(v->alias, user); + else { + /* + * XXX - This processing will not be correct for + * any alias which expands into a list of format + * keywords. Presently there are no aliases + * which do that. + */ + rflen = strlen(v->alias) + strlen(hp) + 2; + realfmt = malloc(rflen); + snprintf(realfmt, rflen, "%s=%s", v->alias, hp); + parsefmt(realfmt, user); + } + return ((VAR *)NULL); + } + if (!v) { + warnx("%s: keyword not found", p); + eval = 1; + } + if (header) + *header = hp; + return (v); +} + +static int +vcmp(const void *a, const void *b) +{ + return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name)); +} diff --git a/adv_cmds/ps/nlist.c b/adv_cmds/ps/nlist.c new file mode 100644 index 0000000..90a2303 --- /dev/null +++ b/adv_cmds/ps/nlist.c @@ -0,0 +1,86 @@ +/*- + * 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. + * 4. 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)nlist.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD: src/bin/ps/nlist.c,v 1.21 2004/04/06 20:06:49 markm Exp $"); + +#include +#include +#ifdef __APPLE__ +#include +#endif + +#include + +#include "ps.h" + +fixpt_t ccpu; /* kernel _ccpu variable */ +int nlistread; /* if nlist already read. */ +#ifdef __APPLE__ +uint64_t mempages; /* number of pages of phys. memory */ +#else +unsigned long mempages; /* number of pages of phys. memory */ +#endif +int fscale; /* kernel _fscale variable */ + +int +donlist(void) +{ +#ifdef __APPLE__ + int mib[2]; +#endif + size_t oldlen; + +#ifdef __APPLE__ + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + oldlen = sizeof(mempages); + if (sysctl(mib, 2, &mempages, &oldlen, NULL, 0) == -1) + return (1); + fscale = 100; +#else + oldlen = sizeof(ccpu); + if (sysctlbyname("kern.ccpu", &ccpu, &oldlen, NULL, 0) == -1) + return (1); + oldlen = sizeof(fscale); + if (sysctlbyname("kern.fscale", &fscale, &oldlen, NULL, 0) == -1) + return (1); + oldlen = sizeof(mempages); + if (sysctlbyname("hw.availpages", &mempages, &oldlen, NULL, 0) == -1) + return (1); +#endif + nlistread = 1; + return (0); +} diff --git a/adv_cmds/ps/print.c b/adv_cmds/ps/print.c new file mode 100644 index 0000000..103ba48 --- /dev/null +++ b/adv_cmds/ps/print.c @@ -0,0 +1,1225 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; +#endif +static const char rcsid[] = + "$FreeBSD: print.c,v 1.33 1998/11/25 09:34:00 dfr Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if FIXME +#include +#endif /* FIXME */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps.h" + +extern int mflg, print_all_thread, print_thread_num; + +void +printheader(void) +{ + VAR *v; + struct varent *vent; + + STAILQ_FOREACH(vent, &varlist, next_ve) + if (*vent->header != '\0') + break; + if (!vent) + return; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (v->flag & LJUST) { + if (STAILQ_NEXT(vent, next_ve) == NULL) /* last one */ + (void)printf("%s", vent->header); + else + (void)printf("%-*s", v->width, vent->header); + } else + (void)printf("%*s", v->width, vent->header); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + (void)putchar('\n'); +} + +/* + * Get command and arguments. + * + * If the global variable eflg is non-zero and the user has permission to view + * the process's environment, the environment is included. + * + * on return argvlen is the length of the extracted string, argv0len is + * the length of the command (same as argvlen if show_args is true) + */ +static void +getproclline(KINFO *k, char **command_name, int *argvlen, int *argv0len, + int show_args) +{ + int mib[3], argmax, nargs, c = 0; + size_t size; + char *procargs, *sp, *np, *cp; + extern int eflg; + + /* Get the maximum process arguments size. */ + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + size = sizeof(argmax); + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) { + goto ERROR_A; + } + + /* Allocate space for the arguments. */ + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + goto ERROR_A; + } + + /* + * Make a sysctl() call to get the raw argument space of the process. + * The layout is documented in start.s, which is part of the Csu + * project. In summary, it looks like: + * + * /---------------\ 0x00000000 + * : : + * : : + * |---------------| + * | argc | + * |---------------| + * | arg[0] | + * |---------------| + * : : + * : : + * |---------------| + * | arg[argc - 1] | + * |---------------| + * | 0 | + * |---------------| + * | env[0] | + * |---------------| + * : : + * : : + * |---------------| + * | env[n] | + * |---------------| + * | 0 | + * |---------------| <-- Beginning of data returned by sysctl() is here. + * | argc | + * |---------------| + * | exec_path | + * |:::::::::::::::| + * | | + * | String area. | + * | | + * |---------------| <-- Top of stack. + * : : + * : : + * \---------------/ 0xffffffff + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = KI_PROC(k)->p_pid; + + size = (size_t)argmax; + if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) { + goto ERROR_B; + } + + memcpy(&nargs, procargs, sizeof(nargs)); + cp = procargs + sizeof(nargs); + + /* Skip the saved exec_path. */ + for (; cp < &procargs[size]; cp++) { + if (*cp == '\0') { + /* End of exec_path reached. */ + break; + } + } + if (cp == &procargs[size]) { + goto ERROR_B; + } + + /* Skip trailing '\0' characters. */ + for (; cp < &procargs[size]; cp++) { + if (*cp != '\0') { + /* Beginning of first argument reached. */ + break; + } + } + if (cp == &procargs[size]) { + goto ERROR_B; + } + /* Save where the argv[0] string starts. */ + sp = cp; + + /* + * Iterate through the '\0'-terminated strings and convert '\0' to ' ' + * until a string is found that has a '=' character in it (or there are + * no more strings in procargs). There is no way to deterministically + * know where the command arguments end and the environment strings + * start, which is why the '=' character is searched for as a heuristic. + */ + for (np = NULL; c < nargs && cp < &procargs[size]; cp++) { + if (*cp == '\0') { + c++; + if (np != NULL) { + /* Convert previous '\0'. */ + *np = ' '; + } else { + *argv0len = cp - sp; + } + /* Note location of current '\0'. */ + np = cp; + + if (!show_args) { + /* + * Don't convert '\0' characters to ' '. + * However, we needed to know that the + * command name was terminated, which we + * now know. + */ + break; + } + } + } + + /* + * If eflg is non-zero, continue converting '\0' characters to ' ' + * characters until no more strings that look like environment settings + * follow. + */ + if ( show_args && (eflg != 0) && ( (getuid() == 0) || (KI_EPROC(k)->e_pcred.p_ruid == getuid()) ) ) { + for (; cp < &procargs[size]; cp++) { + if (*cp == '\0') { + if (np != NULL) { + if (&np[1] == cp) { + /* + * Two '\0' characters in a row. + * This should normally only + * happen after all the strings + * have been seen, but in any + * case, stop parsing. + */ + break; + } + /* Convert previous '\0'. */ + *np = ' '; + } + /* Note location of current '\0'. */ + np = cp; + } + } + } + + /* + * sp points to the beginning of the arguments/environment string, and + * np should point to the '\0' terminator for the string. + */ + if (np == NULL || np == sp) { + /* Empty or unterminated string. */ + goto ERROR_B; + } + + /* Make a copy of the string. */ + *argvlen = asprintf(command_name, "%s", sp); + + /* Clean up. */ + free(procargs); + return; + + ERROR_B: + free(procargs); + ERROR_A: + *argv0len = *argvlen + = asprintf(command_name, "(%s)", KI_PROC(k)->p_comm); +} + +/* Return value is malloc'ed, please free it */ +char * +get_command_and_or_args(KINFO *k, int show_cmd, int show_args) +{ + char *vis_args; + + char *rawcmd, *cmd; + int cmdlen, argv0len = 0; + + + if(!mflg || (print_all_thread && (print_thread_num== 0))) { + getproclline(k, &rawcmd, &cmdlen, &argv0len, show_args); + + if (cflag) { + /* Ignore the path in cmd, if any. */ + for (cmd = &rawcmd[cmdlen - 1]; cmd > rawcmd; cmd--) { + if (*cmd == '/') { + cmd++; + break; + } + } + } else { + cmd = rawcmd; + } + + if (!show_cmd) { + cmd += argv0len; + if (*cmd) { + cmd++; + } + } + + if ((vis_args = malloc(strlen(cmd) * 4 + 1)) == NULL) + err(1, NULL); + strvis(vis_args, cmd, VIS_TAB | VIS_NL | VIS_NOSLASH); + free(rawcmd); + return vis_args; + } else { + return strdup(""); + } +} + +int +s_command_and_or_args(KINFO *k, int show_cmd, int show_args) +{ + char *s = get_command_and_or_args(k, show_cmd, show_args); + int sz = strlen(s); + free(s); + + return sz; +} + +void +p_command_and_or_args(KINFO *k, VARENT *ve, int show_cmd, int show_args, + int no_trunc) +{ + VAR *v = ve->var; + char *s = get_command_and_or_args(k, show_cmd, show_args); + + if (STAILQ_NEXT(ve, next_ve) == NULL) { + /* last field */ + if (termwidth == UNLIMITED) { + fputs(s, stdout); + } else { + int left; + char *cp; + + left = termwidth - (totwidth - v->width); + if (left < 1 || no_trunc) { + /* already wrapped, just use std * width */ + left = v->width; + } + for(cp = s; --left >= 0 && *cp;) { + (void)putchar(*cp++); + } + } + } else { + /* XXX env? */ + (void)printf("%-*.*s", v->width, v->width, s); + } + + free(s); +} + +int s_command(KINFO *k) { + return s_command_and_or_args(k, 1, !cflag); +} + +int s_args(KINFO *k) { + return s_command_and_or_args(k, 1, 1); +} + +int s_just_command(KINFO *k) { + return s_command_and_or_args(k, 1, 0); +} + +void command(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, !cflag, 0); +} + +void args(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, 1, 1); +} + +void just_command(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, 0, 0); +} + +void +ucomm(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%-*s", v->width, KI_PROC(k)->p_comm); +} + +char *getname(uid) + uid_t uid; +{ + register struct passwd *pw; + struct passwd *getpwuid(); + + pw = getpwuid((short)uid); + if (pw == NULL) { + return( "UNKNOWN" ); + } + return( pw->pw_name ); +} + +void +logname(KINFO *k, VARENT *ve) +{ + VAR *v; + char *s; + + v = ve->var; + (void)printf("%-*s", v->width, (s = getname(KI_EPROC(k)->e_ucred.cr_uid), *s) ? s : "-"); +} + +extern int mach_state_order(); +void +state(k, ve) + KINFO *k; + VARENT *ve; +{ + struct extern_proc *p; + int flag,j; + char *cp; + VAR *v; + char buf[16]; + extern char mach_state_table[]; + + v = ve->var; + p = KI_PROC(k); + flag = p->p_flag; + cp = buf; + + if(!mflg ) { + switch (p->p_stat) { + + case SSTOP: + *cp = 'T'; + break; + + case SZOMB: + *cp = 'Z'; + break; + + default: + *cp = mach_state_table[k->state]; + } + cp++; + if (p->p_nice < 0) + *cp++ = '<'; + else if (p->p_nice > 0) + *cp++ = 'N'; + if (flag & P_TRACED) + *cp++ = 'X'; + if (flag & P_WEXIT && p->p_stat != SZOMB) + *cp++ = 'E'; + if (flag & P_PPWAIT) + *cp++ = 'V'; + if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO)) + *cp++ = 'L'; + if (KI_EPROC(k)->e_flag & EPROC_SLEADER) + *cp++ = 's'; + if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid) + *cp++ = '+'; + *cp = '\0'; + (void)printf("%-*s", v->width, buf); + } else if (print_all_thread) { + j = mach_state_order(k->thval[print_thread_num].tb.run_state, + k->thval[print_thread_num].tb.sleep_time); + *cp++ = mach_state_table[j]; + *cp++='\0'; + (void)printf("%-*s", v->width, buf); + } else { + (void)printf("%-*s", v->width, " "); + } + +} + +void +pri(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + int j=0; + char c = '?'; + + v = ve->var; + if (!mflg ) { + (void)printf("%*d", v->width, k->curpri); + } else if (print_all_thread) { + switch(k->thval[print_thread_num].tb.policy) { + case POLICY_TIMESHARE : + j = k->thval[print_thread_num].schedinfo.tshare.cur_priority; + c = 'T'; + break; + case POLICY_FIFO : + j = k->thval[print_thread_num].schedinfo.fifo.base_priority; + c = 'F'; + break; + case POLICY_RR : + j = k->thval[print_thread_num].schedinfo.rr.base_priority; + c = 'R'; + break; + default : + j = 0; + } + (void)printf("%*d%c", v->width - 1, j, c); + }else { + j=0; + (void)printf("%*d", v->width, j); + + } +} + +void +uname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if(!mflg || (print_all_thread && (print_thread_num== 0))) + (void)printf("%-*s", + (int)v->width, + user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)); + else + (void)printf("%-*s", (int)v->width, " "); +} + +int +s_uname(KINFO *k) +{ + return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0))); +} + +void +runame(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%-*s", + (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)); +} + +int +s_runame(KINFO *k) +{ + return (strlen(user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0))); +} + +void +tdev(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char buff[16]; + + v = ve->var; + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV) + (void)printf("%*s", v->width, "??"); + else { + (void)snprintf(buff, sizeof(buff), + "%d/%d", major(dev), minor(dev)); + (void)printf("%*s", v->width, buff); + } +} + +void +tname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char *ttname; + + v = ve->var; + + if(!mflg || (print_all_thread && (print_thread_num== 0))) { + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) + (void)printf("%*s ", v->width-1, "??"); + else { + if (strncmp(ttname, "tty", 3) == 0 || + strncmp(ttname, "cua", 3) == 0) + ttname += 3; + (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, + KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-'); + } + } + else { + (void)printf("%*s ", v->width-1, " "); + } +} + +void +longtname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char *ttname; + + v = ve->var; + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) + (void)printf("%-*s", v->width, "??"); + else + (void)printf("%-*s", v->width, ttname); +} + +void +started(KINFO *k, VARENT *ve) +{ + VAR *v; + time_t then; + struct tm *tp; + static int use_ampm = -1; + char buf[100]; + + v = ve->var; + if (use_ampm < 0) + use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0'); + then = KI_PROC(k)->p_starttime.tv_sec; + tp = localtime(&then); + if (now - KI_PROC(k)->p_starttime.tv_sec < 24 * 3600) { + (void)strftime(buf, sizeof(buf), + use_ampm ? "%l:%M%p" : "%k:%M ", tp); + } else if (now - KI_PROC(k)->p_starttime.tv_sec < 7 * 86400) { + (void)strftime(buf, sizeof(buf), + use_ampm ? "%a%I%p" : "%a%H ", tp); + } else + (void)strftime(buf, sizeof(buf), "%e%b%y", tp); + (void)printf("%-*s", v->width, buf); +} + +void +lstarted(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + time_t then; + char buf[100]; + + v = ve->var; + then = KI_PROC(k)->p_starttime.tv_sec; + (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then)); + (void)printf("%-*s", v->width, buf); +} + +char *get_etime(KINFO *k) { + struct timeval tv; + gettimeofday(&tv, NULL); + long e = tv.tv_sec - KI_PROC(k)->p_starttime.tv_sec; + + char *ret; + + if (e > 100*60*60*24) { + asprintf(&ret, "%ld-%02ld:%02ld:%02ld", + e / (60*60*24), + (e / (60*60)) % 24, + (e / 60) % 60, + e % 60); + } else if (e > 60*60*24) { + asprintf(&ret, "%02ld-%02ld:%02ld:%02ld", + e / (60*60*24), + (e / (60*60)) % 24, + (e / 60) % 60, + e % 60); + } else if (e > 60*60) { + asprintf(&ret, "%02ld:%02ld:%02ld", + (e / (60*60)), + (e / 60) % 60, + e % 60); + } else { + asprintf(&ret, "%02ld:%02ld", + (e / 60), + e % 60); + } + + return ret; +} + +void p_etime(KINFO *k, VARENT *ve) { + char *str = get_etime(k); + printf("%*s", ve->var->width, str); + free(str); +} + +int s_etime(KINFO *k) { + char *str = get_etime(k); + int sz = strlen(str); + free(str); + return sz; +} + +void +wchan(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (KI_PROC(k)->p_wchan) { + if (KI_PROC(k)->p_wmesg) + (void)printf("%-*.*s", v->width, v->width, + KI_EPROC(k)->e_wmesg); + else +#if FIXME + (void)printf("%-*lx", v->width, + (long)KI_PROC(k)->p_wchan &~ KERNBASE); +#else /* FIXME */ + (void)printf("%-*lx", v->width, + (long)KI_PROC(k)->p_wchan); +#endif /* FIXME */ + } else + (void)printf("%-*s", v->width, "-"); +} + +#define pgtok(a) (((a)*getpagesize())/1024) + +void +vsize(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; +#if FIXME + (void)printf("%*d", v->width, + (KI_EPROC(k)->e_vm.vm_map.size/1024)); +#else /* FIXME */ + (void)printf("%*lu", v->width, + (u_long)((k)->tasks_info.virtual_size)/1024); +#endif /* FIXME */ +} + +void +p_rssize(k, ve) /* doesn't account for text */ + KINFO *k; + VARENT *ve; +{ + VAR *v; +/* FIXME LATER */ + v = ve->var; + /* (void)printf("%*ld", v->width, "-"); */ + (void)printf("%*lu", v->width, + (u_long)((k)->tasks_info.resident_size)/1024); +} + +void +cputime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t total_time, system_time; + v = ve->var; +#if FIXME + if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) { + secs = 0; + psecs = 0; + } else { + /* + * 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 + */ +#if FIXME + secs = KI_PROC(k)->p_runtime / 1000000; + psecs = KI_PROC(k)->p_runtime % 1000000; +#endif /* FIXME */ + if (sumrusage) { + secs += k->ki_u.u_cru.ru_utime.tv_sec + + k->ki_u.u_cru.ru_stime.tv_sec; + psecs += k->ki_u.u_cru.ru_utime.tv_usec + + k->ki_u.u_cru.ru_stime.tv_usec; + } + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + } +#else /* FIXME */ + total_time = k->tasks_info.user_time; + system_time = k->tasks_info.system_time; + + time_value_add(&total_time, &k->times.user_time); + time_value_add(&system_time, &k->times.system_time); + time_value_add(&total_time, &system_time); + + secs = total_time.seconds; + psecs = total_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; +#endif /* FIXME */ + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); +} + +void +putime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t user_time; + + + v = ve->var; + if (!mflg) { + user_time = k->tasks_info.user_time; + time_value_add(&user_time, &k->times.user_time); + } else if (print_all_thread) { + user_time = k->thval[print_thread_num].tb.user_time; + } else { + user_time.seconds =0; + user_time.microseconds =0; + } + + secs = user_time.seconds; + psecs = user_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); +} + +void +pstime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t system_time; + + v = ve->var; + if (!mflg) { + system_time = k->tasks_info.system_time; + time_value_add(&system_time, &k->times.system_time); + } else if (print_all_thread) { + system_time = k->thval[print_thread_num].tb.system_time; + } else { + system_time.seconds =0; + system_time.microseconds =0; + } + secs = system_time.seconds; + psecs = system_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); + +} + +int +getpcpu(k) + KINFO *k; +{ +#if FIXME + struct proc *p; + static int failure; + + if (!nlistread) + failure = donlist(); + if (failure) + return (0.0); + p = KI_PROC(k); +#define fxtofl(fixpt) ((double)(fixpt) / fscale) + + /* XXX - I don't like this */ + if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0) + return (0.0); + if (rawcpu) + return (100.0 * fxtofl(p->p_pctcpu)); + return (100.0 * fxtofl(p->p_pctcpu) / + (1.0 - exp(p->p_swtime * log(fxtofl(ccpu))))); +#else + return (k->cpu_usage); +#endif /* FIXME */ +} + +#ifndef TH_USAGE_SCALE +#define TH_USAGE_SCALE 1000 +#endif /* !TH_USAGE_SCALE */ + +void +pcpu(KINFO *k, VARENT *ve) +{ + VAR *v; + int cp; + + if (!mflg) { + cp = getpcpu(k); + } else if (print_all_thread) { + cp = k->thval[print_thread_num].tb.cpu_usage; + } else { + cp = 0; + } + + v = ve->var; + (void)printf("%*.1f", v->width, ((double)cp) * 100.0 / ((double)TH_USAGE_SCALE)); +} + +double +getpmem(k) + KINFO *k; +{ + static int failure; + double fracmem; + + if (!nlistread) + failure = donlist(); + if (failure) + return (0.0); +#if FIXME + p = KI_PROC(k); + e = KI_EPROC(k); + if ((p->p_flag & P_INMEM) == 0) + return (0.0); + /* XXX want pmap ptpages, segtab, etc. (per architecture) */ + szptudot = UPAGES; + /* XXX don't have info about shared */ + fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages; + return (100.0 * fracmem); +#else /* FIXME */ + fracmem = ((float)k->tasks_info.resident_size)/(double)mempages; + return (100.0 * fracmem); +#endif /* FIXME */ +} + +void +pmem(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%*.1f", v->width, getpmem(k)); +} + +void +pagein(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%*ld", v->width, + k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0); +} + +void +maxrss(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + /* XXX not yet */ + (void)printf("%*s", v->width, "-"); +} + +void +tsize(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + int dummy=0; + + v = ve->var; +#if 0 + (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_tsize)); +#else + (void)printf("%*ld", v->width, (long)dummy); +#endif +} + +void +rtprior(k, ve) + KINFO *k; + VARENT *ve; +{ +#if FIXME + + VAR *v; + struct rtprio *prtp; + char str[8]; + unsigned prio, type; + + v = ve->var; + prtp = (struct rtprio *) ((char *)KI_PROC(k) + v->off); + prio = prtp->prio; + type = prtp->type; + switch (type) { + case RTP_PRIO_REALTIME: + snprintf(str, sizeof(str), "real:%u", prio); + break; + case RTP_PRIO_NORMAL: + strncpy(str, "normal", sizeof(str)); + break; + case RTP_PRIO_IDLE: + snprintf(str, sizeof(str), "idle:%u", prio); + break; + default: + snprintf(str, sizeof(str), "%u:%u", type, prio); + break; + } + str[sizeof(str) - 1] = '\0'; + (void)printf("%*s", v->width, str); +#endif /* FIXME */ +} + +/* + * Generic output routines. Print fields from various prototype + * structures. + */ +static void +printval(void *bp, VAR *v) +{ + static char ofmt[32] = "%"; + const char *fcp; + char *cp; + + cp = ofmt + 1; + fcp = v->fmt; + if (v->flag & LJUST) + *cp++ = '-'; + *cp++ = '*'; + while ((*cp++ = *fcp++)); + + switch (v->type) { + case CHAR: + (void)printf(ofmt, v->width, *(char *)bp); + break; + case UCHAR: + (void)printf(ofmt, v->width, *(u_char *)bp); + break; + case SHORT: + (void)printf(ofmt, v->width, *(short *)bp); + break; + case USHORT: + (void)printf(ofmt, v->width, *(u_short *)bp); + break; + case INT: + (void)printf(ofmt, v->width, *(int *)bp); + break; + case UINT: + (void)printf(ofmt, v->width, *(u_int *)bp); + break; + case LONG: + (void)printf(ofmt, v->width, *(long *)bp); + break; + case ULONG: + (void)printf(ofmt, v->width, *(u_long *)bp); + break; + case KPTR: +#if FIXME + (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); +#else /* FIXME */ + (void)printf(ofmt, v->width, *(u_long *)bp); +#endif /* FIXME */ + break; + default: + errx(1, "unknown type %d", v->type); + } +} + +void +pvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + printval((char *)((char *)KI_PROC(k) + v->off), v); +} + +void +evar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + printval((char *)((char *)KI_EPROC(k) + v->off), v); +} + +void +uvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (k->ki_u.u_valid) + printval((char *)((char *)&k->ki_u + v->off), v); + else + (void)printf("%*s", v->width, "-"); +} + +void +rvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (k->ki_u.u_valid) + printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v); + else + (void)printf("%*s", v->width, "-"); +} + +void +wq(KINFO *k, VARENT *ve) +{ + VAR *v; + struct proc_workqueueinfo wqinfo; + int len; + int ret; + uint32_t nthreads; + + len = sizeof(wqinfo); + ret = proc_pidinfo(KI_PROC(k)->p_pid, PROC_PIDWORKQUEUEINFO, 0, &wqinfo, len); + + v = ve->var; + + if (len == ret && len == PROC_PIDWORKQUEUEINFO_SIZE) { + if (strcmp(v->name, "wql") == 0) { + char *s; + switch (wqinfo.pwq_state & (WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT | WQ_EXCEEDED_TOTAL_THREAD_LIMIT)) { + case 0: + s = "-"; + break; + case WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT: + s = "C"; + break; + case WQ_EXCEEDED_TOTAL_THREAD_LIMIT: + s = "T"; + break; + default: + s = "CT"; + break; + } + printf("%*s", v->width, s); + return; + } + if (strcmp(v->name, "wqr") == 0) + nthreads = wqinfo.pwq_runthreads; + else if (strcmp(v->name, "wqb") == 0) + nthreads = wqinfo.pwq_blockedthreads; + else + nthreads = wqinfo.pwq_nthreads; + printf("%*d", v->width, nthreads); + } else + printf("%*s", v->width, "-"); +} diff --git a/adv_cmds/ps/ps.1 b/adv_cmds/ps/ps.1 new file mode 100644 index 0000000..20eed1c --- /dev/null +++ b/adv_cmds/ps/ps.1 @@ -0,0 +1,663 @@ +.\"- +.\" 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. +.\" 4. 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 +.\" $FreeBSD: src/bin/ps/ps.1,v 1.86 2005/04/29 11:10:27 maxim Exp $ +.\" +.Dd March 20, 2005 +.Dt PS 1 +.Os +.Sh NAME +.Nm ps +.Nd process status +.Sh SYNOPSIS +.Nm +.Op Fl AaCcEefhjlMmrSTvwXx +.Op Fl O Ar fmt | Fl o Ar fmt +.Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ... +.Op Fl g Ar grp Ns Op , Ns Ar grp Ns Ar ... +.Op Fl u Ar uid Ns Op , Ns Ar uid Ns Ar ... +.Op Fl p Ar pid Ns Op , Ns Ar pid Ns Ar ... +.Op Fl t Ar tty Ns Op , Ns Ar tty Ns Ar ... +.Op Fl U Ar user Ns Op , Ns Ar user Ns Ar ... +.Nm +.Op Fl L +.Sh DESCRIPTION +The +.Nm +utility +displays a header line, followed by lines containing information about +all of your +processes that have controlling terminals. +.Pp +A different set of processes can be selected for display by using any +combination of the +.Fl a , G , g , p , T , t , U , +and +.Fl u +options. +If more than one of these options are given, then +.Nm +will select all processes which are matched by at least one of the +given options. +.Pp +For the processes which have been selected for display, +.Nm +will usually display one line per process. +The +.Fl M +option may result in multiple output lines (one line per thread) for +some processes. +By default all of these output lines are sorted first by controlling +terminal, then by process ID. +The +.Fl m , r , +and +.Fl v +options will change the sort order. +If more than one sorting option was given, then the selected processes +will be sorted by the last sorting option which was specified. +.Pp +For the processes which have been selected for display, the information +to display is selected based on a set of keywords (see the +.Fl L , O , +and +.Fl o +options). +The default output format includes, for each process, the process' ID, +controlling terminal, CPU time (including both user and system time), +state, and associated command. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl A +Display information about other users' processes, +including those without controlling terminals. +.It Fl a +Display information about other users' processes as well as your own. +This will skip any processes which do not have a controlling terminal, +unless the +.Fl x +option is also specified. +.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 +Change the +.Dq command +column output to just contain the executable name, +rather than the full command line. +.It Fl d +Like +.Fl A , +but excludes session leaders. +.It Fl E +Display the environment as well. +This does not reflect changes in the environment after process launch. +.It Fl e +Identical to +.Fl A . +.It Fl f +Display the uid, pid, parent pid, recent CPU usage, process start time, +controlling tty, elapsed CPU usage, and the associated command. +If the +.Fl u +option is also used, display the user name rather then the numeric uid. +When +.Fl o +or +.Fl O +is used to add to the display following +.Fl f , +the command field is not truncated as severely as it is in other formats. +.It Fl G +Display information about processes +which are running with the specified real group IDs. +.It Fl g +Display information about processes with the specified +process group leaders. +.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: +.Cm user , pid , ppid , pgid , sess , jobc , state , tt , time , +and +.Cm command . +.It Fl L +List the set of keywords available for the +.Fl O +and +.Fl o +options. +.It Fl l +Display information associated with the following keywords: +.Cm uid , pid , ppid , flags , cpu , pri , nice , vsz=SZ , rss , +.Cm wchan , state=S , paddr=ADDR , tty , time , +and +.Cm command=CMD . +.It Fl M +Print the threads corresponding to each task. +.It Fl m +Sort by memory usage, instead of the combination of controlling +terminal and process ID. +.It Fl O +Add the information associated with the space or comma separated list +of keywords specified, after the process ID, +in the default information +display. +Keywords may be appended with an equals +.Pq Ql = +sign and a string. +This causes the printed header to use the specified string instead of +the standard header. +.It Fl o +Display information associated with the space or comma separated +list of keywords specified. +Multiple keywords may also be given in the form of more than one +.Fl o +option. +Keywords may be appended with an equals +.Pq Ql = +sign and a string. +This causes the printed header to use the specified string instead of +the standard header. +If all keywords have empty header texts, no header line is written. +.It Fl p +Display information about processes which match the specified process IDs. +.It Fl r +Sort by current CPU usage, instead of the combination of controlling +terminal and process ID. +.It Fl S +Change the way the process time is calculated by summing all exited +children to their parent process. +.It Fl T +Display information about processes attached to the device associated +with the standard input. +.It Fl t +Display information about processes attached to the specified terminal +devices. +.It Fl U +Display the processes belonging to the specified real user IDs. +.It Fl u +Display the processes belonging to the specified usernames. +.It Fl v +Display information associated with the following keywords: +.Cm pid , state , time , sl , re , pagein , vsz , rss , lim , tsiz , +.Cm %cpu , %mem , +and +.Cm command . +The +.Fl v +option implies the +.Fl m +option. +.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 for your window size. +When output is not to a terminal, an unlimited number of columns are +always used. +.It Fl X +When displaying processes matched by other options, skip any processes +which do not have a controlling terminal. +.It Fl x +When displaying processes matched by other options, include processes +which do not have a controlling terminal. +This is the opposite of the +.Fl X +option. +If both +.Fl X +and +.Fl x +are specified in the same command, then +.Nm +will use the one which was specified last. +.El +.Pp +A complete list of the available keywords is given below. +Some of these keywords are further specified as follows: +.Bl -tag -width lockname +.It Cm %cpu +The CPU utilization of the process; +this is a decaying average over up to a minute of previous (real) time. +Because the time base over which this is computed varies +(some processes may be very young), +it is possible for the sum of all +.Cm %cpu +fields to exceed 100%. +.It Cm %mem +The percentage of real memory used by this process. +.It Cm flags +The flags associated with the process as in +the include file +.In sys/proc.h : +.Bl -column P_STOPPED_SINGLE 0x4000000 +.It Dv "P_ADVLOCK" Ta No "0x00001 Process may hold a POSIX advisory lock" +.It Dv "P_CONTROLT" Ta No "0x00002 Has a controlling terminal" +.It Dv "P_LP64" Ta No "0x00004 Process is LP64" +.It Dv "P_NOCLDSTOP" Ta No "0x00008 No SIGCHLD when children stop" +.It Dv "P_PPWAIT" Ta No "0x00010 Parent is waiting for child to exec/exit" +.It Dv "P_PROFIL" Ta No "0x00020 Has started profiling" +.It Dv "P_SELECT" Ta No "0x00040 Selecting; wakeup/waiting danger" +.It Dv "P_CONTINUED" Ta No "0x00080 Process was stopped and continued" +.It Dv "P_SUGID" Ta No "0x00100 Had set id privileges since last exec" +.It Dv "P_SYSTEM" Ta No "0x00200 System proc: no sigs, stats or swapping" +.It Dv "P_TIMEOUT" Ta No "0x00400 Timing out during sleep" +.It Dv "P_TRACED" Ta No "0x00800 Debugged process being traced" +.It Dv "P_WAITED" Ta No "0x01000 Debugging process has waited for child" +.It Dv "P_WEXIT" Ta No "0x02000 Working on exiting" +.It Dv "P_EXEC" Ta No "0x04000 Process called exec" +.It Dv "P_OWEUPC" Ta No "0x08000 Owe process an addupc() call at next ast" +.It Dv "P_WAITING" Ta No "0x40000 Process has a wait() in progress" +.It Dv "P_KDEBUG" Ta No "0x80000 Kdebug tracing on for this process" +.El +.It Cm lim +The soft limit on memory used, specified via a call to +.Xr setrlimit 2 . +.It Cm lstart +The exact time the command started, using the +.Ql %c +format described in +.Xr strftime 3 . +.It Cm nice +The process scheduling increment (see +.Xr setpriority 2 ) . +.It Cm rss +the real memory (resident set) size of the process (in 1024 byte units). +.It Cm start +The time the command started. +If the command started less than 24 hours ago, the start time is +displayed using the +.Dq Li %l:ps.1p +format described in +.Xr strftime 3 . +If the command started less than 7 days ago, the start time is +displayed using the +.Dq Li %a6.15p +format. +Otherwise, the start time is displayed using the +.Dq Li %e%b%y +format. +.It Cm state +The state is given by a sequence of characters, for example, +.Dq Li RWNA . +The first character indicates the run state of the process: +.Pp +.Bl -tag -width indent -compact +.It Li I +Marks a process that is idle (sleeping for longer than about 20 seconds). +.It Li R +Marks a runnable process. +.It Li S +Marks a process that is sleeping for less than about 20 seconds. +.It Li T +Marks a stopped process. +.It Li U +Marks a process in uninterruptible wait. +.It Li Z +Marks a dead process (a +.Dq zombie ) . +.El +.Pp +Additional characters after these, if any, indicate additional state +information: +.Pp +.Bl -tag -width indent -compact +.It Li + +The process is in the foreground process group of its control terminal. +.It Li < +The process has raised CPU scheduling priority. +.It Li > +The process has specified a soft limit on memory requirements and is +currently exceeding that limit; such a process is (necessarily) not +swapped. +.It Li A +the process has asked for random page replacement +.Pf ( Dv VA_ANOM , +from +.Xr vadvise 2 , +for example, +.Xr lisp 1 +in a garbage collect). +.It Li E +The process is trying to exit. +.It Li L +The process has pages locked in core (for example, for raw +.Tn I/O ) . +.It Li N +The process has reduced CPU scheduling priority (see +.Xr setpriority 2 ) . +.It Li S +The process has asked for +.Tn FIFO +page replacement +.Pf ( Dv VA_SEQL , +from +.Xr vadvise 2 , +for example, a large image processing program using virtual memory to +sequentially address voluminous data). +.It Li s +The process is a session leader. +.It Li V +The process is suspended during a +.Xr vfork 2 . +.It Li W +The process is swapped out. +.It Li X +The process is being traced or debugged. +.El +.It Cm tt +An abbreviation for the pathname of the controlling terminal, if any. +The abbreviation consists of the three letters following +.Pa /dev/tty , +or, for the console, +.Dq Li con . +This is followed by a +.Ql - +if the process can no longer reach that +controlling terminal (i.e., it has been revoked). +.It Cm 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 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 Li , +and a process which is blocked while trying +to exit is listed as +.Dq Li . +If the arguments 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. +The process can change the arguments shown with +.Xr setproctitle 3 . +Otherwise, +.Nm +makes an educated guess as to the file name and arguments given when the +process was created by examining memory or the swap area. +The method is inherently somewhat unreliable and in any event a process +is entitled to destroy this information. +The ucomm (accounting) keyword can, however, be depended on. +If the arguments are unavailable or do not agree with the ucomm keyword, +the value for the ucomm keyword is appended to the arguments in parentheses. +.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 ".Cm sigignore" -compact +.It Cm %cpu +percentage CPU usage (alias +.Cm pcpu ) +.It Cm %mem +percentage memory usage (alias +.Cm pmem ) +.It Cm acflag +accounting flag (alias +.Cm acflg ) +.It Cm args +command and arguments +.It Cm comm +command +.It Cm command +command and arguments +.It Cm cpu +short-term CPU usage factor (for scheduling) +.It Cm etime +elapsed running time +.It Cm flags +the process flags, in hexadecimal (alias +.Cm f ) +.It Cm gid +processes group id (alias +.Cm group ) +.It Cm inblk +total blocks read (alias +.Cm inblock ) +.It Cm jobc +job control count +.It Cm ktrace +tracing flags +.It Cm ktracep +tracing vnode +.It Cm lim +memoryuse limit +.It Cm logname +login name of user who started the session +.It Cm lstart +time started +.It Cm majflt +total page faults +.It Cm minflt +total page reclaims +.It Cm msgrcv +total messages received (reads from pipes/sockets) +.It Cm msgsnd +total messages sent (writes on pipes/sockets) +.It Cm nice +nice value (alias +.Cm ni ) +.It Cm nivcsw +total involuntary context switches +.It Cm nsigs +total signals taken (alias +.Cm nsignals ) +.It Cm nswap +total swaps in/out +.It Cm nvcsw +total voluntary context switches +.It Cm nwchan +wait channel (as an address) +.It Cm oublk +total blocks written (alias +.Cm oublock ) +.It Cm p_ru +resource usage (valid only for zombie) +.It Cm paddr +swap address +.It Cm pagein +pageins (same as majflt) +.It Cm pgid +process group number +.It Cm pid +process ID +.It Cm ppid +parent process ID +.It Cm pri +scheduling priority +.It Cm re +core residency time (in seconds; 127 = infinity) +.It Cm rgid +real group ID +.It Cm rss +resident set size +.It Cm ruid +real user ID +.It Cm ruser +user name (from ruid) +.It Cm sess +session ID +.It Cm sig +pending signals (alias +.Cm pending ) +.It Cm sigmask +blocked signals (alias +.Cm blocked ) +.It Cm sl +sleep time (in seconds; 127 = infinity) +.It Cm start +time started +.It Cm state +symbolic process state (alias +.Cm stat ) +.It Cm svgid +saved gid from a setgid executable +.It Cm svuid +saved UID from a setuid executable +.It Cm tdev +control terminal device number +.It Cm time +accumulated CPU time, user + system (alias +.Cm cputime ) +.It Cm tpgid +control terminal process group ID +.\".It Cm trss +.\"text resident set size (in Kbytes) +.It Cm tsess +control terminal session ID +.It Cm tsiz +text size (in Kbytes) +.It Cm tt +control terminal name (two letter abbreviation) +.It Cm tty +full name of control terminal +.It Cm ucomm +name to be used for accounting +.It Cm uid +effective user ID +.It Cm upr +scheduling priority on return from system call (alias +.Cm usrpri ) +.It Cm user +user name (from UID) +.It Cm utime +user CPU time (alias +.Cm putime ) +.It Cm vsz +virtual size in Kbytes (alias +.Cm vsize ) +.It Cm wchan +wait channel (as a symbolic name) +.It Cm wq +total number of workqueue threads +.It Cm wqb +number of blocked workqueue threads +.It Cm wqr +number of running workqueue threads +.It Cm wql +workqueue limit status (C = constrained thread limit, T = total thread limit) +.It Cm xstat +exit or stop status (valid only for stopped or zombie process) +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev COLUMNS" +.It Ev COLUMNS +If set, specifies the user's preferred output width in column positions. +By default, +.Nm +attempts to automatically determine the terminal width. +.El +.Sh FILES +.Bl -tag -width ".Pa /boot/kernel/kernel" -compact +.It Pa /dev +special files and device names +.It Pa /var/run/dev.db +/dev name database +.It Pa /var/db/kvm_kernel.db +system namelist database +.El +.Sh LEGACY DESCRIPTION +In legacy mode, +.Nm +functions as described above, with the following differences: +.Bl -tag -width indent +.It Fl e +Display the environment as well. Same as +.Fl E . +.It Fl g +Ignored for compatibility. Takes no argument. +.It Fl l +Display information associated with the following keywords: +.Cm uid , pid , ppid , cpu , pri , nice , vsz , rss , wchan , state , +.Cm tt, time , +and +.Cm command . +.It Fl u +Display information associated with the following keywords: +.Cm user , pid , %cpu , %mem , vsz , rss , tt , state , start , time , +and +.Cm command . +The +.Fl u +option implies the +.Fl r +option. +.El +.Pp +The biggest change is in the interpretation of the +.Fl u +option, +which now displays processes belonging to the specified username(s). +Thus, "ps -aux" will fail (unless you want to know about user "x"). +As a convenience, however, "ps aux" still works as it did in Tiger. +.Pp +For more information about legacy mode, see +.Xr compat 5 . +.Sh SEE ALSO +.Xr kill 1 , +.Xr w 1 , +.Xr kvm 3 , +.Xr strftime 3 , +.Xr sysctl 8 +.Sh STANDARDS +The +.Nm +utility supports the +.St -susv3 +standard. +.Sh HISTORY +The +.Nm +command appeared in +.At v4 . +.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. +.Pp +The +.Nm +utility does not correctly display argument lists containing multibyte +characters. diff --git a/adv_cmds/ps/ps.c b/adv_cmds/ps/ps.c new file mode 100644 index 0000000..72c0242 --- /dev/null +++ b/adv_cmds/ps/ps.c @@ -0,0 +1,1373 @@ +/*- + * 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. + * 4. 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. + * ------+---------+---------+-------- + --------+---------+---------+---------* + * Copyright (c) 2004 - Garance Alistair Drosehn . + * All rights reserved. + * + * Significant modifications made to bring `ps' options somewhat closer + * to the standard for `ps' as described in SingleUnixSpec-v3. + * ------+---------+---------+-------- + --------+---------+---------+---------* + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD: src/bin/ps/ps.c,v 1.110 2005/02/09 17:37:38 ru Exp $"); + +#include +#ifdef __APPLE__ +#include +#endif /* __APPLE__ */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifndef __APPLE__ +#include +#endif /* !__APPLE__ */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps.h" + +#ifdef __APPLE__ +#include +#else /* !__APPLE__ */ +#define COMPAT_MODE(func, mode) (1) +#endif /* __APPLE__ */ + +#define W_SEP " \t" /* "Whitespace" list separators */ +#define T_SEP "," /* "Terminate-element" list separators */ + +#ifdef LAZY_PS +#define DEF_UREAD 0 +#define OPT_LAZY_f "f" +#else +#define DEF_UREAD 1 /* Always do the more-expensive read. */ +#define OPT_LAZY_f /* I.e., the `-f' option is not added. */ +#endif + +/* + * isdigit takes an `int', but expects values in the range of unsigned char. + * This wrapper ensures that values from a 'char' end up in the correct range. + */ +#define isdigitch(Anychar) isdigit((u_char)(Anychar)) + +int cflag; /* -c */ +int eval; /* Exit value */ +time_t now; /* Current time(3) value */ +int rawcpu; /* -C */ +int sumrusage; /* -S */ +int termwidth; /* Width of the screen (0 == infinity). */ +int totwidth; /* Calculated-width of requested variables. */ + +struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist); + +#ifndef __APPLE__ +static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */ +static kvm_t *kd; +#endif /* !__APPLE__ */ +static KINFO *kinfo; +static int needcomm; /* -o "command" */ +static int needenv; /* -e */ +static int needuser; /* -o "user" */ +static int optfatal; /* Fatal error parsing some list-option. */ + +static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; + +struct listinfo; +typedef int addelem_rtn(struct listinfo *_inf, const char *_elem); + +struct listinfo { + int count; + int maxcount; + int elemsize; + addelem_rtn *addelem; + const char *lname; + union { + gid_t *gids; + pid_t *pids; + dev_t *ttys; + uid_t *uids; + void *ptr; + } l; +}; + +#ifndef __APPLE__ +static int check_procfs(void); +#endif /* !__APPLE__ */ +static int addelem_gid(struct listinfo *, const char *); +static int addelem_pid(struct listinfo *, const char *); +static int addelem_tty(struct listinfo *, const char *); +static int addelem_uid(struct listinfo *, const char *); +static void add_list(struct listinfo *, const char *); +static void dynsizevars(KINFO *); +static void *expand_list(struct listinfo *); +#ifndef __APPLE__ +static const char * + fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), + KINFO *, char *, int); +#endif /* !__APPLE__ */ +static void free_list(struct listinfo *); +static void init_list(struct listinfo *, addelem_rtn, int, const char *); +static char *kludge_oldps_options(const char *, char *, const char *, int *); +static int pscomp(const void *, const void *); +static void saveuser(KINFO *); +static void scanvars(void); +static void sizevars(void); +static void usage(int); + +/* 5842004: Fix -f option. */ +VAR *findvar(char *, int, char **); + +/* p_ == POSIX/SUSv3/UNIX2003 format */ +static char dfmt[] = "pid,tt,state,time,command"; +static char jfmt[] = "user,pid,ppid,pgid,sess,jobc,state,tt,time,command"; +static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,state," + "tt,time,command"; +static char o1[] = "pid"; +static char o2[] = "tt,state,time,command"; +static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; +static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," + "%cpu,%mem,command"; +#ifndef __APPLE__ +static char Zfmt[] = "label"; +#endif /* !__APPLE__ */ +char p_dfmt[] = "pid tty time command=CMD"; +char p_ffmt[] = "uid pid ppid cpu=C start=STIME tty time command=CMD"; +char p_uffmt[] = "user pid ppid cpu=C start=STIME tty time command=CMD"; +char p_lfmt[] = "uid pid ppid flags cpu pri nice vsz=SZ rss wchan state=S paddr=ADDR tty time command=CMD"; +char mfmt[] = "user pid tt %cpu state pri stime utime command"; + +int eflg = 0; +int mflg = 0; /* if -M option to display all mach threads */ +int print_thread_num = 0; +int print_all_thread = 0; + +#define PS_ARGS (u03 ? "aACcdeEfg:G:hjLlMmO:o:p:rSTt:U:u:vwx" : \ + "aACcdeEgG:hjLlMmO:o:p:rSTt:U:uvwx") + +int +main(int argc, char *argv[]) +{ + struct listinfo gidlist, pgrplist, pidlist; + struct listinfo ruidlist, sesslist, ttylist, uidlist; + struct kinfo_proc *kp; + KINFO *next_KINFO; + struct varent *vent; + struct winsize ws; +#ifndef __APPLE__ + const char *nlistf, *memf; +#endif /* !__APPLE__ */ + char *cols; + int all, ch, elem, flag, _fmt, i, lineno; + int nentries, nkept, nselectors; + int prtheader, showthreads, wflag, what, xkeep, xkeep_implied; +#ifndef __APPLE__ + char errbuf[_POSIX2_LINE_MAX]; +#endif /* !__APPLE__ */ + struct kinfo_proc *kprocbuf; + int j; + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; + size_t bufSize = 0; + size_t orig_bufSize = 0; + int local_error=0; + int retry_count = 0; + int u03 = COMPAT_MODE("bin/ps", "unix2003"); +#ifdef __APPLE__ + int dflag = 0; +#endif /* __APPLE__ */ + + (void) setlocale(LC_ALL, ""); + time(&now); /* Used by routines in print.c. */ + + if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') + termwidth = atoi(cols); + else 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; + + /* + * Hide a number of option-processing kludges in a separate routine, + * to support some historical BSD behaviors, such as `ps axu'. + */ + if (argc > 1) + argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2], &u03); + + all = _fmt = nselectors = optfatal = 0; + prtheader = showthreads = wflag = xkeep_implied = 0; + xkeep = -1; /* Neither -x nor -X. */ + init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); + init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); + init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); + init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); + init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id"); + init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty"); + init_list(&uidlist, addelem_uid, sizeof(uid_t), "user"); +#ifndef __APPLE__ + memf = nlistf = _PATH_DEVNULL; +#endif /* !__APPLE__ */ + while ((ch = getopt(argc, argv, PS_ARGS)) != -1) + switch ((char)ch) { +#ifdef __APPLE__ + case 'd': + dflag = 1; +#endif /* __APPLE__ */ + case 'A': + /* + * Exactly the same as `-ax'. This has been + * added for compatability with SUSv3, but for + * now it will not be described in the man page. + */ + nselectors++; + all = xkeep = 1; + break; + case 'a': + nselectors++; + all = 1; + break; + case 'C': + rawcpu = 1; + break; + case 'c': + cflag = 1; + break; + case 'e': /* XXX set ufmt */ + if (u03) { + nselectors++; + all = xkeep = 1; + break; + } + case 'E': + needenv = 1; + eflg = 1; + break; +#ifdef LAZY_PS + case 'f': + if (getuid() == 0 || getgid() == 0) + forceuread = 1; + break; +#endif + case 'f': + termwidth = UNLIMITED; /* 4990408 */ + if (u03 && uidlist.count == 0) { + parsefmt(p_ffmt, 0); + /* This is a unplesent little trick that makes + ./ps -f -p PID -o pid,comm,args + print out the whole command even if they slap + more fields on after it and gobble up too much + space */ + VAR *v = findvar("command", 0, NULL); + if (v) { + v->width = 64; + } + } else { + parsefmt(p_uffmt, 0); + } + _fmt = 1; + break; + case 'G': + add_list(&gidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'g': + /* The historical BSD-ish (from SunOS) behavior. */ + if (!u03) break; + + add_list(&pgrplist, optarg); + xkeep_implied = 1; + nselectors++; + break; +#ifndef __APPLE__ + case 'H': + showthreads = KERN_PROC_INC_THREAD; + break; +#endif /* !__APPLE__ */ + case 'h': + prtheader = ws.ws_row > 5 ? ws.ws_row : 22; + break; + case 'j': + parsefmt(jfmt, 0); + _fmt = 1; + jfmt[0] = '\0'; + break; + case 'L': + showkey(); + exit(0); + case 'l': + parsefmt(u03 ? p_lfmt : lfmt, 0); + _fmt = 1; + lfmt[0] = '\0'; + break; + case 'M': +#ifndef __APPLE__ + memf = optarg; +#else + parsefmt(mfmt, 0); + _fmt = 1; + mfmt[0] = '\0'; + mflg = 1; +#endif /* 0 */ + break; + case 'm': + sortby = SORTMEM; + break; +#ifndef __APPLE__ + case 'N': + nlistf = optarg; + break; +#endif /* !__APPLE__ */ + case 'O': + parsefmt(o1, 1); + parsefmt(optarg, 1); + parsefmt(o2, 1); + o1[0] = o2[0] = '\0'; + _fmt = 1; + break; + case 'o': + parsefmt(optarg, 1); + _fmt = 1; + break; + case 'p': + add_list(&pidlist, optarg); + /* + * Note: `-p' does not *set* xkeep, but any values + * from pidlist are checked before xkeep is. That + * way they are always matched, even if the user + * specifies `-X'. + */ + nselectors++; + break; + case 'r': + sortby = SORTCPU; + break; + case 'S': + sumrusage = 1; + break; + case 'T': + if ((optarg = ttyname(STDIN_FILENO)) == NULL) + errx(1, "stdin: not a terminal"); + /* FALLTHROUGH */ + case 't': + add_list(&ttylist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'U': + add_list(&ruidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'u': + if (u03) { + /* This is what SUSv3 defines as the `-u' option. */ + add_list(&uidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + } + parsefmt(ufmt, 0); + sortby = SORTCPU; + _fmt = 1; + ufmt[0] = '\0'; + break; + case 'v': + parsefmt(vfmt, 0); + sortby = SORTMEM; + _fmt = 1; + vfmt[0] = '\0'; + break; + case 'w': + if (wflag) + termwidth = UNLIMITED; + else if (termwidth < 131) + termwidth = 131; + wflag++; + break; + case 'X': + /* + * Note that `-X' and `-x' are not standard "selector" + * options. For most selector-options, we check *all* + * processes to see if any are matched by the given + * value(s). After we have a set of all the matched + * processes, then `-X' and `-x' govern whether we + * modify that *matched* set for processes which do + * not have a controlling terminal. `-X' causes + * those processes to be deleted from the matched + * set, while `-x' causes them to be kept. + */ + xkeep = 0; + break; + case 'x': + xkeep = 1; + break; + case '?': + default: + usage(u03); + } + argc -= optind; + argv += optind; + +#ifdef __APPLE__ + /* 3862041 */ + if (!isatty(STDOUT_FILENO)) + termwidth = UNLIMITED; +#endif /* __APPLE__ */ + + /* + * If the user specified ps -e then they want a copy of the process + * environment kvm_getenvv(3) attempts to open /proc//mem. + * Check to make sure that procfs is mounted on /proc, otherwise + * print a warning informing the user that output will be incomplete. + */ +#ifndef __APPLE__ + if (needenv == 1 && check_procfs() == 0) + warnx("Process environment requires procfs(5)"); +#endif /* !__APPLE__ */ + /* + * If there arguments after processing all the options, attempt + * to treat them as a list of process ids. + */ + while (*argv) { + if (!isdigitch(**argv)) + break; + add_list(&pidlist, *argv); + argv++; + } + if (*argv) { + fprintf(stderr, "%s: illegal argument: %s\n", + getprogname(), *argv); + usage(u03); + } + if (optfatal) + exit(1); /* Error messages already printed. */ + if (xkeep < 0) /* Neither -X nor -x was specified. */ + xkeep = xkeep_implied; + +#if FIXME + kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + if (kd == 0) + errx(1, "%s", errbuf); +#endif /* FIXME */ + + if (!_fmt) { + if (u03 && uidlist.count != 0) { + parsefmt("uid", 0); + } + parsefmt(u03 ? p_dfmt : dfmt, 0); + } + + if (nselectors == 0) { + uidlist.l.ptr = malloc(sizeof(uid_t)); + if (uidlist.l.ptr == NULL) + errx(1, "malloc failed"); + nselectors = 1; + uidlist.count = uidlist.maxcount = 1; + *uidlist.l.uids = getuid(); + } + + /* + * scan requested variables, noting what structures are needed, + * and adjusting header widths as appropriate. + */ + scanvars(); + + /* + * Get process list. If the user requested just one selector- + * option, then kvm_getprocs can be asked to return just those + * processes. Otherwise, have it return all processes, and + * then this routine will search that full list and select the + * processes which match any of the user's selector-options. + */ + what = KERN_PROC_ALL; + flag = 0; + if (nselectors == 1) { + if (gidlist.count == 1) { +#if 0 + what = KERN_PROC_RGID | showthreads; + flag = *gidlist.l.gids; + nselectors = 0; +#endif /* 0 */ + } else if (pgrplist.count == 1) { + what = KERN_PROC_PGRP | showthreads; + flag = *pgrplist.l.pids; + nselectors = 0; + } else if (pidlist.count == 1) { + what = KERN_PROC_PID | showthreads; + flag = *pidlist.l.pids; + nselectors = 0; + } else if (ruidlist.count == 1) { + what = KERN_PROC_RUID | showthreads; + flag = *ruidlist.l.uids; + nselectors = 0; + } else if (sesslist.count == 1) { + what = KERN_PROC_SESSION | showthreads; + flag = *sesslist.l.pids; + nselectors = 0; + } else if (ttylist.count == 1) { + what = KERN_PROC_TTY | showthreads; + flag = *ttylist.l.ttys; + nselectors = 0; + } else if (uidlist.count == 1) { + what = (xkeep ? KERN_PROC_RUID : KERN_PROC_UID) | showthreads; + flag = *uidlist.l.uids; + nselectors = 0; + } + } + + /* + * select procs + */ + nentries = -1; +#if FIXME + kp = kvm_getprocs(kd, what, flag, &nentries); + if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0)) + errx(1, "%s", kvm_geterr(kd)); +#else /* FIXME */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = what; + mib[3] = flag; + + if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) { + perror("Failure calling sysctl"); + return 0; + } + + kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize); + + retry_count = 0; + orig_bufSize = bufSize; + for(retry_count=0; ; retry_count++) { + /* retry for transient errors due to load in the system */ + local_error = 0; + bufSize = orig_bufSize; + if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) { + if (retry_count < 1000) { + /* 1 sec back off */ + sleep(1); + continue; + } + perror("Failure calling sysctl"); + return 0; + } else if (local_error == 0) { + break; + } + /* 1 sec back off */ + sleep(1); + } + + /* This has to be after the second sysctl since the bufSize + may have changed. */ + nentries = bufSize / sizeof(struct kinfo_proc); +#endif /* FIXME */ + nkept = 0; + if (nentries > 0) { + if ((kinfo = calloc(nentries, sizeof(*kinfo))) == NULL) + errx(1, "malloc failed"); + for (i = nentries; --i >= 0; ++kp) { +#ifdef __APPLE__ + if (kp->kp_proc.p_pid == 0) { + continue; + } +#endif /* __APPLE__ */ + +#ifdef __APPLE__ + if (dflag && (kp->kp_proc.p_pid == kp->kp_eproc.e_pgid)) + continue; +#endif /* __APPLE__ */ + + /* + * If the user specified multiple selection-criteria, + * then keep any process matched by the inclusive OR + * of all the selection-criteria given. + */ + if (pidlist.count > 0) { + for (elem = 0; elem < pidlist.count; elem++) + if (kp->kp_proc.p_pid == pidlist.l.pids[elem]) + goto keepit; + } + /* + * Note that we had to process pidlist before + * filtering out processes which do not have + * a controlling terminal. + */ + if (xkeep == 0) { + if ((kp->kp_eproc.e_tdev == NODEV || + (kp->kp_proc.p_flag & P_CONTROLT) == 0)) + continue; + } + if (all || nselectors == 0) + goto keepit; + if (gidlist.count > 0) { + for (elem = 0; elem < gidlist.count; elem++) + if (kp->kp_eproc.e_pcred.p_rgid == gidlist.l.gids[elem]) + goto keepit; + } + if (pgrplist.count > 0) { + for (elem = 0; elem < pgrplist.count; elem++) + if (kp->kp_eproc.e_pgid == + pgrplist.l.pids[elem]) + goto keepit; + } + if (ruidlist.count > 0) { + for (elem = 0; elem < ruidlist.count; elem++) + if (kp->kp_eproc.e_pcred.p_ruid == + ruidlist.l.uids[elem]) + goto keepit; + } +#if 0 + if (sesslist.count > 0) { + for (elem = 0; elem < sesslist.count; elem++) + if (kp->ki_sid == sesslist.l.pids[elem]) + goto keepit; + } +#endif + if (ttylist.count > 0) { + for (elem = 0; elem < ttylist.count; elem++) + if (kp->kp_eproc.e_tdev == ttylist.l.ttys[elem]) + goto keepit; + } + if (uidlist.count > 0) { + for (elem = 0; elem < uidlist.count; elem++) + if (kp->kp_eproc.e_ucred.cr_uid == uidlist.l.uids[elem]) + goto keepit; + } + /* + * This process did not match any of the user's + * selector-options, so skip the process. + */ + continue; + + keepit: + next_KINFO = &kinfo[nkept]; + next_KINFO->ki_p = kp; + get_task_info(next_KINFO); +#ifndef __APPLE__ + next_KINFO->ki_pcpu = getpcpu(next_KINFO); + if (sortby == SORTMEM) + next_KINFO->ki_memsize = kp->ki_tsize + + kp->ki_dsize + kp->ki_ssize; +#endif /* !__APPLE__ */ + if (needuser) + saveuser(next_KINFO); + dynsizevars(next_KINFO); + nkept++; + } + } + + sizevars(); + + /* + * print header + */ + printheader(); + if (nkept == 0) + exit(1); + + /* + * sort proc list + */ + qsort(kinfo, nkept, sizeof(KINFO), pscomp); + /* + * For each process, call each variable output function. + */ + for (i = lineno = 0; i < nkept; i++) { + if(mflg) { + print_all_thread = 1; + for(j=0; j < kinfo[i].thread_count; j++) { + print_thread_num = j; + STAILQ_FOREACH(vent, &varlist, next_ve) { + (vent->var->oproc)(&kinfo[i], vent); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + + (void)putchar('\n'); + if (prtheader && lineno++ == prtheader - 4) { + (void)putchar('\n'); + printheader(); + lineno = 0; + } + } + print_all_thread = 0; + } else { + STAILQ_FOREACH(vent, &varlist, next_ve) { + (vent->var->oproc)(&kinfo[i], vent); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + + (void)putchar('\n'); + if (prtheader && lineno++ == prtheader - 4) { + (void)putchar('\n'); + printheader(); + lineno = 0; + } + } + } + for (i = 0; i < nkept; i++) { + if (kinfo[i].invalid_tinfo == 0 && kinfo[i].thread_count) + free(kinfo[i].thval); + } + free(kprocbuf); + free(kinfo); + free_list(&gidlist); + free_list(&pidlist); + free_list(&pgrplist); + free_list(&ruidlist); + free_list(&sesslist); + free_list(&ttylist); + free_list(&uidlist); + + exit(eval); +} + +static int +addelem_gid(struct listinfo *inf, const char *elem) +{ + struct group *grp; + const char *nameorID; + char *endp; + u_long bigtemp; + + if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { + if (*elem == '\0') + warnx("Invalid (zero-length) %s name", inf->lname); + else + warnx("%s name too long: %s", inf->lname, elem); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + /* + * SUSv3 states that `ps -G grouplist' should match "real-group + * ID numbers", and does not mention group-names. I do want to + * also support group-names, so this tries for a group-id first, + * and only tries for a name if that doesn't work. This is the + * opposite order of what is done in addelem_uid(), but in + * practice the order would only matter for group-names which + * are all-numeric. + */ + grp = NULL; + nameorID = "named"; + errno = 0; + bigtemp = strtoul(elem, &endp, 10); + if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) { + nameorID = "name or ID matches"; + grp = getgrgid((gid_t)bigtemp); + } + if (grp == NULL) + grp = getgrnam(elem); + if (grp == NULL) { + warnx("No %s %s '%s'", inf->lname, nameorID, elem); + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.gids[(inf->count)++] = grp->gr_gid; + return (1); +} + +#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */ +static int +addelem_pid(struct listinfo *inf, const char *elem) +{ + char *endp; + long tempid; + + if (*elem == '\0') { + warnx("Invalid (zero-length) process id"); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + errno = 0; + tempid = strtol(elem, &endp, 10); + if (*endp != '\0' || tempid < 0 || elem == endp) { + warnx("Invalid %s: %s", inf->lname, elem); + errno = ERANGE; + } else if (errno != 0 || tempid > BSD_PID_MAX) { + warnx("%s too large: %s", inf->lname, elem); + errno = ERANGE; + } + if (errno == ERANGE) { + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.pids[(inf->count)++] = tempid; + return (1); +} +#undef BSD_PID_MAX + +/*- + * The user can specify a device via one of three formats: + * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console + * 2) missing "/dev", e.g.: ttyp0 console + * 3) two-letters, e.g.: p0 co + * (matching letters that would be seen in the "TT" column) + */ +static int +addelem_tty(struct listinfo *inf, const char *elem) +{ + const char *ttypath; + struct stat sb; + char pathbuf[PATH_MAX], pathbuf2[PATH_MAX]; + + ttypath = NULL; + pathbuf2[0] = '\0'; + switch (*elem) { + case '/': + ttypath = elem; + break; + case 'c': + if (strcmp(elem, "co") == 0) { + ttypath = _PATH_CONSOLE; + break; + } + /* FALLTHROUGH */ + default: + strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf)); + strlcat(pathbuf, elem, sizeof(pathbuf)); + ttypath = pathbuf; + if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0) + break; + if (strcmp(pathbuf, _PATH_CONSOLE) == 0) + break; + /* Check to see if /dev/tty${elem} exists */ + strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2)); + strlcat(pathbuf2, elem, sizeof(pathbuf2)); + if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) { + /* No need to repeat stat() && S_ISCHR() checks */ + ttypath = NULL; + break; + } + break; + } + if (ttypath) { +#ifdef __APPLE__ + if (access(ttypath, F_OK) == -1 || stat(ttypath, &sb) == -1) { +#else + if (stat(ttypath, &sb) == -1) { +#endif + if (pathbuf2[0] != '\0') + warn("%s and %s", pathbuf2, ttypath); + else + warn("%s", ttypath); + optfatal = 1; + return (0); + } + if (!S_ISCHR(sb.st_mode)) { + if (pathbuf2[0] != '\0') + warnx("%s and %s: Not a terminal", pathbuf2, + ttypath); + else + warnx("%s: Not a terminal", ttypath); + optfatal = 1; + return (0); + } + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.ttys[(inf->count)++] = sb.st_rdev; + return (1); +} + +static int +addelem_uid(struct listinfo *inf, const char *elem) +{ + struct passwd *pwd; + char *endp; + u_long bigtemp; + + if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { + if (*elem == '\0') + warnx("Invalid (zero-length) %s name", inf->lname); + else + warnx("%s name too long: %s", inf->lname, elem); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + pwd = getpwnam(elem); + if (pwd == NULL) { + errno = 0; + bigtemp = strtoul(elem, &endp, 10); + if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX) + warnx("No %s named '%s'", inf->lname, elem); + else { + /* The string is all digits, so it might be a userID. */ + pwd = getpwuid((uid_t)bigtemp); + if (pwd == NULL) + warnx("No %s name or ID matches '%s'", + inf->lname, elem); + } + } + if (pwd == NULL) { + /* + * These used to be treated as minor warnings (and the + * option was simply ignored), but now they are fatal + * errors (and the command will be aborted). + */ + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.uids[(inf->count)++] = pwd->pw_uid; + return (1); +} + +static void +add_list(struct listinfo *inf, const char *argp) +{ + const char *savep; + char *cp, *endp; + int toolong; + char elemcopy[PATH_MAX]; + + if (*argp == 0) + inf->addelem(inf, elemcopy); + while (*argp != '\0') { + while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) + argp++; + savep = argp; + toolong = 0; + cp = elemcopy; + if (strchr(T_SEP, *argp) == NULL) { + endp = elemcopy + sizeof(elemcopy) - 1; + while (*argp != '\0' && cp <= endp && + strchr(W_SEP T_SEP, *argp) == NULL) + *cp++ = *argp++; + if (cp > endp) + toolong = 1; + } + if (!toolong) { + *cp = '\0'; + /* + * Add this single element to the given list. + */ + inf->addelem(inf, elemcopy); + } else { + /* + * The string is too long to copy. Find the end + * of the string to print out the warning message. + */ + while (*argp != '\0' && strchr(W_SEP T_SEP, + *argp) == NULL) + argp++; + warnx("Value too long: %.*s", (int)(argp - savep), + savep); + optfatal = 1; + } + /* + * Skip over any number of trailing whitespace characters, + * but only one (at most) trailing element-terminating + * character. + */ + while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) + argp++; + if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) { + argp++; +#if 0 + /* Catch case where string ended with a comma. */ + if (*argp == '\0') + inf->addelem(inf, argp); +#endif /* 0 */ + } + } +} + +static void * +expand_list(struct listinfo *inf) +{ + void *newlist; + int newmax; + + newmax = (inf->maxcount + 1) << 1; + newlist = realloc(inf->l.ptr, newmax * inf->elemsize); + if (newlist == NULL) { + free(inf->l.ptr); + errx(1, "realloc to %d %ss failed", newmax, inf->lname); + } + inf->maxcount = newmax; + inf->l.ptr = newlist; + + return (newlist); +} + +static void +free_list(struct listinfo *inf) +{ + + inf->count = inf->elemsize = inf->maxcount = 0; + if (inf->l.ptr != NULL) + free(inf->l.ptr); + inf->addelem = NULL; + inf->lname = NULL; + inf->l.ptr = NULL; +} + +static void +init_list(struct listinfo *inf, addelem_rtn artn, int elemsize, + const char *lname) +{ + + inf->count = inf->maxcount = 0; + inf->elemsize = elemsize; + inf->addelem = artn; + inf->lname = lname; + inf->l.ptr = NULL; +} + +VARENT * +find_varentry(VAR *v) +{ + struct varent *vent; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + if (strcmp(vent->var->name, v->name) == 0) + return vent; + } + return NULL; +} + +static void +scanvars(void) +{ + struct varent *vent; + VAR *v; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (v->flag & DSIZ) { + v->dwidth = v->width; + v->width = 0; + } + if (v->flag & USER) + needuser = 1; + if (v->flag & COMM) + needcomm = 1; + } +} + +static void +dynsizevars(KINFO *ki) +{ + struct varent *vent; + VAR *v; + int i; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (!(v->flag & DSIZ)) + continue; + i = (v->sproc)( ki); + if (v->width < i) + v->width = i; + if (v->width > v->dwidth) + v->width = v->dwidth; + } +} + +static void +sizevars(void) +{ + struct varent *vent; + VAR *v; + int i; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + i = strlen(vent->header); + if (v->width < i) + v->width = i; + totwidth += v->width + 1; /* +1 for space */ + } + totwidth--; +} + +#ifndef __APPLE__ +static const char * +fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, + char *comm, int maxlen) +{ + const char *s; + + s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); + return (s); +} +#endif /* !__APPLE__ */ + +#define UREADOK(ki) (forceuread || (KI_PROC(ki)->p_flag & P_INMEM)) + +static void +saveuser(KINFO *ki) +{ + struct usave *usp; +#if FIXME + struct user *u_addr = (struct user *)USRSTACK; +#endif /* FIXME */ + + usp = &ki->ki_u; +#if FIXME + if (UREADOK(ki) && kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats, + (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) + { + /* + * The u-area might be swapped out, and we can't get + * at it because we have a crashdump and no swap. + * If it's here fill in these fields, otherwise, just + * leave them 0. + */ + usp->u_start = pstats.p_start; + usp->u_ru = pstats.p_ru; + usp->u_cru = pstats.p_cru; + usp->u_valid = 1; + } else + usp->u_valid = 0; +#else /* FIXME */ + usp->u_valid = 0; +#endif /* FIXME */ + /* + * save arguments if needed + */ +#if FIXME + if (needcomm && UREADOK(ki)) { + ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm, + MAXCOMLEN); + } else if (needcomm) { + ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3); + sprintf(ki->ki_args, "(%s)", KI_PROC(ki)->p_comm); + } else { + ki->ki_args = NULL; + } +#else /* FIXME */ + ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3); + sprintf(ki->ki_args, "%s", KI_PROC(ki)->p_comm); + //ki->ki_args = malloc(10); + //strcpy(ki->ki_args, "()"); +#endif /* FIXME */ +#if FIXME + if (needenv && UREADOK(ki)) { + ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0); + } else if (needenv) { + ki->ki_env = malloc(3); + strcpy(ki->ki_env, "()"); + } else { + ki->ki_env = NULL; + } +#else /* FIXME */ + ki->ki_env = malloc(10); + strcpy(ki->ki_env, ""); +#endif /* FIXME */ +} + +static int +pscomp(const void *a, const void *b) +{ + int i; +#if FIXME +#define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \ + KI_EPROC(k)->e_vm.vm_tsize) +#else /* FIXME */ +#define VSIZE(k) ((k)->tasks_info.resident_size) + +#endif /* FIXME */ + + if (sortby == SORTCPU) + return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a)); + if (sortby == SORTMEM) + return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a)); + i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev; + if (i == 0) + i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid; + return (i); +} + +/* + * 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 users + * 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(const char *optlist, char *origval, const char *nextarg, int *u03) +{ + size_t len; + char *argp, *cp, *newopts, *ns, *optp, *pidp; + + /* + * See if the original value includes any option which takes an + * argument (and will thus use up the remainder of the string). + */ + argp = NULL; + if (optlist != NULL) { + for (cp = origval; *cp != '\0'; cp++) { + optp = strchr(optlist, *cp); + if ((optp != NULL) && *(optp + 1) == ':') { + argp = cp; + break; + } + } + } + if (argp != NULL && *origval == '-') + return (origval); + + /* + * if last letter is a 't' flag with no argument (in the context + * of the oldps options -- option string NOT starting with a '-' -- + * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). + * + * However, if a flag accepting a string argument is found earlier + * in the option string (including a possible `t' flag), then the + * remainder of the string must be the argument to that flag; so + * do not modify that argument. Note that a trailing `t' would + * cause argp to be set, if argp was not already set by some + * earlier option. + */ + len = strlen(origval); + cp = origval + len - 1; + pidp = NULL; + if (*cp == 't' && *origval != '-' && cp == argp) { + if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg)) + *cp = 'T'; + } else if (argp == NULL) { + /* + * The original value did not include any option which takes + * an argument (and that would include `p' and `t'), so check + * the value for trailing number, or comma-separated list of + * numbers, which we will treat as a pid request. + */ + if (isdigitch(*cp)) { + while (cp >= origval && (*cp == ',' || isdigitch(*cp))) + --cp; + pidp = cp + 1; + } + } + + /* + * If nothing needs to be added to the string, then return + * the "original" (although possibly modified) value. + */ + if (*origval == '-' && pidp == NULL) + return (origval); + + /* + * Create a copy of the string to add '-' and/or 'p' to the + * original value. + */ + if ((newopts = ns = malloc(len + 3)) == NULL) + errx(1, "malloc failed"); + + if (*origval != '-') { + *ns++ = '-'; /* add option flag */ + *u03 = 0; + } + + if (pidp == NULL) + strcpy(ns, origval); + else { + /* + * Copy everything before the pid string, add the `p', + * and then copy the pid string. + */ + len = pidp - origval; + memcpy(ns, origval, len); + ns += len; + *ns++ = 'p'; + strcpy(ns, pidp); + } + + return (newopts); +} + +#ifndef __APPLE__ +static int +check_procfs(void) +{ + struct statfs mnt; + + if (statfs("/proc", &mnt) < 0) + return (0); + if (strcmp(mnt.f_fstypename, "procfs") != 0) + return (0); + return (1); +} +#endif /* !__APPLE__ */ + +static void +usage(int u03) +{ +#define SINGLE_OPTS "[-AaCcEefhjlMmrSTvwXx]" + + (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", + "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]", + (u03 ? " [-g grp[,grp...]] [-u [uid,uid...]]" : " [-u]"), + " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]", + " ps [-L]"); + exit(1); +} diff --git a/adv_cmds/ps/ps.h b/adv_cmds/ps/ps.h new file mode 100644 index 0000000..a077eff --- /dev/null +++ b/adv_cmds/ps/ps.h @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1990, 1993 + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: ps.h,v 1.6 1998/09/14 08:32:20 dfr Exp $ + */ + +#include + +#include +#include +#include +#include +#include + +#define UNLIMITED 0 /* unlimited terminal width */ +enum type { CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK }; + +struct usave { + struct timeval u_start; + struct rusage u_ru; + struct rusage u_cru; + char u_acflag; + char u_valid; +}; + +#define KI_PROC(ki) (&(ki)->ki_p->kp_proc) +#define KI_EPROC(ki) (&(ki)->ki_p->kp_eproc) + +typedef struct thread_values { + struct thread_basic_info tb; + /* struct policy_infos schedinfo; */ + union { + struct policy_timeshare_info tshare; + struct policy_rr_info rr; + struct policy_fifo_info fifo; + } schedinfo; +} thread_values_t; + +typedef struct kinfo { + struct kinfo_proc *ki_p; /* kinfo_proc structure */ + struct usave ki_u; /* interesting parts of user */ + char *ki_args; /* exec args */ + char *ki_env; /* environment */ + task_port_t task; + int state; + int cpu_usage; + int curpri; + int basepri; + int swapped; + struct task_basic_info tasks_info; + struct task_thread_times_info times; + /* struct policy_infos schedinfo; */ + union { + struct policy_timeshare_info tshare; + struct policy_rr_info rr; + struct policy_fifo_info fifo; + } schedinfo; + int invalid_tinfo; + unsigned int thread_count; + thread_port_array_t thread_list; + thread_values_t *thval; + int invalid_thinfo; +} KINFO; + +/* Variables. */ +typedef struct varent { + STAILQ_ENTRY(varent) next_ve; + const char *header; + struct var *var; +} VARENT; + +typedef struct var { + const char *name; /* name(s) of variable */ + const char *header; /* default header */ + const char *alias; /* aliases */ +#define COMM 0x01 /* needs exec arguments and environment (XXX) */ +#define LJUST 0x02 /* left adjust on output (trailing blanks) */ +#define USER 0x04 /* needs user structure */ +#define DSIZ 0x08 /* field size is dynamic*/ +#define INF127 0x10 /* values >127 displayed as 127 */ + u_int flag; + /* output routine */ + void (*oproc)(struct kinfo *, struct varent *); + /* sizing routine*/ + int (*sproc)(struct kinfo *); + short width; /* printing width */ + /* + * The following (optional) elements are hooks for passing information + * to the generic output routine pvar (which prints simple elements + * from the well known kinfo_proc structure). + */ + size_t off; /* offset in structure */ + enum type type; /* type of element */ + const char *fmt; /* printf format */ + short dwidth; /* dynamic printing width */ + /* + * glue to link selected fields together + */ +} VAR; + +#include "extern.h" diff --git a/adv_cmds/ps/tasks.c b/adv_cmds/ps/tasks.c new file mode 100644 index 0000000..4548b56 --- /dev/null +++ b/adv_cmds/ps/tasks.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps.h" +#include + +extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target); + +#define STATE_MAX 7 + +int +mach_state_order(s, sleep_time) +int s; +long sleep_time; +{ +switch (s) { +case TH_STATE_RUNNING: return(1); +case TH_STATE_UNINTERRUPTIBLE: + return(2); + case TH_STATE_WAITING: return((sleep_time > 20) ? 4 : 3); + case TH_STATE_STOPPED: return(5); + case TH_STATE_HALTED: return(6); + default: return(7); + } +} + /*01234567 */ +char mach_state_table[] = " RUSITH?"; + + +int +thread_schedinfo( + KINFO *ki, + thread_port_t thread, + policy_t pol, + void * buf) +{ + unsigned int count; + int ret = KERN_FAILURE; + + switch (pol) { + + case POLICY_TIMESHARE: + count = POLICY_TIMESHARE_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO, + (thread_info_t)buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority))) + ki->curpri = ((struct policy_timeshare_info *)buf)->cur_priority; + break; + + case POLICY_FIFO: + count = POLICY_FIFO_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_FIFO_INFO, + buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority))) + ki->curpri = ((struct policy_fifo_info *)buf)->base_priority; + break; + + case POLICY_RR: + count = POLICY_RR_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_RR_INFO, + buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority))) + ki->curpri = ((struct policy_rr_info *)buf)->base_priority; + break; + } + return(ret); +} + +int get_task_info (KINFO *ki) +{ + kern_return_t error; + unsigned int info_count = TASK_BASIC_INFO_COUNT; + unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT; + pid_t pid; + int j, err = 0; + + ki->state = STATE_MAX; + + pid = KI_PROC(ki)->p_pid; + if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) { + return(1); + } + info_count = TASK_BASIC_INFO_COUNT; + error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t)&ki->tasks_info, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + { + vm_region_basic_info_data_64_t b_info; + vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; + vm_size_t size; + mach_port_t object_name; + + /* + * try to determine if this task has the split libraries + * mapped in... if so, adjust its virtual size down by + * the 2 segments that are used for split libraries + */ + info_count = VM_REGION_BASIC_INFO_COUNT_64; + error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&b_info, &info_count, &object_name); + if (error == KERN_SUCCESS) { + if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && + ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) + ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); + } + } + info_count = TASK_THREAD_TIMES_INFO_COUNT; + error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t)&ki->times, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + switch(ki->tasks_info.policy) { + case POLICY_TIMESHARE : + info_count = POLICY_TIMESHARE_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t)&ki->schedinfo.tshare, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.tshare.cur_priority; + ki->basepri = ki->schedinfo.tshare.base_priority; + break; + case POLICY_RR : + info_count = POLICY_RR_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t)&ki->schedinfo.rr, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.rr.base_priority; + ki->basepri = ki->schedinfo.rr.base_priority; + break; + + case POLICY_FIFO : + info_count = POLICY_FIFO_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t)&ki->schedinfo.fifo, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.fifo.base_priority; + ki->basepri = ki->schedinfo.fifo.base_priority; + break; + } + + ki->invalid_tinfo=0; + + ki->cpu_usage=0; + error = task_threads(ki->task, &ki->thread_list, &ki->thread_count); + if (error != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(),ki->task); +#ifdef DEBUG + mach_error("Call to task_threads() failed", error); +#endif + return(1); + } + err=0; + //ki->curpri = 255; + //ki->basepri = 255; + ki->swapped = 1; + ki->thval = calloc(ki->thread_count, sizeof(struct thread_values)); + for (j = 0; j < ki->thread_count; j++) { + int tstate; + thread_info_count = THREAD_BASIC_INFO_COUNT; + error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO, + (thread_info_t)&ki->thval[j].tb, + &thread_info_count); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Call to thread_info() failed", error); +#endif + err=1; + } else { + ki->cpu_usage += ki->thval[j].tb.cpu_usage; + } + error = thread_schedinfo(ki, ki->thread_list[j], + ki->thval[j].tb.policy, &ki->thval[j].schedinfo); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Call to thread_schedinfo() failed", error); +#endif + err=1; + } + tstate = mach_state_order(ki->thval[j].tb.run_state, + ki->thval[j].tb.sleep_time); + if (tstate < ki->state) + ki->state = tstate; + if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0) + ki->swapped = 0; + mach_port_deallocate(mach_task_self(), + ki->thread_list[j]); + } + ki->invalid_thinfo = err; + /* Deallocate the list of threads. */ + error = vm_deallocate(mach_task_self(), + (vm_address_t)(ki->thread_list), + sizeof(*ki->thread_list) * ki->thread_count); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Trouble freeing thread_list", error); +#endif + } + + mach_port_deallocate(mach_task_self(),ki->task); + return(0); +} -- cgit v1.2.3-56-ge451