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