11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1992, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 3087715Smarkm#include <sys/cdefs.h> 3187715Smarkm 3287715Smarkm__FBSDID("$FreeBSD: releng/11.0/usr.bin/systat/main.c 298684 2016-04-27 02:26:31Z araujo $"); 3387715Smarkm 3487715Smarkm#ifdef lint 3587715Smarkmstatic const char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 3687715Smarkm#endif 3787715Smarkm 381590Srgrimes#ifndef lint 3987715Smarkmstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1980, 1992, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4228149Scharnier#endif 431590Srgrimes 441590Srgrimes#include <sys/param.h> 4570118Srwatson#include <sys/time.h> 4674671Stmm#include <sys/sysctl.h> 47265782Smelifaro#include <sys/queue.h> 481590Srgrimes 4928149Scharnier#include <err.h> 5077205Stmm#include <limits.h> 5114953Sache#include <locale.h> 521590Srgrimes#include <nlist.h> 53200462Sdelphij#include <paths.h> 541590Srgrimes#include <signal.h> 551590Srgrimes#include <stdio.h> 5640060Sobrien#include <stdlib.h> 57265782Smelifaro#include <string.h> 5840060Sobrien#include <unistd.h> 5987715Smarkm 601590Srgrimes#include "systat.h" 611590Srgrimes#include "extern.h" 621590Srgrimes 631590Srgrimesstatic int dellave; 641590Srgrimes 651590Srgrimeskvm_t *kd; 661590Srgrimessig_t sigtstpdfl; 671590Srgrimesdouble avenrun[3]; 681590Srgrimesint col; 69240605Smelifarounsigned int delay = 5000000; /* in microseconds */ 701590Srgrimesint verbose = 1; /* to report kvm read errs */ 7170118Srwatsonstruct clockinfo clkinfo; 724930Sbdedouble hertz; 731590Srgrimeschar c; 741590Srgrimeschar *namp; 751590Srgrimeschar hostname[MAXHOSTNAMELEN]; 761590SrgrimesWINDOW *wnd; 771590Srgrimesint CMDLINE; 7874671Stmmint use_kvm = 1; 791590Srgrimes 801590Srgrimesstatic WINDOW *wload; /* one line window for load average */ 811590Srgrimes 82265782Smelifarostruct cmdentry { 83265782Smelifaro SLIST_ENTRY(cmdentry) link; 84265782Smelifaro char *cmd; /* Command name */ 85265782Smelifaro char *argv; /* Arguments vector for a command */ 86265782Smelifaro}; 87265782SmelifaroSLIST_HEAD(, cmdentry) commands; 88265782Smelifaro 89265782Smelifarostatic void 90265782Smelifaroparse_cmd_args (int argc, char **argv) 91265782Smelifaro{ 92265782Smelifaro int in_command = 0; 93265782Smelifaro struct cmdentry *cmd = NULL; 94265782Smelifaro double t; 95265782Smelifaro 96265782Smelifaro while (argc) { 97265782Smelifaro if (argv[0][0] == '-') { 98265782Smelifaro if (in_command) 99265782Smelifaro SLIST_INSERT_HEAD(&commands, cmd, link); 100265782Smelifaro 101265782Smelifaro if (memcmp(argv[0], "--", 3) == 0) { 102265782Smelifaro in_command = 0; /*-- ends a command explicitly*/ 103265782Smelifaro argc --, argv ++; 104265782Smelifaro continue; 105265782Smelifaro } 106265782Smelifaro cmd = calloc(1, sizeof(struct cmdentry)); 107265782Smelifaro if (cmd == NULL) 108265782Smelifaro errx(1, "memory allocating failure"); 109265782Smelifaro cmd->cmd = strdup(&argv[0][1]); 110265782Smelifaro if (cmd->cmd == NULL) 111265782Smelifaro errx(1, "memory allocating failure"); 112265782Smelifaro in_command = 1; 113265782Smelifaro } 114265782Smelifaro else if (!in_command) { 115265782Smelifaro t = strtod(argv[0], NULL) * 1000000.0; 116265782Smelifaro if (t > 0 && t < (double)UINT_MAX) 117265782Smelifaro delay = (unsigned int)t; 118265782Smelifaro } 119265782Smelifaro else if (cmd != NULL) { 120265782Smelifaro cmd->argv = strdup(argv[0]); 121265782Smelifaro if (cmd->argv == NULL) 122265782Smelifaro errx(1, "memory allocating failure"); 123265782Smelifaro in_command = 0; 124265782Smelifaro SLIST_INSERT_HEAD(&commands, cmd, link); 125265782Smelifaro } 126265782Smelifaro else 127265782Smelifaro errx(1, "invalid arguments list"); 128265782Smelifaro 129265782Smelifaro argc--, argv++; 130265782Smelifaro } 131265782Smelifaro if (in_command && cmd != NULL) 132265782Smelifaro SLIST_INSERT_HEAD(&commands, cmd, link); 133265782Smelifaro 134265782Smelifaro} 135265782Smelifaro 13628789Scharnierint 137126775Sdwmalonemain(int argc, char **argv) 1381590Srgrimes{ 13977205Stmm char errbuf[_POSIX2_LINE_MAX], dummy; 14069140Srwatson size_t size; 141265782Smelifaro struct cmdentry *cmd = NULL; 1421590Srgrimes 143199242Sume (void) setlocale(LC_ALL, ""); 14414953Sache 145265782Smelifaro SLIST_INIT(&commands); 1461590Srgrimes argc--, argv++; 147265782Smelifaro if (argc > 0) { 1481590Srgrimes if (argv[0][0] == '-') { 1491590Srgrimes struct cmdtab *p; 1501590Srgrimes 1511590Srgrimes p = lookup(&argv[0][1]); 15228149Scharnier if (p == (struct cmdtab *)-1) 15328149Scharnier errx(1, "%s: ambiguous request", &argv[0][1]); 15428149Scharnier if (p == (struct cmdtab *)0) 15528149Scharnier errx(1, "%s: unknown request", &argv[0][1]); 1561590Srgrimes curcmd = p; 157265782Smelifaro argc--, argv++; 1581590Srgrimes } 159265782Smelifaro parse_cmd_args (argc, argv); 160265782Smelifaro 1611590Srgrimes } 1621590Srgrimes kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 16374671Stmm if (kd != NULL) { 164158161Sbde /* 16574671Stmm * Try to actually read something, we may be in a jail, and 16674671Stmm * have /dev/null opened as /dev/mem. 16774671Stmm */ 168158161Sbde if (kvm_nlist(kd, namelist) != 0 || namelist[0].n_value == 0 || 16974671Stmm kvm_read(kd, namelist[0].n_value, &dummy, sizeof(dummy)) != 17074671Stmm sizeof(dummy)) { 17174671Stmm kvm_close(kd); 17274671Stmm kd = NULL; 17374671Stmm } 17474671Stmm } 1751590Srgrimes if (kd == NULL) { 176158161Sbde /* 17774671Stmm * Maybe we are lacking permissions? Retry, this time with bogus 17874671Stmm * devices. We can now use sysctl only. 17974671Stmm */ 18074671Stmm use_kvm = 0; 181288344Sdelphij kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, 18277205Stmm O_RDONLY, errbuf); 18374671Stmm if (kd == NULL) { 18474671Stmm error("%s", errbuf); 18574671Stmm exit(1); 18674671Stmm } 1871590Srgrimes } 188197956Sjh signal(SIGHUP, die); 1891590Srgrimes signal(SIGINT, die); 1901590Srgrimes signal(SIGQUIT, die); 1911590Srgrimes signal(SIGTERM, die); 1921590Srgrimes 1931590Srgrimes /* 1941590Srgrimes * Initialize display. Load average appears in a one line 1951590Srgrimes * window of its own. Current command's display appears in 1961590Srgrimes * an overlapping sub-window of stdscr configured by the display 1971590Srgrimes * routines to minimize update work by curses. 1981590Srgrimes */ 1991590Srgrimes initscr(); 2001590Srgrimes CMDLINE = LINES - 1; 2011590Srgrimes wnd = (*curcmd->c_open)(); 2021590Srgrimes if (wnd == NULL) { 20328149Scharnier warnx("couldn't initialize display"); 2041590Srgrimes die(0); 2051590Srgrimes } 206158160Sbde wload = newwin(1, 0, 1, 20); 2071590Srgrimes if (wload == NULL) { 20828149Scharnier warnx("couldn't set up load average window"); 2091590Srgrimes die(0); 2101590Srgrimes } 21169140Srwatson gethostname(hostname, sizeof (hostname)); 21269140Srwatson size = sizeof(clkinfo); 21387715Smarkm if (sysctlbyname("kern.clockrate", &clkinfo, &size, NULL, 0) 21487715Smarkm || size != sizeof(clkinfo)) { 21570118Srwatson error("kern.clockrate"); 21669140Srwatson die(0); 2177011Sphk } 21870118Srwatson hertz = clkinfo.stathz; 2191590Srgrimes (*curcmd->c_init)(); 2201590Srgrimes curcmd->c_flags |= CF_INIT; 2211590Srgrimes labels(); 2221590Srgrimes 223265782Smelifaro if (curcmd->c_cmd != NULL) 224265782Smelifaro SLIST_FOREACH (cmd, &commands, link) 225265782Smelifaro if (!curcmd->c_cmd(cmd->cmd, cmd->argv)) 226265782Smelifaro warnx("command is not understood"); 227265782Smelifaro 2281590Srgrimes dellave = 0.0; 229240605Smelifaro display(); 2301590Srgrimes noecho(); 2311590Srgrimes crmode(); 2321590Srgrimes keyboard(); 2331590Srgrimes /*NOTREACHED*/ 23440060Sobrien 23540060Sobrien return EXIT_SUCCESS; 2361590Srgrimes} 2371590Srgrimes 2381590Srgrimesvoid 239175387Sdelphijlabels(void) 2401590Srgrimes{ 2411590Srgrimes if (curcmd->c_flags & CF_LOADAV) { 242158160Sbde mvaddstr(0, 20, 2431590Srgrimes "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 244158160Sbde mvaddstr(1, 5, "Load Average"); 2451590Srgrimes } 246288306Smr if (curcmd->c_flags & CF_ZFSARC) { 247288306Smr mvaddstr(0, 20, 248288306Smr " Total MFU MRU Anon Hdr L2Hdr Other"); 249288306Smr mvaddstr(1, 5, "ZFS ARC "); 250288306Smr } 2511590Srgrimes (*curcmd->c_label)(); 2521590Srgrimes#ifdef notdef 2531590Srgrimes mvprintw(21, 25, "CPU usage on %s", hostname); 2541590Srgrimes#endif 2551590Srgrimes refresh(); 2561590Srgrimes} 2571590Srgrimes 2581590Srgrimesvoid 259246987Scharnierdisplay(void) 2601590Srgrimes{ 26187715Smarkm int i, j; 2621590Srgrimes 2631590Srgrimes /* Get the load average over the last minute. */ 2641590Srgrimes (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 2651590Srgrimes (*curcmd->c_fetch)(); 2661590Srgrimes if (curcmd->c_flags & CF_LOADAV) { 2671590Srgrimes j = 5.0*avenrun[0] + 0.5; 2681590Srgrimes dellave -= avenrun[0]; 2691590Srgrimes if (dellave >= 0.0) 2701590Srgrimes c = '<'; 2711590Srgrimes else { 2721590Srgrimes c = '>'; 2731590Srgrimes dellave = -dellave; 2741590Srgrimes } 2751590Srgrimes if (dellave < 0.1) 2761590Srgrimes c = '|'; 2771590Srgrimes dellave = avenrun[0]; 2781590Srgrimes wmove(wload, 0, 0); wclrtoeol(wload); 279298684Saraujo for (i = MIN(j, 50); i > 0; i--) 2801590Srgrimes waddch(wload, c); 2811590Srgrimes if (j > 50) 2821590Srgrimes wprintw(wload, " %4.1f", avenrun[0]); 2831590Srgrimes } 284288306Smr if (curcmd->c_flags & CF_ZFSARC) { 285288306Smr uint64_t arc[7] = {}; 286288306Smr size_t size = sizeof(arc[0]); 287288306Smr if (sysctlbyname("kstat.zfs.misc.arcstats.size", 288288306Smr &arc[0], &size, NULL, 0) == 0 ) { 289288306Smr GETSYSCTL("vfs.zfs.mfu_size", arc[1]); 290288306Smr GETSYSCTL("vfs.zfs.mru_size", arc[2]); 291288306Smr GETSYSCTL("vfs.zfs.anon_size", arc[3]); 292288306Smr GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]); 293288306Smr GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]); 294288306Smr GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc[6]); 295288306Smr wmove(wload, 0, 0); wclrtoeol(wload); 296288306Smr for (i = 0 ; i < sizeof(arc) / sizeof(arc[0]) ; i++) { 297288306Smr if (arc[i] > 10llu * 1024 * 1024 * 1024 ) { 298288306Smr wprintw(wload, "%7lluG", arc[i] >> 30); 299288306Smr } 300288306Smr else if (arc[i] > 10 * 1024 * 1024 ) { 301288306Smr wprintw(wload, "%7lluM", arc[i] >> 20); 302288306Smr } 303288306Smr else { 304288306Smr wprintw(wload, "%7lluK", arc[i] >> 10); 305288306Smr } 306288306Smr } 307288306Smr } 308288306Smr } 3091590Srgrimes (*curcmd->c_refresh)(); 310288306Smr if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC)) 3111590Srgrimes wrefresh(wload); 3121590Srgrimes wrefresh(wnd); 3131590Srgrimes move(CMDLINE, col); 3141590Srgrimes refresh(); 3151590Srgrimes} 3161590Srgrimes 3171590Srgrimesvoid 318175387Sdelphijload(void) 3191590Srgrimes{ 3201590Srgrimes 3211590Srgrimes (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 3221590Srgrimes mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", 3231590Srgrimes avenrun[0], avenrun[1], avenrun[2]); 3241590Srgrimes clrtoeol(); 3251590Srgrimes} 3261590Srgrimes 3271590Srgrimesvoid 328175387Sdelphijdie(int signo __unused) 3291590Srgrimes{ 3301590Srgrimes move(CMDLINE, 0); 3311590Srgrimes clrtoeol(); 3321590Srgrimes refresh(); 3331590Srgrimes endwin(); 3341590Srgrimes exit(0); 3351590Srgrimes} 3361590Srgrimes 3371590Srgrimes#include <stdarg.h> 3381590Srgrimes 3391590Srgrimesvoid 3401590Srgrimeserror(const char *fmt, ...) 3411590Srgrimes{ 3421590Srgrimes va_list ap; 3431590Srgrimes char buf[255]; 3441590Srgrimes int oy, ox; 34593058Simp 3461590Srgrimes va_start(ap, fmt); 3471590Srgrimes if (wnd) { 3481590Srgrimes getyx(stdscr, oy, ox); 34936789Simp (void) vsnprintf(buf, sizeof(buf), fmt, ap); 3501590Srgrimes clrtoeol(); 3511590Srgrimes standout(); 3521590Srgrimes mvaddstr(CMDLINE, 0, buf); 3531590Srgrimes standend(); 3541590Srgrimes move(oy, ox); 3551590Srgrimes refresh(); 3561590Srgrimes } else { 3571590Srgrimes (void) vfprintf(stderr, fmt, ap); 3581590Srgrimes fprintf(stderr, "\n"); 3591590Srgrimes } 3601590Srgrimes va_end(ap); 3611590Srgrimes} 3621590Srgrimes 3631590Srgrimesvoid 364175387Sdelphijnlisterr(struct nlist n_list[]) 3651590Srgrimes{ 3661590Srgrimes int i, n; 3671590Srgrimes 3681590Srgrimes n = 0; 3691590Srgrimes clear(); 3701590Srgrimes mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 3711590Srgrimes for (i = 0; 37287715Smarkm n_list[i].n_name != NULL && *n_list[i].n_name != '\0'; i++) 37387715Smarkm if (n_list[i].n_value == 0) 37487715Smarkm mvprintw(2 + ++n, 10, "%s", n_list[i].n_name); 3751590Srgrimes move(CMDLINE, 0); 3761590Srgrimes clrtoeol(); 3771590Srgrimes refresh(); 3781590Srgrimes endwin(); 3791590Srgrimes exit(1); 3801590Srgrimes} 381