11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1990, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 4. Neither the name of the University nor the names of its contributors 141556Srgrimes * may be used to endorse or promote products derived from this software 151556Srgrimes * without specific prior written permission. 161556Srgrimes * 171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271556Srgrimes * SUCH DAMAGE. 281556Srgrimes */ 291556Srgrimes 3090143Smarkm#if 0 311556Srgrimes#ifndef lint 3228052Sstevestatic char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94"; 3390143Smarkm#endif /* not lint */ 3428052Ssteve#endif 3599110Sobrien#include <sys/cdefs.h> 3699110Sobrien__FBSDID("$FreeBSD$"); 371556Srgrimes 381556Srgrimes#include <sys/param.h> 391556Srgrimes#include <sys/time.h> 401556Srgrimes#include <sys/resource.h> 411556Srgrimes#include <sys/proc.h> 4228054Ssteve#include <sys/sysctl.h> 4328054Ssteve#include <sys/user.h> 441556Srgrimes 451556Srgrimes#include <err.h> 461556Srgrimes#include <stddef.h> 471556Srgrimes#include <stdio.h> 481556Srgrimes#include <stdlib.h> 491556Srgrimes#include <string.h> 501556Srgrimes 511556Srgrimes#include "ps.h" 521556Srgrimes 53109504Sjmallettstatic VAR *findvar(char *, int, char **header); 5490110Simpstatic int vcmp(const void *, const void *); 551556Srgrimes 561556Srgrimes/* Compute offset in common structures. */ 5769896Smckusick#define KOFF(x) offsetof(struct kinfo_proc, x) 581556Srgrimes#define ROFF(x) offsetof(struct rusage, x) 591556Srgrimes 60130827Sgad#define LWPFMT "d" 61130827Sgad#define NLWPFMT "d" 621556Srgrimes#define UIDFMT "u" 631556Srgrimes#define PIDFMT "d" 641556Srgrimes 65110411Ssobomax/* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */ 6690143Smarkmstatic VAR var[] = { 67225868Strasz {"%cpu", "%CPU", NULL, 0, pcpu, 0, CHAR, NULL, 0}, 68225868Strasz {"%mem", "%MEM", NULL, 0, pmem, 0, CHAR, NULL, 0}, 69225868Strasz {"acflag", "ACFLG", NULL, 0, kvar, KOFF(ki_acflag), USHORT, "x", 0}, 70225868Strasz {"acflg", "", "acflag", 0, NULL, 0, CHAR, NULL, 0}, 71225868Strasz {"args", "COMMAND", NULL, COMM|LJUST|USER, arguments, 0, 7297958Sjmallett CHAR, NULL, 0}, 73225868Strasz {"blocked", "", "sigmask", 0, NULL, 0, CHAR, NULL, 0}, 74225868Strasz {"caught", "", "sigcatch", 0, NULL, 0, CHAR, NULL, 0}, 75225868Strasz {"class", "CLASS", NULL, LJUST, loginclass, 0, CHAR, NULL, 0}, 76225868Strasz {"comm", "COMMAND", NULL, LJUST, ucomm, 0, CHAR, NULL, 0}, 77225868Strasz {"command", "COMMAND", NULL, COMM|LJUST|USER, command, 0, 7897850Sjmallett CHAR, NULL, 0}, 79235851Skib {"cow", "COW", NULL, 0, kvar, KOFF(ki_cow), UINT, "u", 0}, 80225868Strasz {"cpu", "CPU", NULL, 0, kvar, KOFF(ki_estcpu), UINT, "d", 0}, 81225868Strasz {"cputime", "", "time", 0, NULL, 0, CHAR, NULL, 0}, 82240645Szont {"dsiz", "DSIZ", NULL, 0, kvar, KOFF(ki_dsize), PGTOK, "ld", 0}, 83225868Strasz {"egid", "", "gid", 0, NULL, 0, CHAR, NULL, 0}, 84225868Strasz {"egroup", "", "group", 0, NULL, 0, CHAR, NULL, 0}, 85225868Strasz {"emul", "EMUL", NULL, LJUST, emulname, 0, CHAR, NULL, 0}, 86225868Strasz {"etime", "ELAPSED", NULL, USER, elapsed, 0, CHAR, NULL, 0}, 87225868Strasz {"etimes", "ELAPSED", NULL, USER, elapseds, 0, CHAR, NULL, 0}, 88225868Strasz {"euid", "", "uid", 0, NULL, 0, CHAR, NULL, 0}, 89225868Strasz {"f", "F", NULL, 0, kvar, KOFF(ki_flag), INT, "x", 0}, 90267904Spluknet {"f2", "F2", NULL, 0, kvar, KOFF(ki_flag2), INT, "08x", 0}, 91254943Swill {"fib", "FIB", NULL, 0, kvar, KOFF(ki_fibnum), INT, "d", 0}, 92225868Strasz {"flags", "", "f", 0, NULL, 0, CHAR, NULL, 0}, 93267904Spluknet {"flags2", "", "f2", 0, NULL, 0, CHAR, NULL, 0}, 94225868Strasz {"gid", "GID", NULL, 0, kvar, KOFF(ki_groups), UINT, UIDFMT, 0}, 95225868Strasz {"group", "GROUP", NULL, LJUST, egroupname, 0, CHAR, NULL, 0}, 96225868Strasz {"ignored", "", "sigignore", 0, NULL, 0, CHAR, NULL, 0}, 97225868Strasz {"inblk", "INBLK", NULL, USER, rvar, ROFF(ru_inblock), LONG, "ld", 0}, 98225868Strasz {"inblock", "", "inblk", 0, NULL, 0, CHAR, NULL, 0}, 99225868Strasz {"jid", "JID", NULL, 0, kvar, KOFF(ki_jid), INT, "d", 0}, 100225868Strasz {"jobc", "JOBC", NULL, 0, kvar, KOFF(ki_jobc), SHORT, "d", 0}, 101225868Strasz {"ktrace", "KTRACE", NULL, 0, kvar, KOFF(ki_traceflag), INT, "x", 0}, 102225868Strasz {"label", "LABEL", NULL, LJUST, label, 0, CHAR, NULL, 0}, 103225868Strasz {"lim", "LIM", NULL, 0, maxrss, 0, CHAR, NULL, 0}, 104225868Strasz {"lockname", "LOCK", NULL, LJUST, lockname, 0, CHAR, NULL, 0}, 105225868Strasz {"login", "LOGIN", NULL, LJUST, logname, 0, CHAR, NULL, 0}, 106225868Strasz {"logname", "", "login", 0, NULL, 0, CHAR, NULL, 0}, 107225868Strasz {"lstart", "STARTED", NULL, LJUST|USER, lstarted, 0, CHAR, NULL, 0}, 108225868Strasz {"lwp", "LWP", NULL, 0, kvar, KOFF(ki_tid), UINT, LWPFMT, 0}, 109225868Strasz {"majflt", "MAJFLT", NULL, USER, rvar, ROFF(ru_majflt), LONG, "ld", 0}, 110225868Strasz {"minflt", "MINFLT", NULL, USER, rvar, ROFF(ru_minflt), LONG, "ld", 0}, 111225868Strasz {"msgrcv", "MSGRCV", NULL, USER, rvar, ROFF(ru_msgrcv), LONG, "ld", 0}, 112225868Strasz {"msgsnd", "MSGSND", NULL, USER, rvar, ROFF(ru_msgsnd), LONG, "ld", 0}, 113225868Strasz {"mwchan", "MWCHAN", NULL, LJUST, mwchan, 0, CHAR, NULL, 0}, 114225868Strasz {"ni", "", "nice", 0, NULL, 0, CHAR, NULL, 0}, 115225868Strasz {"nice", "NI", NULL, 0, kvar, KOFF(ki_nice), CHAR, "d", 0}, 116225868Strasz {"nivcsw", "NIVCSW", NULL, USER, rvar, ROFF(ru_nivcsw), LONG, "ld", 0}, 117225868Strasz {"nlwp", "NLWP", NULL, 0, kvar, KOFF(ki_numthreads), UINT, NLWPFMT, 0}, 118225868Strasz {"nsignals", "", "nsigs", 0, NULL, 0, CHAR, NULL, 0}, 119225868Strasz {"nsigs", "NSIGS", NULL, USER, rvar, ROFF(ru_nsignals), LONG, "ld", 0}, 120225868Strasz {"nswap", "NSWAP", NULL, USER, rvar, ROFF(ru_nswap), LONG, "ld", 0}, 121225868Strasz {"nvcsw", "NVCSW", NULL, USER, rvar, ROFF(ru_nvcsw), LONG, "ld", 0}, 122225868Strasz {"nwchan", "NWCHAN", NULL, LJUST, nwchan, 0, CHAR, NULL, 0}, 123225868Strasz {"oublk", "OUBLK", NULL, USER, rvar, ROFF(ru_oublock), LONG, "ld", 0}, 124225868Strasz {"oublock", "", "oublk", 0, NULL, 0, CHAR, NULL, 0}, 125225868Strasz {"paddr", "PADDR", NULL, 0, kvar, KOFF(ki_paddr), KPTR, "lx", 0}, 126225868Strasz {"pagein", "PAGEIN", NULL, USER, pagein, 0, CHAR, NULL, 0}, 127225868Strasz {"pcpu", "", "%cpu", 0, NULL, 0, CHAR, NULL, 0}, 128225868Strasz {"pending", "", "sig", 0, NULL, 0, CHAR, NULL, 0}, 129225868Strasz {"pgid", "PGID", NULL, 0, kvar, KOFF(ki_pgid), UINT, PIDFMT, 0}, 130225868Strasz {"pid", "PID", NULL, 0, kvar, KOFF(ki_pid), UINT, PIDFMT, 0}, 131225868Strasz {"pmem", "", "%mem", 0, NULL, 0, CHAR, NULL, 0}, 132225868Strasz {"ppid", "PPID", NULL, 0, kvar, KOFF(ki_ppid), UINT, PIDFMT, 0}, 133225868Strasz {"pri", "PRI", NULL, 0, pri, 0, CHAR, NULL, 0}, 134225868Strasz {"re", "RE", NULL, INF127, kvar, KOFF(ki_swtime), UINT, "d", 0}, 135225868Strasz {"rgid", "RGID", NULL, 0, kvar, KOFF(ki_rgid), UINT, UIDFMT, 0}, 136225868Strasz {"rgroup", "RGROUP", NULL, LJUST, rgroupname, 0, CHAR, NULL, 0}, 137225868Strasz {"rss", "RSS", NULL, 0, kvar, KOFF(ki_rssize), PGTOK, "ld", 0}, 138225868Strasz {"rtprio", "RTPRIO", NULL, 0, priorityr, KOFF(ki_pri), CHAR, NULL, 0}, 139225868Strasz {"ruid", "RUID", NULL, 0, kvar, KOFF(ki_ruid), UINT, UIDFMT, 0}, 140225868Strasz {"ruser", "RUSER", NULL, LJUST, runame, 0, CHAR, NULL, 0}, 141225868Strasz {"sid", "SID", NULL, 0, kvar, KOFF(ki_sid), UINT, PIDFMT, 0}, 142225868Strasz {"sig", "PENDING", NULL, 0, kvar, KOFF(ki_siglist), INT, "x", 0}, 143225868Strasz {"sigcatch", "CAUGHT", NULL, 0, kvar, KOFF(ki_sigcatch), UINT, "x", 0}, 144225868Strasz {"sigignore", "IGNORED", NULL, 0, kvar, KOFF(ki_sigignore), 14590143Smarkm UINT, "x", 0}, 146225868Strasz {"sigmask", "BLOCKED", NULL, 0, kvar, KOFF(ki_sigmask), UINT, "x", 0}, 147225868Strasz {"sl", "SL", NULL, INF127, kvar, KOFF(ki_slptime), UINT, "d", 0}, 148240645Szont {"ssiz", "SSIZ", NULL, 0, kvar, KOFF(ki_ssize), PGTOK, "ld", 0}, 149225868Strasz {"start", "STARTED", NULL, LJUST|USER, started, 0, CHAR, NULL, 0}, 150225868Strasz {"stat", "", "state", 0, NULL, 0, CHAR, NULL, 0}, 151225868Strasz {"state", "STAT", NULL, LJUST, state, 0, CHAR, NULL, 0}, 152225868Strasz {"svgid", "SVGID", NULL, 0, kvar, KOFF(ki_svgid), UINT, UIDFMT, 0}, 153225868Strasz {"svuid", "SVUID", NULL, 0, kvar, KOFF(ki_svuid), UINT, UIDFMT, 0}, 154225868Strasz {"systime", "SYSTIME", NULL, USER, systime, 0, CHAR, NULL, 0}, 155225868Strasz {"tdaddr", "TDADDR", NULL, 0, kvar, KOFF(ki_tdaddr), KPTR, "lx", 0}, 156225868Strasz {"tdev", "TDEV", NULL, 0, tdev, 0, CHAR, NULL, 0}, 157225868Strasz {"tdnam", "TDNAM", NULL, LJUST, tdnam, 0, CHAR, NULL, 0}, 158225868Strasz {"time", "TIME", NULL, USER, cputime, 0, CHAR, NULL, 0}, 159225868Strasz {"tpgid", "TPGID", NULL, 0, kvar, KOFF(ki_tpgid), UINT, PIDFMT, 0}, 160225868Strasz {"tsid", "TSID", NULL, 0, kvar, KOFF(ki_tsid), UINT, PIDFMT, 0}, 161225868Strasz {"tsiz", "TSIZ", NULL, 0, kvar, KOFF(ki_tsize), PGTOK, "ld", 0}, 162225868Strasz {"tt", "TT ", NULL, 0, tname, 0, CHAR, NULL, 0}, 163225868Strasz {"tty", "TTY", NULL, LJUST, longtname, 0, CHAR, NULL, 0}, 164225868Strasz {"ucomm", "UCOMM", NULL, LJUST, ucomm, 0, CHAR, NULL, 0}, 165225868Strasz {"uid", "UID", NULL, 0, kvar, KOFF(ki_uid), UINT, UIDFMT, 0}, 166225868Strasz {"upr", "UPR", NULL, 0, upr, 0, CHAR, NULL, 0}, 167225868Strasz {"uprocp", "UPROCP", NULL, 0, kvar, KOFF(ki_paddr), KPTR, "lx", 0}, 168225868Strasz {"user", "USER", NULL, LJUST, uname, 0, CHAR, NULL, 0}, 169225868Strasz {"usertime", "USERTIME", NULL, USER, usertime, 0, CHAR, NULL, 0}, 170225868Strasz {"usrpri", "", "upr", 0, NULL, 0, CHAR, NULL, 0}, 171225868Strasz {"vsize", "", "vsz", 0, NULL, 0, CHAR, NULL, 0}, 172225868Strasz {"vsz", "VSZ", NULL, 0, vsize, 0, CHAR, NULL, 0}, 173225868Strasz {"wchan", "WCHAN", NULL, LJUST, wchan, 0, CHAR, NULL, 0}, 174225868Strasz {"xstat", "XSTAT", NULL, 0, kvar, KOFF(ki_xstat), USHORT, "x", 0}, 175225868Strasz {"", NULL, NULL, 0, NULL, 0, CHAR, NULL, 0}, 1761556Srgrimes}; 1771556Srgrimes 1781556Srgrimesvoid 17990110Simpshowkey(void) 1801556Srgrimes{ 1811556Srgrimes VAR *v; 1821556Srgrimes int i; 18390143Smarkm const char *p, *sep; 1841556Srgrimes 1851556Srgrimes i = 0; 1861556Srgrimes sep = ""; 1871556Srgrimes for (v = var; *(p = v->name); ++v) { 1881556Srgrimes int len = strlen(p); 1891556Srgrimes if (termwidth && (i += len + 1) > termwidth) { 1901556Srgrimes i = len; 1911556Srgrimes sep = "\n"; 1921556Srgrimes } 1931556Srgrimes (void) printf("%s%s", sep, p); 1941556Srgrimes sep = " "; 1951556Srgrimes } 1961556Srgrimes (void) printf("\n"); 1971556Srgrimes} 1981556Srgrimes 1991556Srgrimesvoid 200109502Sjmallettparsefmt(const char *p, int user) 2011556Srgrimes{ 20290143Smarkm char *tempstr, *tempstr1; 2031556Srgrimes 20498050Sjmallett#define FMTSEP " \t,\n" 20590143Smarkm tempstr1 = tempstr = strdup(p); 20690143Smarkm while (tempstr && *tempstr) { 207109504Sjmallett char *cp, *hp; 2081556Srgrimes VAR *v; 2091556Srgrimes struct varent *vent; 2101556Srgrimes 21197944Sjmallett /* 21298050Sjmallett * If an item contains an equals sign, it specifies a column 21398050Sjmallett * header, may contain embedded separator characters and 21498050Sjmallett * is always the last item. 21597944Sjmallett */ 21698050Sjmallett if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=') 21798050Sjmallett while ((cp = strsep(&tempstr, FMTSEP)) != NULL && 21898050Sjmallett *cp == '\0') 21998050Sjmallett /* void */; 22098050Sjmallett else { 22198050Sjmallett cp = tempstr; 22298050Sjmallett tempstr = NULL; 22398050Sjmallett } 224109504Sjmallett if (cp == NULL || !(v = findvar(cp, user, &hp))) 2251556Srgrimes continue; 226109502Sjmallett if (!user) { 227109502Sjmallett /* 228109502Sjmallett * If the user is NOT adding this field manually, 229109502Sjmallett * get on with our lives if this VAR is already 230109502Sjmallett * represented in the list. 231109502Sjmallett */ 232109502Sjmallett vent = find_varentry(v); 233109502Sjmallett if (vent != NULL) 234109502Sjmallett continue; 235109502Sjmallett } 2361556Srgrimes if ((vent = malloc(sizeof(struct varent))) == NULL) 23797877Sjmallett errx(1, "malloc failed"); 238109504Sjmallett vent->header = v->header; 239109504Sjmallett if (hp) { 240109504Sjmallett hp = strdup(hp); 241109504Sjmallett if (hp) 242109504Sjmallett vent->header = hp; 243109504Sjmallett } 24497848Sjmallett vent->var = malloc(sizeof(*vent->var)); 24597848Sjmallett if (vent->var == NULL) 24697877Sjmallett errx(1, "malloc failed"); 24797848Sjmallett memcpy(vent->var, v, sizeof(*vent->var)); 248130999Sgad STAILQ_INSERT_TAIL(&varlist, vent, next_ve); 2491556Srgrimes } 25090143Smarkm free(tempstr1); 251130999Sgad if (STAILQ_EMPTY(&varlist)) { 252104026Sjmallett warnx("no valid keywords; valid keywords:"); 253104026Sjmallett showkey(); 254104026Sjmallett exit(1); 255104026Sjmallett } 2561556Srgrimes} 2571556Srgrimes 2581556Srgrimesstatic VAR * 259109504Sjmallettfindvar(char *p, int user, char **header) 2601556Srgrimes{ 261156423Sgad size_t rflen; 2621556Srgrimes VAR *v, key; 263156423Sgad char *hp, *realfmt; 2641556Srgrimes 2651556Srgrimes hp = strchr(p, '='); 2661556Srgrimes if (hp) 2671556Srgrimes *hp++ = '\0'; 2681556Srgrimes 2691556Srgrimes key.name = p; 2701556Srgrimes v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp); 2711556Srgrimes 2721556Srgrimes if (v && v->alias) { 273156423Sgad /* 274157559Sgad * If the user specified an alternate-header for this 275157559Sgad * (aliased) format-name, then we need to copy that 276157559Sgad * alternate-header when making the recursive call to 277157559Sgad * process the alias. 278156423Sgad */ 279157559Sgad if (hp == NULL) 280157559Sgad parsefmt(v->alias, user); 281157559Sgad else { 282157559Sgad /* 283157559Sgad * XXX - This processing will not be correct for 284157559Sgad * any alias which expands into a list of format 285157559Sgad * keywords. Presently there are no aliases 286157559Sgad * which do that. 287157559Sgad */ 288157559Sgad rflen = strlen(v->alias) + strlen(hp) + 2; 289157559Sgad realfmt = malloc(rflen); 290189078Sattilio if (realfmt == NULL) 291189078Sattilio errx(1, "malloc failed"); 292157559Sgad snprintf(realfmt, rflen, "%s=%s", v->alias, hp); 293157559Sgad parsefmt(realfmt, user); 294199351Snetchild free(realfmt); 295157559Sgad } 2961556Srgrimes return ((VAR *)NULL); 2971556Srgrimes } 2981556Srgrimes if (!v) { 2991556Srgrimes warnx("%s: keyword not found", p); 3001556Srgrimes eval = 1; 301109504Sjmallett } 302109504Sjmallett if (header) 303109504Sjmallett *header = hp; 3041556Srgrimes return (v); 3051556Srgrimes} 3061556Srgrimes 3071556Srgrimesstatic int 30890110Simpvcmp(const void *a, const void *b) 3091556Srgrimes{ 31090143Smarkm return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name)); 3111556Srgrimes} 312