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