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 42227956Strocinystatic int aflag, bflag, cflag, eflag, fflag, iflag, jflag, kflag, lflag, sflag; 43227956Strocinystatic int tflag, vflag, xflag; 44224859Srwatsonint hflag, nflag, Cflag; 45174199Srwatson 46174199Srwatsonstatic void 47174199Srwatsonusage(void) 48174199Srwatson{ 49174199Srwatson 50224859Srwatson fprintf(stderr, "usage: procstat [-h] [-C] [-M core] [-N system] " 51227838Strociny "[-w interval] \n"); 52227838Strociny fprintf(stderr, " [-b | -c | -e | -f | -i | -j | -k | " 53249686Strociny "-l | -s | -t | -v | -x] [-a | pid | core ...]\n"); 54174199Srwatson exit(EX_USAGE); 55174199Srwatson} 56174199Srwatson 57174199Srwatsonstatic void 58221807Sstasprocstat(struct procstat *prstat, struct kinfo_proc *kipp) 59174199Srwatson{ 60174199Srwatson 61174199Srwatson if (bflag) 62249678Strociny procstat_bin(prstat, kipp); 63174199Srwatson else if (cflag) 64249680Strociny procstat_args(prstat, kipp); 65227838Strociny else if (eflag) 66249680Strociny procstat_env(prstat, kipp); 67174199Srwatson else if (fflag) 68221807Sstas procstat_files(prstat, kipp); 69204879Skib else if (iflag) 70221807Sstas procstat_sigs(prstat, kipp); 71204879Skib else if (jflag) 72221807Sstas procstat_threads_sigs(prstat, kipp); 73174199Srwatson else if (kflag) 74249685Strociny procstat_kstack(prstat, kipp, kflag); 75227956Strociny else if (lflag) 76249675Strociny procstat_rlimit(prstat, kipp); 77174199Srwatson else if (sflag) 78249671Strociny procstat_cred(prstat, kipp); 79174199Srwatson else if (tflag) 80249668Strociny procstat_threads(prstat, kipp); 81174199Srwatson else if (vflag) 82249669Strociny procstat_vm(prstat, kipp); 83227838Strociny else if (xflag) 84249683Strociny procstat_auxv(prstat, kipp); 85174199Srwatson else 86221807Sstas procstat_basic(kipp); 87174199Srwatson} 88174199Srwatson 89174199Srwatson/* 90174199Srwatson * Sort processes first by pid and then tid. 91174199Srwatson */ 92174199Srwatsonstatic int 93174199Srwatsonkinfo_proc_compare(const void *a, const void *b) 94174199Srwatson{ 95174199Srwatson int i; 96174199Srwatson 97176107Sdwmalone i = ((const struct kinfo_proc *)a)->ki_pid - 98176107Sdwmalone ((const struct kinfo_proc *)b)->ki_pid; 99174199Srwatson if (i != 0) 100174199Srwatson return (i); 101176107Sdwmalone i = ((const struct kinfo_proc *)a)->ki_tid - 102176107Sdwmalone ((const struct kinfo_proc *)b)->ki_tid; 103174199Srwatson return (i); 104174199Srwatson} 105174199Srwatson 106174199Srwatsonvoid 107174199Srwatsonkinfo_proc_sort(struct kinfo_proc *kipp, int count) 108174199Srwatson{ 109174199Srwatson 110174199Srwatson qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare); 111174199Srwatson} 112174199Srwatson 113174199Srwatsonint 114174199Srwatsonmain(int argc, char *argv[]) 115174199Srwatson{ 116221807Sstas int ch, interval, tmp; 117221807Sstas int i; 118221807Sstas struct kinfo_proc *p; 119249686Strociny struct procstat *prstat, *cprstat; 120174199Srwatson long l; 121174199Srwatson pid_t pid; 122174199Srwatson char *dummy; 123221807Sstas char *nlistf, *memf; 124221807Sstas int cnt; 125174199Srwatson 126174199Srwatson interval = 0; 127221807Sstas memf = nlistf = NULL; 128227956Strociny while ((ch = getopt(argc, argv, "CN:M:abcefijklhstvw:x")) != -1) { 129174199Srwatson switch (ch) { 130224859Srwatson case 'C': 131224859Srwatson Cflag++; 132224859Srwatson break; 133224859Srwatson 134221807Sstas case 'M': 135221807Sstas memf = optarg; 136221807Sstas break; 137221807Sstas case 'N': 138221807Sstas nlistf = optarg; 139221807Sstas break; 140174199Srwatson case 'a': 141174199Srwatson aflag++; 142174199Srwatson break; 143174199Srwatson 144174199Srwatson case 'b': 145174199Srwatson bflag++; 146174199Srwatson break; 147174199Srwatson 148174199Srwatson case 'c': 149174199Srwatson cflag++; 150174199Srwatson break; 151174199Srwatson 152227838Strociny case 'e': 153227838Strociny eflag++; 154227838Strociny break; 155227838Strociny 156174199Srwatson case 'f': 157174199Srwatson fflag++; 158174199Srwatson break; 159174199Srwatson 160204879Skib case 'i': 161204879Skib iflag++; 162204879Skib break; 163204879Skib 164204879Skib case 'j': 165204879Skib jflag++; 166204879Skib break; 167204879Skib 168174199Srwatson case 'k': 169174199Srwatson kflag++; 170174199Srwatson break; 171174199Srwatson 172227956Strociny case 'l': 173227956Strociny lflag++; 174227956Strociny break; 175227956Strociny 176204879Skib case 'n': 177204879Skib nflag++; 178204879Skib break; 179204879Skib 180174199Srwatson case 'h': 181174199Srwatson hflag++; 182174199Srwatson break; 183174199Srwatson 184174199Srwatson case 's': 185174199Srwatson sflag++; 186174199Srwatson break; 187174199Srwatson 188174199Srwatson case 't': 189174199Srwatson tflag++; 190174199Srwatson break; 191174199Srwatson 192174199Srwatson case 'v': 193174199Srwatson vflag++; 194174199Srwatson break; 195174199Srwatson 196174199Srwatson case 'w': 197174199Srwatson l = strtol(optarg, &dummy, 10); 198174199Srwatson if (*dummy != '\0') 199174199Srwatson usage(); 200174199Srwatson if (l < 1 || l > INT_MAX) 201174199Srwatson usage(); 202174199Srwatson interval = l; 203174199Srwatson break; 204174199Srwatson 205227838Strociny case 'x': 206227838Strociny xflag++; 207227838Strociny break; 208227838Strociny 209174199Srwatson case '?': 210174199Srwatson default: 211174199Srwatson usage(); 212174199Srwatson } 213174199Srwatson 214174199Srwatson } 215174199Srwatson argc -= optind; 216174199Srwatson argv += optind; 217174199Srwatson 218174199Srwatson /* We require that either 0 or 1 mode flags be set. */ 219245345Smjg tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + 220245345Smjg lflag + sflag + tflag + vflag + xflag; 221174199Srwatson if (!(tmp == 0 || tmp == 1)) 222174199Srwatson usage(); 223174199Srwatson 224174199Srwatson /* We allow -k to be specified up to twice, but not more. */ 225174199Srwatson if (kflag > 2) 226174199Srwatson usage(); 227174199Srwatson 228174199Srwatson /* Must specify either the -a flag or a list of pids. */ 229174199Srwatson if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) 230174199Srwatson usage(); 231174199Srwatson 232224859Srwatson /* Only allow -C with -f. */ 233224859Srwatson if (Cflag && !fflag) 234224859Srwatson usage(); 235224859Srwatson 236221807Sstas if (memf != NULL) 237221807Sstas prstat = procstat_open_kvm(nlistf, memf); 238221807Sstas else 239221807Sstas prstat = procstat_open_sysctl(); 240221807Sstas if (prstat == NULL) 241221807Sstas errx(1, "procstat_open()"); 242174199Srwatson do { 243174199Srwatson if (aflag) { 244221807Sstas p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); 245221807Sstas if (p == NULL) 246221807Sstas errx(1, "procstat_getprocs()"); 247221807Sstas kinfo_proc_sort(p, cnt); 248221807Sstas for (i = 0; i < cnt; i++) { 249221807Sstas procstat(prstat, &p[i]); 250174199Srwatson 251174199Srwatson /* Suppress header after first process. */ 252174199Srwatson hflag = 1; 253174199Srwatson } 254221807Sstas procstat_freeprocs(prstat, p); 255174199Srwatson } 256221807Sstas for (i = 0; i < argc; i++) { 257174199Srwatson l = strtol(argv[i], &dummy, 10); 258249686Strociny if (*dummy == '\0') { 259249686Strociny if (l < 0) 260249686Strociny usage(); 261249686Strociny pid = l; 262174199Srwatson 263249686Strociny p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); 264249686Strociny if (p == NULL) 265249686Strociny errx(1, "procstat_getprocs()"); 266249686Strociny if (cnt != 0) 267249686Strociny procstat(prstat, p); 268249686Strociny procstat_freeprocs(prstat, p); 269249686Strociny } else { 270249686Strociny cprstat = procstat_open_core(argv[i]); 271249686Strociny if (cprstat == NULL) { 272249686Strociny warnx("procstat_open()"); 273249686Strociny continue; 274249686Strociny } 275249686Strociny p = procstat_getprocs(cprstat, KERN_PROC_PID, 276249686Strociny -1, &cnt); 277249686Strociny if (p == NULL) 278249686Strociny errx(1, "procstat_getprocs()"); 279249686Strociny if (cnt != 0) 280249686Strociny procstat(cprstat, p); 281249686Strociny procstat_freeprocs(cprstat, p); 282249686Strociny procstat_close(cprstat); 283249686Strociny } 284174199Srwatson /* Suppress header after first process. */ 285174199Srwatson hflag = 1; 286174199Srwatson } 287174199Srwatson if (interval) 288174199Srwatson sleep(interval); 289174199Srwatson } while (interval); 290221807Sstas procstat_close(prstat); 291174199Srwatson exit(0); 292174199Srwatson} 293