]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/systat/main.c
sys/{x86,amd64}: remove one of doubled ;s
[FreeBSD/FreeBSD.git] / usr.bin / systat / main.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33
34 __FBSDID("$FreeBSD$");
35
36 #ifdef lint
37 static const char sccsid[] = "@(#)main.c        8.1 (Berkeley) 6/6/93";
38 #endif
39
40 #ifndef lint
41 static const char copyright[] =
42 "@(#) Copyright (c) 1980, 1992, 1993\n\
43         The Regents of the University of California.  All rights reserved.\n";
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/sysctl.h>
49 #include <sys/queue.h>
50
51 #include <err.h>
52 #include <limits.h>
53 #include <locale.h>
54 #include <nlist.h>
55 #include <paths.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include "systat.h"
63 #include "extern.h"
64
65 static int     dellave;
66
67 kvm_t *kd;
68 sig_t   sigtstpdfl;
69 double avenrun[3];
70 int     col;
71 unsigned int    delay = 5000000;        /* in microseconds */
72 int     verbose = 1;                    /* to report kvm read errs */
73 struct  clockinfo clkinfo;
74 double  hertz;
75 char    c;
76 char    *namp;
77 char    hostname[MAXHOSTNAMELEN];
78 WINDOW  *wnd;
79 int     CMDLINE;
80 int     use_kvm = 1;
81
82 static  WINDOW *wload;                  /* one line window for load average */
83
84 struct cmdentry {
85         SLIST_ENTRY(cmdentry) link;
86         char            *cmd;           /* Command name */
87         char            *argv;          /* Arguments vector for a command */
88 };
89 SLIST_HEAD(, cmdentry) commands;
90
91 static void
92 parse_cmd_args (int argc, char **argv)
93 {
94         int in_command = 0;
95         struct cmdentry *cmd = NULL;
96         double t;
97
98         while (argc) {
99                 if (argv[0][0] == '-') {
100                         if (in_command)
101                                         SLIST_INSERT_HEAD(&commands, cmd, link);
102
103                         if (memcmp(argv[0], "--", 3) == 0) {
104                                 in_command = 0; /*-- ends a command explicitly*/
105                                 argc --, argv ++;
106                                 continue;
107                         }
108                         cmd = calloc(1, sizeof(struct cmdentry));
109                         if (cmd == NULL)
110                                 errx(1, "memory allocating failure");
111                         cmd->cmd = strdup(&argv[0][1]);
112                         if (cmd->cmd == NULL)
113                                 errx(1, "memory allocating failure");
114                         in_command = 1;
115                 }
116                 else if (!in_command) {
117                         t = strtod(argv[0], NULL) * 1000000.0;
118                         if (t > 0 && t < (double)UINT_MAX)
119                                 delay = (unsigned int)t;
120                 }
121                 else if (cmd != NULL) {
122                         cmd->argv = strdup(argv[0]);
123                         if (cmd->argv == NULL)
124                                 errx(1, "memory allocating failure");
125                         in_command = 0;
126                         SLIST_INSERT_HEAD(&commands, cmd, link);
127                 }
128                 else
129                         errx(1, "invalid arguments list");
130
131                 argc--, argv++;
132         }
133         if (in_command && cmd != NULL)
134                 SLIST_INSERT_HEAD(&commands, cmd, link);
135
136 }
137
138 int
139 main(int argc, char **argv)
140 {
141         char errbuf[_POSIX2_LINE_MAX], dummy;
142         size_t  size;
143         struct cmdentry *cmd = NULL;
144
145         (void) setlocale(LC_ALL, "");
146
147         SLIST_INIT(&commands);
148         argc--, argv++;
149         if (argc > 0) {
150                 if (argv[0][0] == '-') {
151                         struct cmdtab *p;
152
153                         p = lookup(&argv[0][1]);
154                         if (p == (struct cmdtab *)-1)
155                                 errx(1, "%s: ambiguous request", &argv[0][1]);
156                         if (p == (struct cmdtab *)0)
157                                 errx(1, "%s: unknown request", &argv[0][1]);
158                         curcmd = p;
159                         argc--, argv++;
160                 }
161                 parse_cmd_args (argc, argv);
162                 
163         }
164         kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
165         if (kd != NULL) {
166                 /*
167                  * Try to actually read something, we may be in a jail, and
168                  * have /dev/null opened as /dev/mem.
169                  */
170                 if (kvm_nlist(kd, namelist) != 0 || namelist[0].n_value == 0 ||
171                     kvm_read(kd, namelist[0].n_value, &dummy, sizeof(dummy)) !=
172                     sizeof(dummy)) {
173                         kvm_close(kd);
174                         kd = NULL;
175                 }
176         }
177         if (kd == NULL) {
178                 /*
179                  * Maybe we are lacking permissions? Retry, this time with bogus
180                  * devices. We can now use sysctl only.
181                  */
182                 use_kvm = 0;
183                 kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL,
184                     O_RDONLY, errbuf);
185                 if (kd == NULL) {
186                         error("%s", errbuf);
187                         exit(1);
188                 }
189         }
190         signal(SIGHUP, die);
191         signal(SIGINT, die);
192         signal(SIGQUIT, die);
193         signal(SIGTERM, die);
194
195         /*
196          * Initialize display.  Load average appears in a one line
197          * window of its own.  Current command's display appears in
198          * an overlapping sub-window of stdscr configured by the display
199          * routines to minimize update work by curses.
200          */
201         initscr();
202         CMDLINE = LINES - 1;
203         wnd = (*curcmd->c_open)();
204         if (wnd == NULL) {
205                 warnx("couldn't initialize display");
206                 die(0);
207         }
208         wload = newwin(1, 0, 1, 20);
209         if (wload == NULL) {
210                 warnx("couldn't set up load average window");
211                 die(0);
212         }
213         gethostname(hostname, sizeof (hostname));
214         size = sizeof(clkinfo);
215         if (sysctlbyname("kern.clockrate", &clkinfo, &size, NULL, 0)
216             || size != sizeof(clkinfo)) {
217                 error("kern.clockrate");
218                 die(0);
219         }
220         hertz = clkinfo.stathz;
221         (*curcmd->c_init)();
222         curcmd->c_flags |= CF_INIT;
223         labels();
224
225         if (curcmd->c_cmd != NULL)
226                 SLIST_FOREACH (cmd, &commands, link)
227                         if (!curcmd->c_cmd(cmd->cmd, cmd->argv))
228                                 warnx("command is not understood");
229
230         dellave = 0.0;
231         display();
232         noecho();
233         crmode();
234         keyboard();
235         /*NOTREACHED*/
236
237         return EXIT_SUCCESS;
238 }
239
240 void
241 labels(void)
242 {
243         if (curcmd->c_flags & CF_LOADAV) {
244                 mvaddstr(0, 20,
245                     "/0   /1   /2   /3   /4   /5   /6   /7   /8   /9   /10");
246                 mvaddstr(1, 5, "Load Average");
247         }
248         if (curcmd->c_flags & CF_ZFSARC) {
249                 mvaddstr(0, 20,
250                     "   Total     MFU     MRU    Anon     Hdr   L2Hdr   Other");
251                 mvaddstr(1, 5, "ZFS ARC     ");
252         }
253         (*curcmd->c_label)();
254 #ifdef notdef
255         mvprintw(21, 25, "CPU usage on %s", hostname);
256 #endif
257         refresh();
258 }
259
260 void
261 display(void)
262 {
263         uint64_t arc_stat;
264         int i, j;
265
266         /* Get the load average over the last minute. */
267         (void) getloadavg(avenrun, nitems(avenrun));
268         (*curcmd->c_fetch)();
269         if (curcmd->c_flags & CF_LOADAV) {
270                 j = 5.0*avenrun[0] + 0.5;
271                 dellave -= avenrun[0];
272                 if (dellave >= 0.0)
273                         c = '<';
274                 else {
275                         c = '>';
276                         dellave = -dellave;
277                 }
278                 if (dellave < 0.1)
279                         c = '|';
280                 dellave = avenrun[0];
281                 wmove(wload, 0, 0); wclrtoeol(wload);
282                 for (i = MIN(j, 50); i > 0; i--)
283                         waddch(wload, c);
284                 if (j > 50)
285                         wprintw(wload, " %4.1f", avenrun[0]);
286         }
287         if (curcmd->c_flags & CF_ZFSARC) {
288             uint64_t arc[7] = {};
289             size_t size = sizeof(arc[0]);
290             if (sysctlbyname("kstat.zfs.misc.arcstats.size",
291                 &arc[0], &size, NULL, 0) == 0 ) {
292                     GETSYSCTL("vfs.zfs.mfu_size", arc[1]);
293                     GETSYSCTL("vfs.zfs.mru_size", arc[2]);
294                     GETSYSCTL("vfs.zfs.anon_size", arc[3]);
295                     GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]);
296                     GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]);
297                     GETSYSCTL("kstat.zfs.misc.arcstats.bonus_size", arc[6]);
298                     GETSYSCTL("kstat.zfs.misc.arcstats.dnode_size", arc_stat);
299                     arc[6] += arc_stat;
300                     GETSYSCTL("kstat.zfs.misc.arcstats.dbuf_size", arc_stat);
301                     arc[6] += arc_stat;
302                     wmove(wload, 0, 0); wclrtoeol(wload);
303                     for (i = 0 ; i < nitems(arc); i++) {
304                         if (arc[i] > 10llu * 1024 * 1024 * 1024 ) {
305                                 wprintw(wload, "%7lluG", arc[i] >> 30);
306                         }
307                         else if (arc[i] > 10 * 1024 * 1024 ) {
308                                 wprintw(wload, "%7lluM", arc[i] >> 20);
309                         }
310                         else {
311                                 wprintw(wload, "%7lluK", arc[i] >> 10);
312                         }
313                     }
314             }
315         }
316         (*curcmd->c_refresh)();
317         if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC))
318                 wrefresh(wload);
319         wrefresh(wnd);
320         move(CMDLINE, col);
321         refresh();
322 }
323
324 void
325 load(void)
326 {
327
328         (void) getloadavg(avenrun, nitems(avenrun));
329         mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f",
330             avenrun[0], avenrun[1], avenrun[2]);
331         clrtoeol();
332 }
333
334 void
335 die(int signo __unused)
336 {
337         move(CMDLINE, 0);
338         clrtoeol();
339         refresh();
340         endwin();
341         exit(0);
342 }
343
344 #include <stdarg.h>
345
346 void
347 error(const char *fmt, ...)
348 {
349         va_list ap;
350         char buf[255];
351         int oy, ox;
352
353         va_start(ap, fmt);
354         if (wnd) {
355                 getyx(stdscr, oy, ox);
356                 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
357                 clrtoeol();
358                 standout();
359                 mvaddstr(CMDLINE, 0, buf);
360                 standend();
361                 move(oy, ox);
362                 refresh();
363         } else {
364                 (void) vfprintf(stderr, fmt, ap);
365                 fprintf(stderr, "\n");
366         }
367         va_end(ap);
368 }
369
370 void
371 nlisterr(struct nlist n_list[])
372 {
373         int i, n;
374
375         n = 0;
376         clear();
377         mvprintw(2, 10, "systat: nlist: can't find following symbols:");
378         for (i = 0;
379             n_list[i].n_name != NULL && *n_list[i].n_name != '\0'; i++)
380                 if (n_list[i].n_value == 0)
381                         mvprintw(2 + ++n, 10, "%s", n_list[i].n_name);
382         move(CMDLINE, 0);
383         clrtoeol();
384         refresh();
385         endwin();
386         exit(1);
387 }