1 /*- 2 * Copyright (c) 2007, 2011 Robert N. M. Watson 3 * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/sysctl.h> 32 #include <sys/user.h> 33 34 #include <err.h> 35 #include <libprocstat.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <sysexits.h> 39 #include <unistd.h> 40 41 #include "procstat.h" 42 43 static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, rflag; 44 static int sflag, tflag, vflag, xflag, Sflag; 45 int hflag, nflag, Cflag, Hflag; 46 47 static void 48 usage(void) 49 { 50 51 xo_error("usage: procstat [-CHhn] [-M core] [-N system] " 52 "[-w interval]\n" 53 " [-b | -c | -e | -f | -i | -j | -k | " 54 "-l | -r | -s | -S | -t | -v | -x]\n" 55 " [-a | pid | core ...]\n"); 56 xo_finish(); 57 exit(EX_USAGE); 58 } 59 60 static void 61 procstat(struct procstat *prstat, struct kinfo_proc *kipp) 62 { 63 char *pidstr = NULL; 64 65 asprintf(&pidstr, "%d", kipp->ki_pid); 66 if (pidstr == NULL) 67 xo_errc(1, ENOMEM, "Failed to allocate memory in procstat()"); 68 xo_open_container(pidstr); 69 70 if (bflag) 71 procstat_bin(prstat, kipp); 72 else if (cflag) 73 procstat_args(prstat, kipp); 74 else if (eflag) 75 procstat_env(prstat, kipp); 76 else if (fflag) 77 procstat_files(prstat, kipp); 78 else if (iflag) 79 procstat_sigs(prstat, kipp); 80 else if (jflag) 81 procstat_threads_sigs(prstat, kipp); 82 else if (kflag) 83 procstat_kstack(prstat, kipp, kflag); 84 else if (lflag) 85 procstat_rlimit(prstat, kipp); 86 else if (rflag) 87 procstat_rusage(prstat, kipp); 88 else if (sflag) 89 procstat_cred(prstat, kipp); 90 else if (tflag) 91 procstat_threads(prstat, kipp); 92 else if (vflag) 93 procstat_vm(prstat, kipp); 94 else if (xflag) 95 procstat_auxv(prstat, kipp); 96 else if (Sflag) 97 procstat_cs(prstat, kipp); 98 else 99 procstat_basic(kipp); 100 101 xo_close_container(pidstr); 102 free(pidstr); 103 } 104 105 /* 106 * Sort processes first by pid and then tid. 107 */ 108 static int 109 kinfo_proc_compare(const void *a, const void *b) 110 { 111 int i; 112 113 i = ((const struct kinfo_proc *)a)->ki_pid - 114 ((const struct kinfo_proc *)b)->ki_pid; 115 if (i != 0) 116 return (i); 117 i = ((const struct kinfo_proc *)a)->ki_tid - 118 ((const struct kinfo_proc *)b)->ki_tid; 119 return (i); 120 } 121 122 void 123 kinfo_proc_sort(struct kinfo_proc *kipp, int count) 124 { 125 126 qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare); 127 } 128 129 int 130 main(int argc, char *argv[]) 131 { 132 int ch, interval, tmp; 133 int i; 134 struct kinfo_proc *p; 135 struct procstat *prstat, *cprstat; 136 long l; 137 pid_t pid; 138 char *dummy; 139 char *nlistf, *memf; 140 const char *xocontainer; 141 int cnt; 142 143 interval = 0; 144 memf = nlistf = NULL; 145 argc = xo_parse_args(argc, argv); 146 xocontainer = "basic"; 147 148 while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { 149 switch (ch) { 150 case 'C': 151 Cflag++; 152 break; 153 154 case 'H': 155 Hflag++; 156 break; 157 158 case 'M': 159 memf = optarg; 160 break; 161 case 'N': 162 nlistf = optarg; 163 break; 164 case 'S': 165 Sflag++; 166 xocontainer = "cs"; 167 break; 168 case 'a': 169 aflag++; 170 break; 171 172 case 'b': 173 bflag++; 174 xocontainer = "binary"; 175 break; 176 177 case 'c': 178 cflag++; 179 xocontainer = "arguments"; 180 break; 181 182 case 'e': 183 eflag++; 184 xocontainer = "environment"; 185 break; 186 187 case 'f': 188 fflag++; 189 xocontainer = "files"; 190 break; 191 192 case 'i': 193 iflag++; 194 xocontainer = "signals"; 195 break; 196 197 case 'j': 198 jflag++; 199 xocontainer = "thread_signals"; 200 break; 201 202 case 'k': 203 kflag++; 204 xocontainer = "kstack"; 205 break; 206 207 case 'l': 208 lflag++; 209 xocontainer = "rlimit"; 210 break; 211 212 case 'n': 213 nflag++; 214 break; 215 216 case 'h': 217 hflag++; 218 break; 219 220 case 'r': 221 rflag++; 222 xocontainer = "rusage"; 223 break; 224 225 case 's': 226 sflag++; 227 xocontainer = "credentials"; 228 break; 229 230 case 't': 231 tflag++; 232 xocontainer = "threads"; 233 break; 234 235 case 'v': 236 vflag++; 237 xocontainer = "vm"; 238 break; 239 240 case 'w': 241 l = strtol(optarg, &dummy, 10); 242 if (*dummy != '\0') 243 usage(); 244 if (l < 1 || l > INT_MAX) 245 usage(); 246 interval = l; 247 break; 248 249 case 'x': 250 xflag++; 251 xocontainer = "auxv"; 252 break; 253 254 case '?': 255 default: 256 usage(); 257 } 258 259 } 260 argc -= optind; 261 argv += optind; 262 263 /* We require that either 0 or 1 mode flags be set. */ 264 tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + 265 lflag + rflag + sflag + tflag + vflag + xflag + Sflag; 266 if (!(tmp == 0 || tmp == 1)) 267 usage(); 268 269 /* We allow -k to be specified up to twice, but not more. */ 270 if (kflag > 2) 271 usage(); 272 273 /* Must specify either the -a flag or a list of pids. */ 274 if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) 275 usage(); 276 277 /* Only allow -C with -f. */ 278 if (Cflag && !fflag) 279 usage(); 280 281 if (memf != NULL) 282 prstat = procstat_open_kvm(nlistf, memf); 283 else 284 prstat = procstat_open_sysctl(); 285 if (prstat == NULL) 286 xo_errx(1, "procstat_open()"); 287 do { 288 xo_set_version(PROCSTAT_XO_VERSION); 289 xo_open_container("procstat"); 290 xo_open_container(xocontainer); 291 292 if (aflag) { 293 p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); 294 if (p == NULL) 295 xo_errx(1, "procstat_getprocs()"); 296 kinfo_proc_sort(p, cnt); 297 for (i = 0; i < cnt; i++) { 298 procstat(prstat, &p[i]); 299 300 /* Suppress header after first process. */ 301 hflag = 1; 302 xo_flush(); 303 } 304 procstat_freeprocs(prstat, p); 305 } 306 for (i = 0; i < argc; i++) { 307 l = strtol(argv[i], &dummy, 10); 308 if (*dummy == '\0') { 309 if (l < 0) 310 usage(); 311 pid = l; 312 313 p = procstat_getprocs(prstat, KERN_PROC_PID, 314 pid, &cnt); 315 if (p == NULL) 316 xo_errx(1, "procstat_getprocs()"); 317 if (cnt != 0) 318 procstat(prstat, p); 319 procstat_freeprocs(prstat, p); 320 } else { 321 cprstat = procstat_open_core(argv[i]); 322 if (cprstat == NULL) { 323 warnx("procstat_open()"); 324 continue; 325 } 326 p = procstat_getprocs(cprstat, KERN_PROC_PID, 327 -1, &cnt); 328 if (p == NULL) 329 xo_errx(1, "procstat_getprocs()"); 330 if (cnt != 0) 331 procstat(cprstat, p); 332 procstat_freeprocs(cprstat, p); 333 procstat_close(cprstat); 334 } 335 /* Suppress header after first process. */ 336 hflag = 1; 337 } 338 339 xo_close_container(xocontainer); 340 xo_close_container("procstat"); 341 xo_finish(); 342 if (interval) 343 sleep(interval); 344 } while (interval); 345 346 procstat_close(prstat); 347 348 exit(0); 349 } 350