/usr.bin/procstat/procstat.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 279 lines · 203 code · 40 blank · 36 comment · 64 complexity · 68ce9ebd6f8bf014e5639e57a92daac2 MD5 · raw file

  1. /*-
  2. * Copyright (c) 2007, 2011 Robert N. M. Watson
  3. * 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. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. * $FreeBSD$
  27. */
  28. #include <sys/param.h>
  29. #include <sys/sysctl.h>
  30. #include <sys/user.h>
  31. #include <err.h>
  32. #include <libprocstat.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <sysexits.h>
  36. #include <unistd.h>
  37. #include "procstat.h"
  38. static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, sflag;
  39. static int tflag, vflag, xflag;
  40. int hflag, nflag, Cflag;
  41. static void
  42. usage(void)
  43. {
  44. fprintf(stderr, "usage: procstat [-h] [-C] [-M core] [-N system] "
  45. "[-w interval] \n");
  46. fprintf(stderr, " [-b | -c | -e | -f | -i | -j | -k | "
  47. "-l | -s | -t | -v | -x] [-a | pid ...]\n");
  48. exit(EX_USAGE);
  49. }
  50. static void
  51. procstat(struct procstat *prstat, struct kinfo_proc *kipp)
  52. {
  53. if (bflag)
  54. procstat_bin(kipp);
  55. else if (cflag)
  56. procstat_args(kipp);
  57. else if (eflag)
  58. procstat_env(kipp);
  59. else if (fflag)
  60. procstat_files(prstat, kipp);
  61. else if (iflag)
  62. procstat_sigs(prstat, kipp);
  63. else if (jflag)
  64. procstat_threads_sigs(prstat, kipp);
  65. else if (kflag)
  66. procstat_kstack(kipp, kflag);
  67. else if (lflag)
  68. procstat_rlimit(kipp);
  69. else if (sflag)
  70. procstat_cred(kipp);
  71. else if (tflag)
  72. procstat_threads(kipp);
  73. else if (vflag)
  74. procstat_vm(kipp);
  75. else if (xflag)
  76. procstat_auxv(kipp);
  77. else
  78. procstat_basic(kipp);
  79. }
  80. /*
  81. * Sort processes first by pid and then tid.
  82. */
  83. static int
  84. kinfo_proc_compare(const void *a, const void *b)
  85. {
  86. int i;
  87. i = ((const struct kinfo_proc *)a)->ki_pid -
  88. ((const struct kinfo_proc *)b)->ki_pid;
  89. if (i != 0)
  90. return (i);
  91. i = ((const struct kinfo_proc *)a)->ki_tid -
  92. ((const struct kinfo_proc *)b)->ki_tid;
  93. return (i);
  94. }
  95. void
  96. kinfo_proc_sort(struct kinfo_proc *kipp, int count)
  97. {
  98. qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare);
  99. }
  100. int
  101. main(int argc, char *argv[])
  102. {
  103. int ch, interval, tmp;
  104. int i;
  105. struct kinfo_proc *p;
  106. struct procstat *prstat;
  107. long l;
  108. pid_t pid;
  109. char *dummy;
  110. char *nlistf, *memf;
  111. int cnt;
  112. interval = 0;
  113. memf = nlistf = NULL;
  114. while ((ch = getopt(argc, argv, "CN:M:abcefijklhstvw:x")) != -1) {
  115. switch (ch) {
  116. case 'C':
  117. Cflag++;
  118. break;
  119. case 'M':
  120. memf = optarg;
  121. break;
  122. case 'N':
  123. nlistf = optarg;
  124. break;
  125. case 'a':
  126. aflag++;
  127. break;
  128. case 'b':
  129. bflag++;
  130. break;
  131. case 'c':
  132. cflag++;
  133. break;
  134. case 'e':
  135. eflag++;
  136. break;
  137. case 'f':
  138. fflag++;
  139. break;
  140. case 'i':
  141. iflag++;
  142. break;
  143. case 'j':
  144. jflag++;
  145. break;
  146. case 'k':
  147. kflag++;
  148. break;
  149. case 'l':
  150. lflag++;
  151. break;
  152. case 'n':
  153. nflag++;
  154. break;
  155. case 'h':
  156. hflag++;
  157. break;
  158. case 's':
  159. sflag++;
  160. break;
  161. case 't':
  162. tflag++;
  163. break;
  164. case 'v':
  165. vflag++;
  166. break;
  167. case 'w':
  168. l = strtol(optarg, &dummy, 10);
  169. if (*dummy != '\0')
  170. usage();
  171. if (l < 1 || l > INT_MAX)
  172. usage();
  173. interval = l;
  174. break;
  175. case 'x':
  176. xflag++;
  177. break;
  178. case '?':
  179. default:
  180. usage();
  181. }
  182. }
  183. argc -= optind;
  184. argv += optind;
  185. /* We require that either 0 or 1 mode flags be set. */
  186. tmp = bflag + cflag + eflag + fflag + (kflag ? 1 : 0) + lflag + sflag +
  187. tflag + vflag + xflag;
  188. if (!(tmp == 0 || tmp == 1))
  189. usage();
  190. /* We allow -k to be specified up to twice, but not more. */
  191. if (kflag > 2)
  192. usage();
  193. /* Must specify either the -a flag or a list of pids. */
  194. if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0))
  195. usage();
  196. /* Only allow -C with -f. */
  197. if (Cflag && !fflag)
  198. usage();
  199. if (memf != NULL)
  200. prstat = procstat_open_kvm(nlistf, memf);
  201. else
  202. prstat = procstat_open_sysctl();
  203. if (prstat == NULL)
  204. errx(1, "procstat_open()");
  205. do {
  206. if (aflag) {
  207. p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt);
  208. if (p == NULL)
  209. errx(1, "procstat_getprocs()");
  210. kinfo_proc_sort(p, cnt);
  211. for (i = 0; i < cnt; i++) {
  212. procstat(prstat, &p[i]);
  213. /* Suppress header after first process. */
  214. hflag = 1;
  215. }
  216. procstat_freeprocs(prstat, p);
  217. }
  218. for (i = 0; i < argc; i++) {
  219. l = strtol(argv[i], &dummy, 10);
  220. if (*dummy != '\0')
  221. usage();
  222. if (l < 0)
  223. usage();
  224. pid = l;
  225. p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
  226. if (p == NULL)
  227. errx(1, "procstat_getprocs()");
  228. if (cnt != 0)
  229. procstat(prstat, p);
  230. procstat_freeprocs(prstat, p);
  231. /* Suppress header after first process. */
  232. hflag = 1;
  233. }
  234. if (interval)
  235. sleep(interval);
  236. } while (interval);
  237. procstat_close(prstat);
  238. exit(0);
  239. }