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 <string.h> 39 #include <sysexits.h> 40 #include <unistd.h> 41 42 #include "procstat.h" 43 44 static int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, rflag; 45 static int sflag, tflag, vflag, xflag, Sflag; 46 int hflag, nflag, Cflag, Hflag; 47 48 static void 49 usage(void) 50 { 51 52 xo_error("usage: procstat [-CHhn] [-M core] [-N system] " 53 "[-w interval]\n" 54 " [-b | -c | -e | -f | -i | -j | -k | " 55 "-l | -r | -s | -S | -t | -v | -x]\n" 56 " [-a | pid | core ...]\n"); 57 xo_finish(); 58 exit(EX_USAGE); 59 } 60 61 static void 62 procstat(struct procstat *prstat, struct kinfo_proc *kipp) 63 { 64 char *pidstr = NULL; 65 66 asprintf(&pidstr, "%d", kipp->ki_pid); 67 if (pidstr == NULL) 68 xo_errc(1, ENOMEM, "Failed to allocate memory in procstat()"); 69 xo_open_container(pidstr); 70 71 if (bflag) 72 procstat_bin(prstat, kipp); 73 else if (cflag) 74 procstat_args(prstat, kipp); 75 else if (eflag) 76 procstat_env(prstat, kipp); 77 else if (fflag) 78 procstat_files(prstat, kipp); 79 else if (iflag) 80 procstat_sigs(prstat, kipp); 81 else if (jflag) 82 procstat_threads_sigs(prstat, kipp); 83 else if (kflag) 84 procstat_kstack(prstat, kipp, kflag); 85 else if (lflag) 86 procstat_rlimit(prstat, kipp); 87 else if (rflag) 88 procstat_rusage(prstat, kipp); 89 else if (sflag) 90 procstat_cred(prstat, kipp); 91 else if (tflag) 92 procstat_threads(prstat, kipp); 93 else if (vflag) 94 procstat_vm(prstat, kipp); 95 else if (xflag) 96 procstat_auxv(prstat, kipp); 97 else if (Sflag) 98 procstat_cs(prstat, kipp); 99 else 100 procstat_basic(kipp); 101 102 xo_close_container(pidstr); 103 free(pidstr); 104 } 105 106 /* 107 * Sort processes first by pid and then tid. 108 */ 109 static int 110 kinfo_proc_compare(const void *a, const void *b) 111 { 112 int i; 113 114 i = ((const struct kinfo_proc *)a)->ki_pid - 115 ((const struct kinfo_proc *)b)->ki_pid; 116 if (i != 0) 117 return (i); 118 i = ((const struct kinfo_proc *)a)->ki_tid - 119 ((const struct kinfo_proc *)b)->ki_tid; 120 return (i); 121 } 122 123 void 124 kinfo_proc_sort(struct kinfo_proc *kipp, int count) 125 { 126 127 qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare); 128 } 129 130 const char * 131 kinfo_proc_thread_name(const struct kinfo_proc *kipp) 132 { 133 static char name[MAXCOMLEN+1]; 134 135 strlcpy(name, kipp->ki_tdname, sizeof(name)); 136 strlcat(name, kipp->ki_moretdname, sizeof(name)); 137 if (name[0] == '\0' || strcmp(kipp->ki_comm, name) == 0) { 138 name[0] = '-'; 139 name[1] = '\0'; 140 } 141 142 return (name); 143 } 144 145 int 146 main(int argc, char *argv[]) 147 { 148 int ch, interval, tmp; 149 int i; 150 struct kinfo_proc *p; 151 struct procstat *prstat, *cprstat; 152 long l; 153 pid_t pid; 154 char *dummy; 155 char *nlistf, *memf; 156 const char *xocontainer; 157 int cnt; 158 159 interval = 0; 160 memf = nlistf = NULL; 161 argc = xo_parse_args(argc, argv); 162 xocontainer = "basic"; 163 164 while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { 165 switch (ch) { 166 case 'C': 167 Cflag++; 168 break; 169 170 case 'H': 171 Hflag++; 172 break; 173 174 case 'M': 175 memf = optarg; 176 break; 177 case 'N': 178 nlistf = optarg; 179 break; 180 case 'S': 181 Sflag++; 182 xocontainer = "cs"; 183 break; 184 case 'a': 185 aflag++; 186 break; 187 188 case 'b': 189 bflag++; 190 xocontainer = "binary"; 191 break; 192 193 case 'c': 194 cflag++; 195 xocontainer = "arguments"; 196 break; 197 198 case 'e': 199 eflag++; 200 xocontainer = "environment"; 201 break; 202 203 case 'f': 204 fflag++; 205 xocontainer = "files"; 206 break; 207 208 case 'i': 209 iflag++; 210 xocontainer = "signals"; 211 break; 212 213 case 'j': 214 jflag++; 215 xocontainer = "thread_signals"; 216 break; 217 218 case 'k': 219 kflag++; 220 xocontainer = "kstack"; 221 break; 222 223 case 'l': 224 lflag++; 225 xocontainer = "rlimit"; 226 break; 227 228 case 'n': 229 nflag++; 230 break; 231 232 case 'h': 233 hflag++; 234 break; 235 236 case 'r': 237 rflag++; 238 xocontainer = "rusage"; 239 break; 240 241 case 's': 242 sflag++; 243 xocontainer = "credentials"; 244 break; 245 246 case 't': 247 tflag++; 248 xocontainer = "threads"; 249 break; 250 251 case 'v': 252 vflag++; 253 xocontainer = "vm"; 254 break; 255 256 case 'w': 257 l = strtol(optarg, &dummy, 10); 258 if (*dummy != '\0') 259 usage(); 260 if (l < 1 || l > INT_MAX) 261 usage(); 262 interval = l; 263 break; 264 265 case 'x': 266 xflag++; 267 xocontainer = "auxv"; 268 break; 269 270 case '?': 271 default: 272 usage(); 273 } 274 275 } 276 argc -= optind; 277 argv += optind; 278 279 /* We require that either 0 or 1 mode flags be set. */ 280 tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + 281 lflag + rflag + sflag + tflag + vflag + xflag + Sflag; 282 if (!(tmp == 0 || tmp == 1)) 283 usage(); 284 285 /* We allow -k to be specified up to twice, but not more. */ 286 if (kflag > 2) 287 usage(); 288 289 /* Must specify either the -a flag or a list of pids. */ 290 if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) 291 usage(); 292 293 /* Only allow -C with -f. */ 294 if (Cflag && !fflag) 295 usage(); 296 297 if (memf != NULL) 298 prstat = procstat_open_kvm(nlistf, memf); 299 else 300 prstat = procstat_open_sysctl(); 301 if (prstat == NULL) 302 xo_errx(1, "procstat_open()"); 303 do { 304 xo_set_version(PROCSTAT_XO_VERSION); 305 xo_open_container("procstat"); 306 xo_open_container(xocontainer); 307 308 if (aflag) { 309 p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); 310 if (p == NULL) 311 xo_errx(1, "procstat_getprocs()"); 312 kinfo_proc_sort(p, cnt); 313 for (i = 0; i < cnt; i++) { 314 procstat(prstat, &p[i]); 315 316 /* Suppress header after first process. */ 317 hflag = 1; 318 xo_flush(); 319 } 320 procstat_freeprocs(prstat, p); 321 } 322 for (i = 0; i < argc; i++) { 323 l = strtol(argv[i], &dummy, 10); 324 if (*dummy == '\0') { 325 if (l < 0) 326 usage(); 327 pid = l; 328 329 p = procstat_getprocs(prstat, KERN_PROC_PID, 330 pid, &cnt); 331 if (p == NULL) 332 xo_errx(1, "procstat_getprocs()"); 333 if (cnt != 0) 334 procstat(prstat, p); 335 procstat_freeprocs(prstat, p); 336 } else { 337 cprstat = procstat_open_core(argv[i]); 338 if (cprstat == NULL) { 339 warnx("procstat_open()"); 340 continue; 341 } 342 p = procstat_getprocs(cprstat, KERN_PROC_PID, 343 -1, &cnt); 344 if (p == NULL) 345 xo_errx(1, "procstat_getprocs()"); 346 if (cnt != 0) 347 procstat(cprstat, p); 348 procstat_freeprocs(cprstat, p); 349 procstat_close(cprstat); 350 } 351 /* Suppress header after first process. */ 352 hflag = 1; 353 } 354 355 xo_close_container(xocontainer); 356 xo_close_container("procstat"); 357 xo_finish(); 358 if (interval) 359 sleep(interval); 360 } while (interval); 361 362 procstat_close(prstat); 363 364 exit(0); 365 } 366