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