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