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