/bin/ps/keyword.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 308 lines · 238 code · 18 blank · 52 comment · 34 complexity · 54ac1596ba6d46a7af49d7e7cb508820 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1990, 1993, 1994
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #if 0
  30. #ifndef lint
  31. static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94";
  32. #endif /* not lint */
  33. #endif
  34. #include <sys/cdefs.h>
  35. __FBSDID("$FreeBSD$");
  36. #include <sys/param.h>
  37. #include <sys/time.h>
  38. #include <sys/resource.h>
  39. #include <sys/proc.h>
  40. #include <sys/sysctl.h>
  41. #include <sys/user.h>
  42. #include <err.h>
  43. #include <stddef.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include "ps.h"
  48. static VAR *findvar(char *, int, char **header);
  49. static int vcmp(const void *, const void *);
  50. /* Compute offset in common structures. */
  51. #define KOFF(x) offsetof(struct kinfo_proc, x)
  52. #define ROFF(x) offsetof(struct rusage, x)
  53. #define LWPFMT "d"
  54. #define NLWPFMT "d"
  55. #define UIDFMT "u"
  56. #define PIDFMT "d"
  57. /* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */
  58. static VAR var[] = {
  59. {"%cpu", "%CPU", NULL, 0, pcpu, 0, CHAR, NULL, 0},
  60. {"%mem", "%MEM", NULL, 0, pmem, 0, CHAR, NULL, 0},
  61. {"acflag", "ACFLG", NULL, 0, kvar, KOFF(ki_acflag), USHORT, "x", 0},
  62. {"acflg", "", "acflag", 0, NULL, 0, CHAR, NULL, 0},
  63. {"args", "COMMAND", NULL, COMM|LJUST|USER, arguments, 0,
  64. CHAR, NULL, 0},
  65. {"blocked", "", "sigmask", 0, NULL, 0, CHAR, NULL, 0},
  66. {"caught", "", "sigcatch", 0, NULL, 0, CHAR, NULL, 0},
  67. {"class", "CLASS", NULL, LJUST, loginclass, 0, CHAR, NULL, 0},
  68. {"comm", "COMMAND", NULL, LJUST, ucomm, 0, CHAR, NULL, 0},
  69. {"command", "COMMAND", NULL, COMM|LJUST|USER, command, 0,
  70. CHAR, NULL, 0},
  71. {"cow", "COW", NULL, 0, kvar, KOFF(ki_cow), UINT, "u", 0},
  72. {"cpu", "CPU", NULL, 0, kvar, KOFF(ki_estcpu), UINT, "d", 0},
  73. {"cputime", "", "time", 0, NULL, 0, CHAR, NULL, 0},
  74. {"dsiz", "DSIZ", NULL, 0, kvar, KOFF(ki_dsize), PGTOK, "ld", 0},
  75. {"egid", "", "gid", 0, NULL, 0, CHAR, NULL, 0},
  76. {"egroup", "", "group", 0, NULL, 0, CHAR, NULL, 0},
  77. {"emul", "EMUL", NULL, LJUST, emulname, 0, CHAR, NULL, 0},
  78. {"etime", "ELAPSED", NULL, USER, elapsed, 0, CHAR, NULL, 0},
  79. {"etimes", "ELAPSED", NULL, USER, elapseds, 0, CHAR, NULL, 0},
  80. {"euid", "", "uid", 0, NULL, 0, CHAR, NULL, 0},
  81. {"f", "F", NULL, 0, kvar, KOFF(ki_flag), INT, "x", 0},
  82. {"flags", "", "f", 0, NULL, 0, CHAR, NULL, 0},
  83. {"gid", "GID", NULL, 0, kvar, KOFF(ki_groups), UINT, UIDFMT, 0},
  84. {"group", "GROUP", NULL, LJUST, egroupname, 0, CHAR, NULL, 0},
  85. {"ignored", "", "sigignore", 0, NULL, 0, CHAR, NULL, 0},
  86. {"inblk", "INBLK", NULL, USER, rvar, ROFF(ru_inblock), LONG, "ld", 0},
  87. {"inblock", "", "inblk", 0, NULL, 0, CHAR, NULL, 0},
  88. {"jid", "JID", NULL, 0, kvar, KOFF(ki_jid), INT, "d", 0},
  89. {"jobc", "JOBC", NULL, 0, kvar, KOFF(ki_jobc), SHORT, "d", 0},
  90. {"ktrace", "KTRACE", NULL, 0, kvar, KOFF(ki_traceflag), INT, "x", 0},
  91. {"label", "LABEL", NULL, LJUST, label, 0, CHAR, NULL, 0},
  92. {"lim", "LIM", NULL, 0, maxrss, 0, CHAR, NULL, 0},
  93. {"lockname", "LOCK", NULL, LJUST, lockname, 0, CHAR, NULL, 0},
  94. {"login", "LOGIN", NULL, LJUST, logname, 0, CHAR, NULL, 0},
  95. {"logname", "", "login", 0, NULL, 0, CHAR, NULL, 0},
  96. {"lstart", "STARTED", NULL, LJUST|USER, lstarted, 0, CHAR, NULL, 0},
  97. {"lwp", "LWP", NULL, 0, kvar, KOFF(ki_tid), UINT, LWPFMT, 0},
  98. {"majflt", "MAJFLT", NULL, USER, rvar, ROFF(ru_majflt), LONG, "ld", 0},
  99. {"minflt", "MINFLT", NULL, USER, rvar, ROFF(ru_minflt), LONG, "ld", 0},
  100. {"msgrcv", "MSGRCV", NULL, USER, rvar, ROFF(ru_msgrcv), LONG, "ld", 0},
  101. {"msgsnd", "MSGSND", NULL, USER, rvar, ROFF(ru_msgsnd), LONG, "ld", 0},
  102. {"mwchan", "MWCHAN", NULL, LJUST, mwchan, 0, CHAR, NULL, 0},
  103. {"ni", "", "nice", 0, NULL, 0, CHAR, NULL, 0},
  104. {"nice", "NI", NULL, 0, kvar, KOFF(ki_nice), CHAR, "d", 0},
  105. {"nivcsw", "NIVCSW", NULL, USER, rvar, ROFF(ru_nivcsw), LONG, "ld", 0},
  106. {"nlwp", "NLWP", NULL, 0, kvar, KOFF(ki_numthreads), UINT, NLWPFMT, 0},
  107. {"nsignals", "", "nsigs", 0, NULL, 0, CHAR, NULL, 0},
  108. {"nsigs", "NSIGS", NULL, USER, rvar, ROFF(ru_nsignals), LONG, "ld", 0},
  109. {"nswap", "NSWAP", NULL, USER, rvar, ROFF(ru_nswap), LONG, "ld", 0},
  110. {"nvcsw", "NVCSW", NULL, USER, rvar, ROFF(ru_nvcsw), LONG, "ld", 0},
  111. {"nwchan", "NWCHAN", NULL, LJUST, nwchan, 0, CHAR, NULL, 0},
  112. {"oublk", "OUBLK", NULL, USER, rvar, ROFF(ru_oublock), LONG, "ld", 0},
  113. {"oublock", "", "oublk", 0, NULL, 0, CHAR, NULL, 0},
  114. {"paddr", "PADDR", NULL, 0, kvar, KOFF(ki_paddr), KPTR, "lx", 0},
  115. {"pagein", "PAGEIN", NULL, USER, pagein, 0, CHAR, NULL, 0},
  116. {"pcpu", "", "%cpu", 0, NULL, 0, CHAR, NULL, 0},
  117. {"pending", "", "sig", 0, NULL, 0, CHAR, NULL, 0},
  118. {"pgid", "PGID", NULL, 0, kvar, KOFF(ki_pgid), UINT, PIDFMT, 0},
  119. {"pid", "PID", NULL, 0, kvar, KOFF(ki_pid), UINT, PIDFMT, 0},
  120. {"pmem", "", "%mem", 0, NULL, 0, CHAR, NULL, 0},
  121. {"ppid", "PPID", NULL, 0, kvar, KOFF(ki_ppid), UINT, PIDFMT, 0},
  122. {"pri", "PRI", NULL, 0, pri, 0, CHAR, NULL, 0},
  123. {"re", "RE", NULL, INF127, kvar, KOFF(ki_swtime), UINT, "d", 0},
  124. {"rgid", "RGID", NULL, 0, kvar, KOFF(ki_rgid), UINT, UIDFMT, 0},
  125. {"rgroup", "RGROUP", NULL, LJUST, rgroupname, 0, CHAR, NULL, 0},
  126. {"rss", "RSS", NULL, 0, kvar, KOFF(ki_rssize), PGTOK, "ld", 0},
  127. {"rtprio", "RTPRIO", NULL, 0, priorityr, KOFF(ki_pri), CHAR, NULL, 0},
  128. {"ruid", "RUID", NULL, 0, kvar, KOFF(ki_ruid), UINT, UIDFMT, 0},
  129. {"ruser", "RUSER", NULL, LJUST, runame, 0, CHAR, NULL, 0},
  130. {"sid", "SID", NULL, 0, kvar, KOFF(ki_sid), UINT, PIDFMT, 0},
  131. {"sig", "PENDING", NULL, 0, kvar, KOFF(ki_siglist), INT, "x", 0},
  132. {"sigcatch", "CAUGHT", NULL, 0, kvar, KOFF(ki_sigcatch), UINT, "x", 0},
  133. {"sigignore", "IGNORED", NULL, 0, kvar, KOFF(ki_sigignore),
  134. UINT, "x", 0},
  135. {"sigmask", "BLOCKED", NULL, 0, kvar, KOFF(ki_sigmask), UINT, "x", 0},
  136. {"sl", "SL", NULL, INF127, kvar, KOFF(ki_slptime), UINT, "d", 0},
  137. {"ssiz", "SSIZ", NULL, 0, kvar, KOFF(ki_ssize), PGTOK, "ld", 0},
  138. {"start", "STARTED", NULL, LJUST|USER, started, 0, CHAR, NULL, 0},
  139. {"stat", "", "state", 0, NULL, 0, CHAR, NULL, 0},
  140. {"state", "STAT", NULL, LJUST, state, 0, CHAR, NULL, 0},
  141. {"svgid", "SVGID", NULL, 0, kvar, KOFF(ki_svgid), UINT, UIDFMT, 0},
  142. {"svuid", "SVUID", NULL, 0, kvar, KOFF(ki_svuid), UINT, UIDFMT, 0},
  143. {"systime", "SYSTIME", NULL, USER, systime, 0, CHAR, NULL, 0},
  144. {"tdaddr", "TDADDR", NULL, 0, kvar, KOFF(ki_tdaddr), KPTR, "lx", 0},
  145. {"tdev", "TDEV", NULL, 0, tdev, 0, CHAR, NULL, 0},
  146. {"tdnam", "TDNAM", NULL, LJUST, tdnam, 0, CHAR, NULL, 0},
  147. {"time", "TIME", NULL, USER, cputime, 0, CHAR, NULL, 0},
  148. {"tpgid", "TPGID", NULL, 0, kvar, KOFF(ki_tpgid), UINT, PIDFMT, 0},
  149. {"tsid", "TSID", NULL, 0, kvar, KOFF(ki_tsid), UINT, PIDFMT, 0},
  150. {"tsiz", "TSIZ", NULL, 0, kvar, KOFF(ki_tsize), PGTOK, "ld", 0},
  151. {"tt", "TT ", NULL, 0, tname, 0, CHAR, NULL, 0},
  152. {"tty", "TTY", NULL, LJUST, longtname, 0, CHAR, NULL, 0},
  153. {"ucomm", "UCOMM", NULL, LJUST, ucomm, 0, CHAR, NULL, 0},
  154. {"uid", "UID", NULL, 0, kvar, KOFF(ki_uid), UINT, UIDFMT, 0},
  155. {"upr", "UPR", NULL, 0, upr, 0, CHAR, NULL, 0},
  156. {"uprocp", "UPROCP", NULL, 0, kvar, KOFF(ki_paddr), KPTR, "lx", 0},
  157. {"user", "USER", NULL, LJUST, uname, 0, CHAR, NULL, 0},
  158. {"usertime", "USERTIME", NULL, USER, usertime, 0, CHAR, NULL, 0},
  159. {"usrpri", "", "upr", 0, NULL, 0, CHAR, NULL, 0},
  160. {"vsize", "", "vsz", 0, NULL, 0, CHAR, NULL, 0},
  161. {"vsz", "VSZ", NULL, 0, vsize, 0, CHAR, NULL, 0},
  162. {"wchan", "WCHAN", NULL, LJUST, wchan, 0, CHAR, NULL, 0},
  163. {"xstat", "XSTAT", NULL, 0, kvar, KOFF(ki_xstat), USHORT, "x", 0},
  164. {"", NULL, NULL, 0, NULL, 0, CHAR, NULL, 0},
  165. };
  166. void
  167. showkey(void)
  168. {
  169. VAR *v;
  170. int i;
  171. const char *p, *sep;
  172. i = 0;
  173. sep = "";
  174. for (v = var; *(p = v->name); ++v) {
  175. int len = strlen(p);
  176. if (termwidth && (i += len + 1) > termwidth) {
  177. i = len;
  178. sep = "\n";
  179. }
  180. (void) printf("%s%s", sep, p);
  181. sep = " ";
  182. }
  183. (void) printf("\n");
  184. }
  185. void
  186. parsefmt(const char *p, int user)
  187. {
  188. char *tempstr, *tempstr1;
  189. #define FMTSEP " \t,\n"
  190. tempstr1 = tempstr = strdup(p);
  191. while (tempstr && *tempstr) {
  192. char *cp, *hp;
  193. VAR *v;
  194. struct varent *vent;
  195. /*
  196. * If an item contains an equals sign, it specifies a column
  197. * header, may contain embedded separator characters and
  198. * is always the last item.
  199. */
  200. if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=')
  201. while ((cp = strsep(&tempstr, FMTSEP)) != NULL &&
  202. *cp == '\0')
  203. /* void */;
  204. else {
  205. cp = tempstr;
  206. tempstr = NULL;
  207. }
  208. if (cp == NULL || !(v = findvar(cp, user, &hp)))
  209. continue;
  210. if (!user) {
  211. /*
  212. * If the user is NOT adding this field manually,
  213. * get on with our lives if this VAR is already
  214. * represented in the list.
  215. */
  216. vent = find_varentry(v);
  217. if (vent != NULL)
  218. continue;
  219. }
  220. if ((vent = malloc(sizeof(struct varent))) == NULL)
  221. errx(1, "malloc failed");
  222. vent->header = v->header;
  223. if (hp) {
  224. hp = strdup(hp);
  225. if (hp)
  226. vent->header = hp;
  227. }
  228. vent->var = malloc(sizeof(*vent->var));
  229. if (vent->var == NULL)
  230. errx(1, "malloc failed");
  231. memcpy(vent->var, v, sizeof(*vent->var));
  232. STAILQ_INSERT_TAIL(&varlist, vent, next_ve);
  233. }
  234. free(tempstr1);
  235. if (STAILQ_EMPTY(&varlist)) {
  236. warnx("no valid keywords; valid keywords:");
  237. showkey();
  238. exit(1);
  239. }
  240. }
  241. static VAR *
  242. findvar(char *p, int user, char **header)
  243. {
  244. size_t rflen;
  245. VAR *v, key;
  246. char *hp, *realfmt;
  247. hp = strchr(p, '=');
  248. if (hp)
  249. *hp++ = '\0';
  250. key.name = p;
  251. v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp);
  252. if (v && v->alias) {
  253. /*
  254. * If the user specified an alternate-header for this
  255. * (aliased) format-name, then we need to copy that
  256. * alternate-header when making the recursive call to
  257. * process the alias.
  258. */
  259. if (hp == NULL)
  260. parsefmt(v->alias, user);
  261. else {
  262. /*
  263. * XXX - This processing will not be correct for
  264. * any alias which expands into a list of format
  265. * keywords. Presently there are no aliases
  266. * which do that.
  267. */
  268. rflen = strlen(v->alias) + strlen(hp) + 2;
  269. realfmt = malloc(rflen);
  270. if (realfmt == NULL)
  271. errx(1, "malloc failed");
  272. snprintf(realfmt, rflen, "%s=%s", v->alias, hp);
  273. parsefmt(realfmt, user);
  274. free(realfmt);
  275. }
  276. return ((VAR *)NULL);
  277. }
  278. if (!v) {
  279. warnx("%s: keyword not found", p);
  280. eval = 1;
  281. }
  282. if (header)
  283. *header = hp;
  284. return (v);
  285. }
  286. static int
  287. vcmp(const void *a, const void *b)
  288. {
  289. return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name));
  290. }