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