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