Index: usr.bin/procstat/procstat.h =================================================================== --- usr.bin/procstat/procstat.h +++ usr.bin/procstat/procstat.h @@ -35,23 +35,34 @@ #define PROCSTAT_XO_VERSION "1" -extern int hflag, nflag, Cflag, Hflag; +enum { + PS_OPT_CAPABILITIES = 0x01, + PS_OPT_NOHEADER = 0x02, + PS_OPT_PERTHREAD = 0x04, + PS_OPT_SIGNUM = 0x08, + PS_OPT_VERBOSE = 0x10 +}; +#define PS_SUBCOMMAND_OPTS \ + (PS_OPT_CAPABILITIES | PS_OPT_SIGNUM | \ + PS_OPT_PERTHREAD | PS_OPT_VERBOSE) + +extern int procstat_opts; + struct kinfo_proc; void kinfo_proc_sort(struct kinfo_proc *kipp, int count); const char * kinfo_proc_thread_name(const struct kinfo_proc *kipp); void procstat_args(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_auxv(struct procstat *prstat, struct kinfo_proc *kipp); -void procstat_basic(struct kinfo_proc *kipp); +void procstat_basic(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_bin(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_cred(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_cs(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_env(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_files(struct procstat *prstat, struct kinfo_proc *kipp); -void procstat_kstack(struct procstat *prstat, struct kinfo_proc *kipp, - int kflag); -void procstat_ptlwpinfo(struct procstat *prstat); +void procstat_kstack(struct procstat *prstat, struct kinfo_proc *kipp); +void procstat_ptlwpinfo(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_rlimit(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_rusage(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_sigs(struct procstat *prstat, struct kinfo_proc *kipp); Index: usr.bin/procstat/procstat.1 =================================================================== --- usr.bin/procstat/procstat.1 +++ usr.bin/procstat/procstat.1 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 26, 2017 +.Dd May 31, 2017 .Dt PROCSTAT 1 .Os .Sh NAME @@ -34,12 +34,36 @@ .Sh SYNOPSIS .Nm .Op Fl -libxo +.Op Fl h +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar interval +.Ar command +.Op Ar pid | Ar core ... +.Nm +.Op Fl -libxo +.Fl a +.Op Fl h +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar interval +.Ar command +.Nm +.Op Fl -libxo .Op Fl CHhn .Op Fl M Ar core .Op Fl N Ar system .Op Fl w Ar interval .Op Fl b | c | e | f | i | j | k | l | L | r | s | S | t | v | x -.Op Fl a | Ar pid | Ar core ... +.Op Ar pid | Ar core ... +.Nm +.Op Fl -libxo +.Fl a +.Op Fl CHhn +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar interval +.Op Fl b | c | e | f | i | j | k | l | L | r | s | S | t | v | x .Sh DESCRIPTION The .Nm @@ -51,49 +75,88 @@ It can also display information extracted from a process core file, if the core file is specified as the argument. .Pp -By default, basic process statistics are printed; one of the following -options may be specified in order to select more detailed process information -for printing: -.Bl -tag -width indent -.It Fl -libxo -Generate output via +If the +.Fl -libxo +flag is specified the output is generated via .Xr libxo 3 in a selection of different human and machine readable formats. See .Xr xo_parse_args 3 for details on command line arguments. -.It Fl b +.Pp +The following commands are available: +.Bl -tag -width indent +.It Ar basic +Print basic process statistics (this is the default). +.It Ar binary | Fl b Display binary information for the process. -.It Fl c +.Pp +Substring commands are accepted. +.It Ar argument[s] | Fl c Display command line arguments for the process. -.It Fl e +.Pp +Substring commands are accepted. +.It Ar environment | Fl e Display environment variables for the process. -.It Fl f +.Pp +Substring commands are accepted. +.It Ar file[s] | Ar fd[s] | Fl f Display file descriptor information for the process. -.It Fl i +.Pp +If the +.Fl C +sub-command flag is used then additional capability information is printed. +.It Ar signal[s] | Fl i Display signal pending and disposition information for the process. -.It Fl j +.Pp +If the +.Fl n +sub-command option is used, the signal numbers are shown instead of signal +names. +.Pp +Substring commands are accepted. +.It Ar tsignal[s] | Fl j Display signal pending and blocked information for the process's threads. -.It Fl k +.Pp +If the +.Fl n +sub-command option is used, the signal numbers are shown instead of signal +names. +.Pp +Substring commands are accepted. +.It Ar kstack | Fl k Display the stacks of kernel threads in the process, excluding stacks of threads currently running on a CPU and threads with stacks swapped to disk. -If the flag is repeated, function offsets as well as function names are -printed. -.It Fl l +.Pp +If the +.Fl v +sub-command option is used (or the command flag is repeated), function +offsets as well as function names are printed. +.It Ar rlimit | Fl l Display resource limits for the process. -.It Fl L +.It Ar ptlwpinfo | Fl L Display LWP info for the process pertaining to its signal driven exit. -.It Fl r +.It Ar rusage | Fl r Display resource usage information for the process. -.It Fl s +.Pp +If the +.Fl v +.Pq or Fl H +sub-command flag +is used then per-thread statistics are printed, rather +than per-process statistics. The second field in the table will +list the thread ID to which the row of information corresponds. +.It Ar credential[s] | Fl s Display security credential information for the process. -.It Fl S +.Pp +Substring commands are accepted. +.It Ar cpuset | Ar cs | Fl S Display the cpuset information for the thread. -.It Fl t +.It Ar thread[s] | Fl t Display thread information for the process. -.It Fl v +.It Ar vm | Fl v Display virtual memory mappings for the process. -.It Fl x +.It Ar auxv | Fl x Display ELF auxiliary vector for the process. .El .Pp @@ -110,23 +173,6 @@ If the .Fl w flag is not specified, the output will not repeat. -.Pp -The -.Fl C -flag requests the printing of additional capability information in the file -descriptor view. -.Pp -The -.Fl H -flag may be used to request per-thread statistics rather than per-process -statistics for some options. -For those options, the second field in the table will list the thread ID -to which the row of information corresponds. -The -.Fl H -flag is implied for the -.Fl S -mode. .Pp Information for VM, file descriptor, and cpuset options is available only to the owner of a process or the superuser. Index: usr.bin/procstat/procstat.c =================================================================== --- usr.bin/procstat/procstat.c +++ usr.bin/procstat/procstat.c @@ -42,26 +42,110 @@ #include "procstat.h" -static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag; -static int lflag, Lflag, rflag, sflag, tflag, vflag, xflag, Sflag; -int hflag, nflag, Cflag, Hflag; +enum { + PS_CMP_NORMAL = 0x00, + PS_CMP_PLURAL = 0x01, + PS_CMP_SUBSTR = 0x02 +}; +struct procstat_cmd { + const char *command; + const char *xocontainer; + const char *usage; + void (*cmd)(struct procstat *, struct kinfo_proc *); + void (*opt)(int, char **); + int cmp; +}; + +int procstat_opts = 0; + +static void cmdopt_none(int argc, char *argv[]); +static void cmdopt_verbose(int argc, char *argv[]); +static void cmdopt_signals(int argc, char *argv[]); +static void cmdopt_rusage(int argc, char *argv[]); +static void cmdopt_files(int argc, char *argv[]); +static void cmdopt_cpuset(int argc, char *argv[]); + +static const struct procstat_cmd cmd_table[] = { + { "argument", "arguments", NULL, &procstat_args, &cmdopt_none, + PS_CMP_PLURAL | PS_CMP_SUBSTR }, + { "auxv", "auxv", NULL, &procstat_auxv, &cmdopt_none, PS_CMP_NORMAL }, + { "basic", "basic", NULL, &procstat_basic, &cmdopt_none, + PS_CMP_NORMAL }, + { "binary", "binary", NULL, &procstat_bin, &cmdopt_none, + PS_CMP_SUBSTR }, + { "cpuset", "cs", NULL, &procstat_cs, &cmdopt_cpuset, PS_CMP_NORMAL }, + { "credential", "credentials", NULL, &procstat_cred, &cmdopt_none, + PS_CMP_PLURAL | PS_CMP_SUBSTR }, + { "cs", "cs", NULL, &procstat_cs, &cmdopt_cpuset, PS_CMP_NORMAL }, + { "environment", "environment", NULL, &procstat_env, &cmdopt_none, + PS_CMP_SUBSTR }, + { "fd", "files", "[-C]", &procstat_files, &cmdopt_files, + PS_CMP_PLURAL }, + { "file", "files", "[-C]", &procstat_files, &cmdopt_files, + PS_CMP_PLURAL }, + { "kstack", "kstack", "[-v]", &procstat_kstack, &cmdopt_verbose, + PS_CMP_NORMAL }, + { "ptlwpinfo", "ptlwpinfo", NULL, &procstat_ptlwpinfo, &cmdopt_none, + PS_CMP_NORMAL }, + { "rlimit", "rlimit", NULL, &procstat_rlimit, &cmdopt_none, + PS_CMP_NORMAL }, + { "rusage", "rusage", "[-Ht]", &procstat_rusage, &cmdopt_rusage, + PS_CMP_NORMAL }, + { "signal", "signals", "[-n]", &procstat_sigs, &cmdopt_signals, + PS_CMP_PLURAL | PS_CMP_SUBSTR }, + { "thread", "threads", NULL, &procstat_threads, &cmdopt_none, + PS_CMP_PLURAL }, + { "tsignal", "thread_signals", "[-n]", &procstat_threads_sigs, + &cmdopt_signals, PS_CMP_PLURAL | PS_CMP_SUBSTR }, + { "vm", "vm", NULL, &procstat_vm, &cmdopt_none, PS_CMP_NORMAL } +}; + static void usage(void) { + size_t i; + size_t l; + int multi; - xo_error("usage: procstat [--libxo] [-CHhn] [-M core] " - "[-N system] [-w interval]\n" - " [-b | -c | -e | -f | -i | -j | -k | " - "-l | -L | -r | -s | \n" + xo_error("usage: procstat [--libxo] [-h] [-M core] [-N system]" + " [-w interval]\n" + " command [pid | core ...]\n" + " procstat [--libxo] -a [-h] [-M core] [-N system] " + " [-w interval]\n" + " command\n" + " procstat [--libxo] [-CHhn] [-M core]" + " [-N system] [-w interval]\n" + " [-b | -c | -e | -f | -i | -j | -k |" + " -l | -L | -r | -s |\n" + " -S | -t | -v | -x] [pid | core ...]\n" + " procstat [--libxo] -a [-CHhn] [-M core]" + " [-N system] [-w interval]\n" + " [-b | -c | -e | -f | -i | -j | -k |" + " -l | -L | -r | -s |\n" " -S | -t | -v | -x]\n" - " [-a | pid | core ...]\n"); + "Available commands:\n"); + for (i = 0, l = nitems(cmd_table); i < l; i++) { + multi = i + 1 < l && cmd_table[i].cmd == cmd_table[i + 1].cmd; + xo_error(" %s%s%s", multi ? "[" : "", cmd_table[i].command, + (cmd_table[i].cmp & PS_CMP_PLURAL) ? "[s]" : ""); + for (; i + 1 < l && cmd_table[i].cmd == cmd_table[i + 1].cmd; + i++) + xo_error(" | %s%s", cmd_table[i + 1].command, + (cmd_table[i].cmp & PS_CMP_PLURAL) ? "[s]" : ""); + if (multi) + xo_error("]"); + if (cmd_table[i].usage != NULL) + xo_error(" %s", cmd_table[i].usage); + xo_error("\n"); + } xo_finish(); exit(EX_USAGE); } static void -procstat(struct procstat *prstat, struct kinfo_proc *kipp) +procstat(const struct procstat_cmd *cmd, struct procstat *prstat, + struct kinfo_proc *kipp) { char *pidstr = NULL; @@ -69,40 +153,7 @@ if (pidstr == NULL) xo_errc(1, ENOMEM, "Failed to allocate memory in procstat()"); xo_open_container(pidstr); - - if (bflag) - procstat_bin(prstat, kipp); - else if (cflag) - procstat_args(prstat, kipp); - else if (eflag) - procstat_env(prstat, kipp); - else if (fflag) - procstat_files(prstat, kipp); - else if (iflag) - procstat_sigs(prstat, kipp); - else if (jflag) - procstat_threads_sigs(prstat, kipp); - else if (kflag) - procstat_kstack(prstat, kipp, kflag); - else if (lflag) - procstat_rlimit(prstat, kipp); - else if (Lflag) - procstat_ptlwpinfo(prstat); - else if (rflag) - procstat_rusage(prstat, kipp); - else if (sflag) - procstat_cred(prstat, kipp); - else if (tflag) - procstat_threads(prstat, kipp); - else if (vflag) - procstat_vm(prstat, kipp); - else if (xflag) - procstat_auxv(prstat, kipp); - else if (Sflag) - procstat_cs(prstat, kipp); - else - procstat_basic(kipp); - + cmd->cmd(prstat, kipp); xo_close_container(pidstr); free(pidstr); } @@ -146,122 +197,160 @@ return (name); } +static const struct procstat_cmd * +getcmd(const char *str) +{ + const struct procstat_cmd *cmd; + size_t i; + size_t l; + int cmp; + int s; + + if (str == NULL) + return (NULL); + cmd = NULL; + if ((l = strlen(str)) == 0) + return (getcmd("basic")); + s = l > 1 && strcasecmp(str + l - 1, "s") == 0; + for (i = 0; i < nitems(cmd_table); i++) { + /* + * After the first match substring matches are disabled, + * allowing subsequent full matches to take precedence. + */ + if (cmd == NULL && (cmd_table[i].cmp & PS_CMP_SUBSTR)) + cmp = strncasecmp(str, cmd_table[i].command, l - + ((cmd_table[i].cmp & PS_CMP_PLURAL) && s ? 1 : 0)); + else if ((cmd_table[i].cmp & PS_CMP_PLURAL) && s && + l == strlen(cmd_table[i].command) + 1) + cmp = strncasecmp(str, cmd_table[i].command, l - 1); + else + cmp = strcasecmp(str, cmd_table[i].command); + if (cmp == 0) + cmd = &cmd_table[i]; + } + return (cmd); +} + int main(int argc, char *argv[]) { - int ch, interval, tmp; + int ch, interval; int i; struct kinfo_proc *p; + const struct procstat_cmd *cmd; struct procstat *prstat, *cprstat; long l; pid_t pid; char *dummy; char *nlistf, *memf; - const char *xocontainer; + int aflag; int cnt; interval = 0; + cmd = NULL; memf = nlistf = NULL; + aflag = 0; argc = xo_parse_args(argc, argv); - xocontainer = "basic"; while ((ch = getopt(argc, argv, "abCcefHhijkLlM:N:nrSstvw:x")) != -1) { switch (ch) { - case 'C': - Cflag++; - break; - - case 'H': - Hflag++; - break; - - case 'M': - memf = optarg; - break; - case 'N': - nlistf = optarg; - break; - case 'S': - Sflag++; - xocontainer = "cs"; - break; case 'a': aflag++; break; - case 'b': - bflag++; - xocontainer = "binary"; + if (cmd != NULL) + usage(); + cmd = getcmd("binary"); break; - + case 'C': + procstat_opts |= PS_OPT_CAPABILITIES; + break; case 'c': - cflag++; - xocontainer = "arguments"; + if (cmd != NULL) + usage(); + cmd = getcmd("arguments"); break; - case 'e': - eflag++; - xocontainer = "environment"; + if (cmd != NULL) + usage(); + cmd = getcmd("environment"); break; - case 'f': - fflag++; - xocontainer = "files"; + if (cmd != NULL) + usage(); + cmd = getcmd("files"); break; - + case 'H': + procstat_opts |= PS_OPT_PERTHREAD; + break; + case 'h': + procstat_opts |= PS_OPT_NOHEADER; + break; case 'i': - iflag++; - xocontainer = "signals"; + if (cmd != NULL) + usage(); + cmd = getcmd("signals"); break; - case 'j': - jflag++; - xocontainer = "thread_signals"; + if (cmd != NULL) + usage(); + cmd = getcmd("tsignals"); break; - case 'k': - kflag++; - xocontainer = "kstack"; + if (cmd->cmd == procstat_kstack) { + if (procstat_opts & PS_OPT_VERBOSE) + usage(); + procstat_opts |= PS_OPT_VERBOSE; + } else { + if (cmd != NULL) + usage(); + cmd = getcmd("kstack"); + } break; - + case 'L': + if (cmd != NULL) + usage(); + cmd = getcmd("ptlwpinfo"); + break; case 'l': - lflag++; - xocontainer = "rlimit"; + if (cmd != NULL) + usage(); + cmd = getcmd("rlimit"); break; - - case 'L': - Lflag++; - xocontainer = "ptlwpinfo"; + case 'M': + memf = optarg; break; - + case 'N': + nlistf = optarg; + break; case 'n': - nflag++; + procstat_opts |= PS_OPT_SIGNUM; break; - - case 'h': - hflag++; - break; - case 'r': - rflag++; - xocontainer = "rusage"; + if (cmd != NULL) + usage(); + cmd = getcmd("rusage"); break; - + case 'S': + if (cmd != NULL) + usage(); + cmd = getcmd("cpuset"); + break; case 's': - sflag++; - xocontainer = "credentials"; + if (cmd != NULL) + usage(); + cmd = getcmd("credentials"); break; - case 't': - tflag++; - xocontainer = "threads"; + if (cmd != NULL) + usage(); + cmd = getcmd("threads"); break; - case 'v': - vflag++; - xocontainer = "vm"; + if (cmd != NULL) + usage(); + cmd = getcmd("vm"); break; - case 'w': l = strtol(optarg, &dummy, 10); if (*dummy != '\0') @@ -270,12 +359,11 @@ usage(); interval = l; break; - case 'x': - xflag++; - xocontainer = "auxv"; + if (cmd != NULL) + usage(); + cmd = getcmd("auxv"); break; - case '?': default: usage(); @@ -285,24 +373,31 @@ argc -= optind; argv += optind; - /* We require that either 0 or 1 mode flags be set. */ - tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + - lflag + rflag + sflag + tflag + vflag + xflag + Sflag; - if (!(tmp == 0 || tmp == 1)) - usage(); + if (cmd == NULL && argv[0] != NULL && (cmd = getcmd(argv[0])) != NULL) { + if (procstat_opts & PS_SUBCOMMAND_OPTS) + usage(); + if (cmd->opt != NULL) { + optreset = 1; + optind = 1; + cmd->opt(argc, argv); + argc -= optind; + argv += optind; + } else { + argc -= 1; + argv += 1; + } + } else { + if (cmd == NULL) + cmd = getcmd("basic"); + if (cmd->cmd != procstat_files && + (procstat_opts & PS_OPT_CAPABILITIES)) + usage(); + } - /* We allow -k to be specified up to twice, but not more. */ - if (kflag > 2) - usage(); - /* Must specify either the -a flag or a list of pids. */ if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) usage(); - /* Only allow -C with -f. */ - if (Cflag && !fflag) - usage(); - if (memf != NULL) prstat = procstat_open_kvm(nlistf, memf); else @@ -312,7 +407,7 @@ do { xo_set_version(PROCSTAT_XO_VERSION); xo_open_container("procstat"); - xo_open_container(xocontainer); + xo_open_container(cmd->xocontainer); if (aflag) { p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); @@ -320,10 +415,10 @@ xo_errx(1, "procstat_getprocs()"); kinfo_proc_sort(p, cnt); for (i = 0; i < cnt; i++) { - procstat(prstat, &p[i]); + procstat(cmd, prstat, &p[i]); /* Suppress header after first process. */ - hflag = 1; + procstat_opts |= PS_OPT_NOHEADER; xo_flush(); } procstat_freeprocs(prstat, p); @@ -340,7 +435,7 @@ if (p == NULL) xo_errx(1, "procstat_getprocs()"); if (cnt != 0) - procstat(prstat, p); + procstat(cmd, prstat, p); procstat_freeprocs(prstat, p); } else { cprstat = procstat_open_core(argv[i]); @@ -353,15 +448,15 @@ if (p == NULL) xo_errx(1, "procstat_getprocs()"); if (cnt != 0) - procstat(cprstat, p); + procstat(cmd, cprstat, p); procstat_freeprocs(cprstat, p); procstat_close(cprstat); } /* Suppress header after first process. */ - hflag = 1; + procstat_opts |= PS_OPT_NOHEADER; } - xo_close_container(xocontainer); + xo_close_container(cmd->xocontainer); xo_close_container("procstat"); xo_finish(); if (interval) @@ -371,4 +466,96 @@ procstat_close(prstat); exit(0); +} + +void +cmdopt_none(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + case '?': + default: + usage(); + } + } +} + +void +cmdopt_verbose(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + procstat_opts |= PS_OPT_VERBOSE; + break; + case '?': + default: + usage(); + } + } +} + +void +cmdopt_signals(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "n")) != -1) { + switch (ch) { + case 'n': + procstat_opts |= PS_OPT_SIGNUM; + break; + case '?': + default: + usage(); + } + } +} + +void +cmdopt_rusage(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "Ht")) != -1) { + switch (ch) { + case 'H': + /* FALLTHROUGH */ + case 't': + procstat_opts |= PS_OPT_PERTHREAD; + break; + case '?': + default: + usage(); + } + } +} + +void +cmdopt_files(int argc, char *argv[]) +{ + int ch; + + while ((ch = getopt(argc, argv, "C")) != -1) { + switch (ch) { + case 'C': + procstat_opts |= PS_OPT_CAPABILITIES; + break; + case '?': + default: + usage(); + } + } +} + +void +cmdopt_cpuset(int argc, char *argv[]) +{ + + procstat_opts |= PS_OPT_PERTHREAD; + cmdopt_none(argc, argv); } Index: usr.bin/procstat/procstat_args.c =================================================================== --- usr.bin/procstat/procstat_args.c +++ usr.bin/procstat/procstat_args.c @@ -47,7 +47,7 @@ int i; char **args; - if (!hflag) { + if (!(procstat_opts & PS_OPT_NOHEADER)) { xo_emit("{T:/%5s %-16s %-53s}\n", "PID", "COMM", "ARGS"); } @@ -74,7 +74,7 @@ int i; char **envs; - if (!hflag) { + if (!(procstat_opts & PS_OPT_NOHEADER)) { xo_emit("{T:/%5s %-16s %-53s}\n", "PID", "COMM", "ENVIRONMENT"); } Index: usr.bin/procstat/procstat_auxv.c =================================================================== --- usr.bin/procstat/procstat_auxv.c +++ usr.bin/procstat/procstat_auxv.c @@ -51,7 +51,7 @@ u_int count, i; static char prefix[256]; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %-16s %-16s %-16s}\n", "PID", "COMM", "AUXV", "VALUE"); Index: usr.bin/procstat/procstat_basic.c =================================================================== --- usr.bin/procstat/procstat_basic.c +++ usr.bin/procstat/procstat_basic.c @@ -39,10 +39,10 @@ #include "procstat.h" void -procstat_basic(struct kinfo_proc *kipp) +procstat_basic(struct procstat *procstat __unused, struct kinfo_proc *kipp) { - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %5s %5s %5s %5s %3s %-8s %-9s %-13s %-12s}\n", "PID", "PPID", "PGID", "SID", "TSID", "THR", "LOGIN", "WCHAN", "EMUL", "COMM"); Index: usr.bin/procstat/procstat_bin.c =================================================================== --- usr.bin/procstat/procstat_bin.c +++ usr.bin/procstat/procstat_bin.c @@ -46,7 +46,7 @@ int osrel; static char pathname[PATH_MAX]; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %-16s %8s %s}\n", "PID", "COMM", "OSREL", "PATH"); Index: usr.bin/procstat/procstat_cred.c =================================================================== --- usr.bin/procstat/procstat_cred.c +++ usr.bin/procstat/procstat_cred.c @@ -48,7 +48,7 @@ unsigned int i, ngroups; gid_t *groups; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %-16s %5s %5s %5s %5s %5s %5s %5s %5s %-15s}\n", "PID", "COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", "SVGID", "UMASK", "FLAGS", "GROUPS"); Index: usr.bin/procstat/procstat_cs.c =================================================================== --- usr.bin/procstat/procstat_cs.c +++ usr.bin/procstat/procstat_cs.c @@ -52,7 +52,7 @@ unsigned int count, i; int once, twice, lastcpu, cpu; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %6s %-19s %-19s %2s %4s %-7s}\n", "PID", "TID", "COMM", "TDNAME", "CPU", "CSID", "CPU MASK"); Index: usr.bin/procstat/procstat_files.c =================================================================== --- usr.bin/procstat/procstat_files.c +++ usr.bin/procstat/procstat_files.c @@ -303,7 +303,7 @@ */ capwidth = 0; head = procstat_getfiles(procstat, kipp, 0); - if (head != NULL && Cflag) { + if (head != NULL && (procstat_opts & PS_OPT_CAPABILITIES)) { STAILQ_FOREACH(fst, head, next) { width = width_capability(&fst->fs_cap_rights); if (width > capwidth) @@ -313,8 +313,8 @@ capwidth = strlen("CAPABILITIES"); } - if (!hflag) { - if (Cflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) { + if (procstat_opts & PS_OPT_CAPABILITIES) xo_emit("{T:/%5s %-16s %5s %1s %-8s %-*s " "%-3s %-12s}\n", "PID", "COMM", "FD", "T", "FLAGS", capwidth, "CAPABILITIES", "PRO", @@ -412,7 +412,7 @@ break; } xo_emit("{d:fd_type/%1s/%s} ", str); - if (!Cflag) { + if (!(procstat_opts & PS_OPT_CAPABILITIES)) { str = "-"; if (fst->fs_type == PS_FST_TYPE_VNODE) { error = procstat_get_vnode_info(procstat, fst, @@ -509,7 +509,7 @@ xo_emit("{elq:fd_flags/lock_held}"); xo_close_list("fd_flags"); - if (!Cflag) { + if (!(procstat_opts & PS_OPT_CAPABILITIES)) { if (fst->fs_ref_count > -1) xo_emit("{:ref_count/%3d/%d} ", fst->fs_ref_count); @@ -521,7 +521,7 @@ else xo_emit("{q:offset/%7c/%c} ", '-'); } - if (Cflag) { + if (procstat_opts & PS_OPT_CAPABILITIES) { print_capability(&fst->fs_cap_rights, capwidth); xo_emit(" "); } Index: usr.bin/procstat/procstat_kstack.c =================================================================== --- usr.bin/procstat/procstat_kstack.c +++ usr.bin/procstat/procstat_kstack.c @@ -162,7 +162,7 @@ void -procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) +procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp) { struct kinfo_kstack *kkstp, *kkstp_free; struct kinfo_proc *kip, *kip_free; @@ -170,7 +170,7 @@ unsigned int i, j; unsigned int kip_count, kstk_count; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %6s %-19s %-19s %-29s}\n", "PID", "TID", "COMM", "TDNAME", "KSTACK"); @@ -234,9 +234,11 @@ * entries, but for a more compact view, we convert carriage * returns to spaces. */ - kstack_cleanup(kkstp->kkst_trace, trace, kflag); + kstack_cleanup(kkstp->kkst_trace, trace, + (procstat_opts & PS_OPT_VERBOSE) ? 2 : 1); xo_open_list("trace"); - kstack_cleanup_encoded(kkstp->kkst_trace, encoded_trace, kflag); + kstack_cleanup_encoded(kkstp->kkst_trace, encoded_trace, + (procstat_opts & PS_OPT_VERBOSE) ? 2 : 1); xo_close_list("trace"); xo_emit("{d:trace/%-29s}\n", trace); } Index: usr.bin/procstat/procstat_ptlwpinfo.c =================================================================== --- usr.bin/procstat/procstat_ptlwpinfo.c +++ usr.bin/procstat/procstat_ptlwpinfo.c @@ -36,7 +36,7 @@ #include "procstat.h" void -procstat_ptlwpinfo(struct procstat *prstat) +procstat_ptlwpinfo(struct procstat *prstat, struct kinfo_proc *kipp __unused) { struct ptrace_lwpinfo *pl; unsigned int count, i; @@ -45,7 +45,7 @@ if (pl == NULL) return; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{:/%6s %7s %5s %5s %5s %6s %5s} {[:/%d}{:/%s}{]:}" " {:/%s}\n", "LWPID", "EVENT", "SIGNO", "CODE", "ERRNO", "PID", "UID", Index: usr.bin/procstat/procstat_rlimit.c =================================================================== --- usr.bin/procstat/procstat_rlimit.c +++ usr.bin/procstat/procstat_rlimit.c @@ -94,7 +94,7 @@ struct rlimit rlimit; int i; - if (!hflag) { + if (!(procstat_opts & PS_OPT_NOHEADER)) { xo_emit("{T:/%5s %-16s %-16s %16s %16s}\n", "PID", "COMM", "RLIMIT", "SOFT ", "HARD "); } Index: usr.bin/procstat/procstat_rusage.c =================================================================== --- usr.bin/procstat/procstat_rusage.c +++ usr.bin/procstat/procstat_rusage.c @@ -106,7 +106,7 @@ { xo_emit("{d:process_id/%5d/%d} ", kipp->ki_pid); - if (Hflag) + if (procstat_opts & PS_OPT_PERTHREAD) xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid); xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); } @@ -125,7 +125,7 @@ xo_emit("{d:resource/%-14s} {d:usage/%29s}{P: }\n", "system time", format_time(&kipp->ki_rusage.ru_stime)); - if (Hflag) { + if (procstat_opts & PS_OPT_PERTHREAD) { asprintf(&threadid, "%d", kipp->ki_tid); if (threadid == NULL) xo_errc(1, ENOMEM, @@ -154,7 +154,7 @@ rusage_info[i].ri_scale)); lp++; } - if (Hflag) { + if (procstat_opts & PS_OPT_PERTHREAD) { xo_close_container(threadid); free(threadid); } @@ -166,15 +166,15 @@ struct kinfo_proc *kip; unsigned int count, i; - if (!hflag) { + if (!(procstat_opts & PS_OPT_NOHEADER)) { xo_emit("{d:ta/%5s} ", "PID"); - if (Hflag) + if (procstat_opts & PS_OPT_PERTHREAD) xo_emit("{d:tb/%6s} ", "TID"); xo_emit("{d:tc/%-16s %-32s %14s}\n", "COMM", "RESOURCE", "VALUE "); } - if (!Hflag) { + if (!(procstat_opts & PS_OPT_PERTHREAD)) { print_rusage(kipp); return; } Index: usr.bin/procstat/procstat_sigs.c =================================================================== --- usr.bin/procstat/procstat_sigs.c +++ usr.bin/procstat/procstat_sigs.c @@ -48,7 +48,7 @@ char name[12]; int i; - if (!nflag && sig < sys_nsig) { + if (!(procstat_opts & PS_OPT_SIGNUM) && sig < sys_nsig) { strlcpy(name, sys_signame[sig], sizeof(name)); for (i = 0; name[i] != 0; i++) name[i] = toupper(name[i]); @@ -67,7 +67,7 @@ char name[12]; int i; - if (!nflag && sig < sys_nsig) { + if (!(procstat_opts & PS_OPT_SIGNUM) && sig < sys_nsig) { strlcpy(name, sys_signame[sig], sizeof(name)); for (i = 0; name[i] != 0; i++) name[i] = toupper(name[i]); @@ -110,7 +110,7 @@ { int j; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %-16s %-7s %4s}\n", "PID", "COMM", "SIG", "FLAGS"); @@ -139,7 +139,7 @@ unsigned int count, i; char *threadid; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %6s %-16s %-7s %4s}\n", "PID", "TID", "COMM", "SIG", "FLAGS"); Index: usr.bin/procstat/procstat_threads.c =================================================================== --- usr.bin/procstat/procstat_threads.c +++ usr.bin/procstat/procstat_threads.c @@ -48,7 +48,7 @@ const char *str; char *threadid; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %6s %-19s %-19s %2s %4s %-7s %-9s}\n", "PID", "TID", "COMM", "TDNAME", "CPU", "PRI", "STATE", "WCHAN"); Index: usr.bin/procstat/procstat_vm.c =================================================================== --- usr.bin/procstat/procstat_vm.c +++ usr.bin/procstat/procstat_vm.c @@ -50,7 +50,7 @@ const char *str, *lstr; ptrwidth = 2*sizeof(void *) + 2; - if (!hflag) + if (!(procstat_opts & PS_OPT_NOHEADER)) xo_emit("{T:/%5s %*s %*s %3s %4s %4s %3s %3s %-4s %-2s %-s}\n", "PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES", "PRES", "REF", "SHD", "FLAG", "TP", "PATH"); Index: usr.bin/procstat/tests/procstat_test.sh =================================================================== --- usr.bin/procstat/tests/procstat_test.sh +++ usr.bin/procstat/tests/procstat_test.sh @@ -63,8 +63,11 @@ header_re=$(printf "$line_format" "PID" "COMM" "OSREL" "PATH") line_re=$(printf "$line_format" $PROG_PID $PROG_COMM "[[:digit:]]+" "$PROG_PATH") - atf_check -o save:procstat.out procstat -b $PROG_PID + atf_check -o save:procstat.out procstat binary $PROG_PID + atf_check -o match:"$header_re" head -n 1 procstat.out + atf_check -o match:"$line_re" tail -n 1 procstat.out + atf_check -o save:procstat.out procstat -b $PROG_PID atf_check -o match:"$header_re" head -n 1 procstat.out atf_check -o match:"$line_re" tail -n 1 procstat.out } @@ -84,6 +87,10 @@ header_re=$(printf "$line_format" "PID" "COMM" "ARGS") line_re=$(printf "$line_format" $PROG_PID "$PROG_COMM" "$PROG_PATH $arguments") + atf_check -o save:procstat.out procstat arguments $PROG_PID + atf_check -o match:"$header_re" head -n 1 procstat.out + atf_check -o match:"$line_re" tail -n 1 procstat.out + atf_check -o save:procstat.out procstat -c $PROG_PID atf_check -o match:"$header_re" head -n 1 procstat.out atf_check -o match:"$line_re" tail -n 1 procstat.out @@ -105,8 +112,11 @@ header_re=$(printf "$line_format" "PID" "COMM" "ENVIRONMENT") line_re=$(printf "$line_format" $PROG_PID $PROG_COMM ".*$var.*") - atf_check -o save:procstat.out procstat -e $PROG_PID + atf_check -o save:procstat.out procstat environment $PROG_PID + atf_check -o match:"$header_re" head -n 1 procstat.out + atf_check -o match:"$line_re" tail -n 1 procstat.out + atf_check -o save:procstat.out procstat -e $PROG_PID atf_check -o match:"$header_re" head -n 1 procstat.out atf_check -o match:"$line_re" tail -n 1 procstat.out } @@ -125,8 +135,11 @@ # XXX: write a more sensible feature test line_re=$(printf "$line_format" $PROG_PID $PROG_COMM ".+" ".+" ".+" ".+" ".+" ".+" ".+" ".+") - atf_check -o save:procstat.out procstat -f $PROG_PID + atf_check -o save:procstat.out procstat files $PROG_PID + atf_check -o match:"$header_re" head -n 1 procstat.out + atf_check -o match:"$line_re" awk 'NR > 1' procstat.out + atf_check -o save:procstat.out procstat -f $PROG_PID atf_check -o match:"$header_re" head -n 1 procstat.out atf_check -o match:"$line_re" awk 'NR > 1' procstat.out }