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; 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 | -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 89 procstat_basic(kipp); 90 } 91 92 /* 93 * Sort processes first by pid and then tid. 94 */ 95 static int 96 kinfo_proc_compare(const void *a, const void *b) 97 { 98 int i; 99 100 i = ((const struct kinfo_proc *)a)->ki_pid - 101 ((const struct kinfo_proc *)b)->ki_pid; 102 if (i != 0) 103 return (i); 104 i = ((const struct kinfo_proc *)a)->ki_tid - 105 ((const struct kinfo_proc *)b)->ki_tid; 106 return (i); 107 } 108 109 void 110 kinfo_proc_sort(struct kinfo_proc *kipp, int count) 111 { 112 113 qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare); 114 } 115 116 int 117 main(int argc, char *argv[]) 118 { 119 int ch, interval, tmp; 120 int i; 121 struct kinfo_proc *p; 122 struct procstat *prstat, *cprstat; 123 long l; 124 pid_t pid; 125 char *dummy; 126 char *nlistf, *memf; 127 int cnt; 128 129 interval = 0; 130 memf = nlistf = NULL; 131 while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrstvw:x")) != -1) { 132 switch (ch) { 133 case 'C': 134 Cflag++; 135 break; 136 137 case 'H': 138 Hflag++; 139 break; 140 141 case 'M': 142 memf = optarg; 143 break; 144 case 'N': 145 nlistf = optarg; 146 break; 147 case 'a': 148 aflag++; 149 break; 150 151 case 'b': 152 bflag++; 153 break; 154 155 case 'c': 156 cflag++; 157 break; 158 159 case 'e': 160 eflag++; 161 break; 162 163 case 'f': 164 fflag++; 165 break; 166 167 case 'i': 168 iflag++; 169 break; 170 171 case 'j': 172 jflag++; 173 break; 174 175 case 'k': 176 kflag++; 177 break; 178 179 case 'l': 180 lflag++; 181 break; 182 183 case 'n': 184 nflag++; 185 break; 186 187 case 'h': 188 hflag++; 189 break; 190 191 case 'r': 192 rflag++; 193 break; 194 195 case 's': 196 sflag++; 197 break; 198 199 case 't': 200 tflag++; 201 break; 202 203 case 'v': 204 vflag++; 205 break; 206 207 case 'w': 208 l = strtol(optarg, &dummy, 10); 209 if (*dummy != '\0') 210 usage(); 211 if (l < 1 || l > INT_MAX) 212 usage(); 213 interval = l; 214 break; 215 216 case 'x': 217 xflag++; 218 break; 219 220 case '?': 221 default: 222 usage(); 223 } 224 225 } 226 argc -= optind; 227 argv += optind; 228 229 /* We require that either 0 or 1 mode flags be set. */ 230 tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + 231 lflag + rflag + sflag + tflag + vflag + xflag; 232 if (!(tmp == 0 || tmp == 1)) 233 usage(); 234 235 /* We allow -k to be specified up to twice, but not more. */ 236 if (kflag > 2) 237 usage(); 238 239 /* Must specify either the -a flag or a list of pids. */ 240 if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) 241 usage(); 242 243 /* Only allow -C with -f. */ 244 if (Cflag && !fflag) 245 usage(); 246 247 if (memf != NULL) 248 prstat = procstat_open_kvm(nlistf, memf); 249 else 250 prstat = procstat_open_sysctl(); 251 if (prstat == NULL) 252 errx(1, "procstat_open()"); 253 do { 254 if (aflag) { 255 p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); 256 if (p == NULL) 257 errx(1, "procstat_getprocs()"); 258 kinfo_proc_sort(p, cnt); 259 for (i = 0; i < cnt; i++) { 260 procstat(prstat, &p[i]); 261 262 /* Suppress header after first process. */ 263 hflag = 1; 264 } 265 procstat_freeprocs(prstat, p); 266 } 267 for (i = 0; i < argc; i++) { 268 l = strtol(argv[i], &dummy, 10); 269 if (*dummy == '\0') { 270 if (l < 0) 271 usage(); 272 pid = l; 273 274 p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); 275 if (p == NULL) 276 errx(1, "procstat_getprocs()"); 277 if (cnt != 0) 278 procstat(prstat, p); 279 procstat_freeprocs(prstat, p); 280 } else { 281 cprstat = procstat_open_core(argv[i]); 282 if (cprstat == NULL) { 283 warnx("procstat_open()"); 284 continue; 285 } 286 p = procstat_getprocs(cprstat, KERN_PROC_PID, 287 -1, &cnt); 288 if (p == NULL) 289 errx(1, "procstat_getprocs()"); 290 if (cnt != 0) 291 procstat(cprstat, p); 292 procstat_freeprocs(cprstat, p); 293 procstat_close(cprstat); 294 } 295 /* Suppress header after first process. */ 296 hflag = 1; 297 } 298 if (interval) 299 sleep(interval); 300 } while (interval); 301 procstat_close(prstat); 302 exit(0); 303 } 304