1174199Srwatson/*- 2224859Srwatson * Copyright (c) 2007, 2011 Robert N. M. Watson 3174199Srwatson * All rights reserved. 4174199Srwatson * 5174199Srwatson * Redistribution and use in source and binary forms, with or without 6174199Srwatson * modification, are permitted provided that the following conditions 7174199Srwatson * are met: 8174199Srwatson * 1. Redistributions of source code must retain the above copyright 9174199Srwatson * notice, this list of conditions and the following disclaimer. 10174199Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11174199Srwatson * notice, this list of conditions and the following disclaimer in the 12174199Srwatson * documentation and/or other materials provided with the distribution. 13174199Srwatson * 14174199Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15174199Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16174199Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17174199Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18174199Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19174199Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20174199Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21174199Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22174199Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23174199Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24174199Srwatson * SUCH DAMAGE. 25174199Srwatson * 26174199Srwatson * $FreeBSD$ 27174199Srwatson */ 28174199Srwatson 29186567Srwatson#include <sys/param.h> 30174199Srwatson#include <sys/sysctl.h> 31174199Srwatson#include <sys/user.h> 32174199Srwatson 33174199Srwatson#include <err.h> 34221807Sstas#include <libprocstat.h> 35174199Srwatson#include <stdio.h> 36174199Srwatson#include <stdlib.h> 37174199Srwatson#include <sysexits.h> 38174199Srwatson#include <unistd.h> 39174199Srwatson 40174199Srwatson#include "procstat.h" 41174199Srwatson 42267979Sjhbstatic int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, rflag; 43267979Sjhbstatic int sflag, tflag, vflag, xflag; 44267979Sjhbint hflag, nflag, Cflag, Hflag; 45174199Srwatson 46174199Srwatsonstatic void 47174199Srwatsonusage(void) 48174199Srwatson{ 49174199Srwatson 50267979Sjhb fprintf(stderr, "usage: procstat [-CHhn] [-M core] [-N system] " 51227838Strociny "[-w interval] \n"); 52227838Strociny fprintf(stderr, " [-b | -c | -e | -f | -i | -j | -k | " 53267979Sjhb "-l | -r | -s | -t | -v | -x]\n"); 54267979Sjhb fprintf(stderr, " [-a | pid | core ...]\n"); 55174199Srwatson exit(EX_USAGE); 56174199Srwatson} 57174199Srwatson 58174199Srwatsonstatic void 59221807Sstasprocstat(struct procstat *prstat, struct kinfo_proc *kipp) 60174199Srwatson{ 61174199Srwatson 62174199Srwatson if (bflag) 63249678Strociny procstat_bin(prstat, kipp); 64174199Srwatson else if (cflag) 65249680Strociny procstat_args(prstat, kipp); 66227838Strociny else if (eflag) 67249680Strociny procstat_env(prstat, kipp); 68174199Srwatson else if (fflag) 69221807Sstas procstat_files(prstat, kipp); 70204879Skib else if (iflag) 71221807Sstas procstat_sigs(prstat, kipp); 72204879Skib else if (jflag) 73221807Sstas procstat_threads_sigs(prstat, kipp); 74174199Srwatson else if (kflag) 75249685Strociny procstat_kstack(prstat, kipp, kflag); 76227956Strociny else if (lflag) 77249675Strociny procstat_rlimit(prstat, kipp); 78267979Sjhb else if (rflag) 79267979Sjhb procstat_rusage(prstat, kipp); 80174199Srwatson else if (sflag) 81249671Strociny procstat_cred(prstat, kipp); 82174199Srwatson else if (tflag) 83249668Strociny procstat_threads(prstat, kipp); 84174199Srwatson else if (vflag) 85249669Strociny procstat_vm(prstat, kipp); 86227838Strociny else if (xflag) 87249683Strociny procstat_auxv(prstat, kipp); 88174199Srwatson else 89221807Sstas procstat_basic(kipp); 90174199Srwatson} 91174199Srwatson 92174199Srwatson/* 93174199Srwatson * Sort processes first by pid and then tid. 94174199Srwatson */ 95174199Srwatsonstatic int 96174199Srwatsonkinfo_proc_compare(const void *a, const void *b) 97174199Srwatson{ 98174199Srwatson int i; 99174199Srwatson 100176107Sdwmalone i = ((const struct kinfo_proc *)a)->ki_pid - 101176107Sdwmalone ((const struct kinfo_proc *)b)->ki_pid; 102174199Srwatson if (i != 0) 103174199Srwatson return (i); 104176107Sdwmalone i = ((const struct kinfo_proc *)a)->ki_tid - 105176107Sdwmalone ((const struct kinfo_proc *)b)->ki_tid; 106174199Srwatson return (i); 107174199Srwatson} 108174199Srwatson 109174199Srwatsonvoid 110174199Srwatsonkinfo_proc_sort(struct kinfo_proc *kipp, int count) 111174199Srwatson{ 112174199Srwatson 113174199Srwatson qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare); 114174199Srwatson} 115174199Srwatson 116174199Srwatsonint 117174199Srwatsonmain(int argc, char *argv[]) 118174199Srwatson{ 119221807Sstas int ch, interval, tmp; 120221807Sstas int i; 121221807Sstas struct kinfo_proc *p; 122249686Strociny struct procstat *prstat, *cprstat; 123174199Srwatson long l; 124174199Srwatson pid_t pid; 125174199Srwatson char *dummy; 126221807Sstas char *nlistf, *memf; 127221807Sstas int cnt; 128174199Srwatson 129174199Srwatson interval = 0; 130221807Sstas memf = nlistf = NULL; 131267979Sjhb while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrstvw:x")) != -1) { 132174199Srwatson switch (ch) { 133224859Srwatson case 'C': 134224859Srwatson Cflag++; 135224859Srwatson break; 136224859Srwatson 137267979Sjhb case 'H': 138267979Sjhb Hflag++; 139267979Sjhb break; 140267979Sjhb 141221807Sstas case 'M': 142221807Sstas memf = optarg; 143221807Sstas break; 144221807Sstas case 'N': 145221807Sstas nlistf = optarg; 146221807Sstas break; 147174199Srwatson case 'a': 148174199Srwatson aflag++; 149174199Srwatson break; 150174199Srwatson 151174199Srwatson case 'b': 152174199Srwatson bflag++; 153174199Srwatson break; 154174199Srwatson 155174199Srwatson case 'c': 156174199Srwatson cflag++; 157174199Srwatson break; 158174199Srwatson 159227838Strociny case 'e': 160227838Strociny eflag++; 161227838Strociny break; 162227838Strociny 163174199Srwatson case 'f': 164174199Srwatson fflag++; 165174199Srwatson break; 166174199Srwatson 167204879Skib case 'i': 168204879Skib iflag++; 169204879Skib break; 170204879Skib 171204879Skib case 'j': 172204879Skib jflag++; 173204879Skib break; 174204879Skib 175174199Srwatson case 'k': 176174199Srwatson kflag++; 177174199Srwatson break; 178174199Srwatson 179227956Strociny case 'l': 180227956Strociny lflag++; 181227956Strociny break; 182227956Strociny 183204879Skib case 'n': 184204879Skib nflag++; 185204879Skib break; 186204879Skib 187174199Srwatson case 'h': 188174199Srwatson hflag++; 189174199Srwatson break; 190174199Srwatson 191267979Sjhb case 'r': 192267979Sjhb rflag++; 193267979Sjhb break; 194267979Sjhb 195174199Srwatson case 's': 196174199Srwatson sflag++; 197174199Srwatson break; 198174199Srwatson 199174199Srwatson case 't': 200174199Srwatson tflag++; 201174199Srwatson break; 202174199Srwatson 203174199Srwatson case 'v': 204174199Srwatson vflag++; 205174199Srwatson break; 206174199Srwatson 207174199Srwatson case 'w': 208174199Srwatson l = strtol(optarg, &dummy, 10); 209174199Srwatson if (*dummy != '\0') 210174199Srwatson usage(); 211174199Srwatson if (l < 1 || l > INT_MAX) 212174199Srwatson usage(); 213174199Srwatson interval = l; 214174199Srwatson break; 215174199Srwatson 216227838Strociny case 'x': 217227838Strociny xflag++; 218227838Strociny break; 219227838Strociny 220174199Srwatson case '?': 221174199Srwatson default: 222174199Srwatson usage(); 223174199Srwatson } 224174199Srwatson 225174199Srwatson } 226174199Srwatson argc -= optind; 227174199Srwatson argv += optind; 228174199Srwatson 229174199Srwatson /* We require that either 0 or 1 mode flags be set. */ 230245345Smjg tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + 231267979Sjhb lflag + rflag + sflag + tflag + vflag + xflag; 232174199Srwatson if (!(tmp == 0 || tmp == 1)) 233174199Srwatson usage(); 234174199Srwatson 235174199Srwatson /* We allow -k to be specified up to twice, but not more. */ 236174199Srwatson if (kflag > 2) 237174199Srwatson usage(); 238174199Srwatson 239174199Srwatson /* Must specify either the -a flag or a list of pids. */ 240174199Srwatson if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) 241174199Srwatson usage(); 242174199Srwatson 243224859Srwatson /* Only allow -C with -f. */ 244224859Srwatson if (Cflag && !fflag) 245224859Srwatson usage(); 246224859Srwatson 247221807Sstas if (memf != NULL) 248221807Sstas prstat = procstat_open_kvm(nlistf, memf); 249221807Sstas else 250221807Sstas prstat = procstat_open_sysctl(); 251221807Sstas if (prstat == NULL) 252221807Sstas errx(1, "procstat_open()"); 253174199Srwatson do { 254174199Srwatson if (aflag) { 255221807Sstas p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); 256221807Sstas if (p == NULL) 257221807Sstas errx(1, "procstat_getprocs()"); 258221807Sstas kinfo_proc_sort(p, cnt); 259221807Sstas for (i = 0; i < cnt; i++) { 260221807Sstas procstat(prstat, &p[i]); 261174199Srwatson 262174199Srwatson /* Suppress header after first process. */ 263174199Srwatson hflag = 1; 264174199Srwatson } 265221807Sstas procstat_freeprocs(prstat, p); 266174199Srwatson } 267221807Sstas for (i = 0; i < argc; i++) { 268174199Srwatson l = strtol(argv[i], &dummy, 10); 269249686Strociny if (*dummy == '\0') { 270249686Strociny if (l < 0) 271249686Strociny usage(); 272249686Strociny pid = l; 273174199Srwatson 274249686Strociny p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); 275249686Strociny if (p == NULL) 276249686Strociny errx(1, "procstat_getprocs()"); 277249686Strociny if (cnt != 0) 278249686Strociny procstat(prstat, p); 279249686Strociny procstat_freeprocs(prstat, p); 280249686Strociny } else { 281249686Strociny cprstat = procstat_open_core(argv[i]); 282249686Strociny if (cprstat == NULL) { 283249686Strociny warnx("procstat_open()"); 284249686Strociny continue; 285249686Strociny } 286249686Strociny p = procstat_getprocs(cprstat, KERN_PROC_PID, 287249686Strociny -1, &cnt); 288249686Strociny if (p == NULL) 289249686Strociny errx(1, "procstat_getprocs()"); 290249686Strociny if (cnt != 0) 291249686Strociny procstat(cprstat, p); 292249686Strociny procstat_freeprocs(cprstat, p); 293249686Strociny procstat_close(cprstat); 294249686Strociny } 295174199Srwatson /* Suppress header after first process. */ 296174199Srwatson hflag = 1; 297174199Srwatson } 298174199Srwatson if (interval) 299174199Srwatson sleep(interval); 300174199Srwatson } while (interval); 301221807Sstas procstat_close(prstat); 302174199Srwatson exit(0); 303174199Srwatson} 304