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$"); 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> 471590Srgrimes 4828149Scharnier#include <err.h> 4977205Stmm#include <limits.h> 5014953Sache#include <locale.h> 511590Srgrimes#include <nlist.h> 52200462Sdelphij#include <paths.h> 531590Srgrimes#include <signal.h> 541590Srgrimes#include <stdio.h> 5540060Sobrien#include <stdlib.h> 5640060Sobrien#include <unistd.h> 5787715Smarkm 581590Srgrimes#include "systat.h" 591590Srgrimes#include "extern.h" 601590Srgrimes 611590Srgrimesstatic int dellave; 621590Srgrimes 631590Srgrimeskvm_t *kd; 641590Srgrimessig_t sigtstpdfl; 651590Srgrimesdouble avenrun[3]; 661590Srgrimesint col; 67240605Smelifarounsigned int delay = 5000000; /* in microseconds */ 681590Srgrimesint verbose = 1; /* to report kvm read errs */ 6970118Srwatsonstruct clockinfo clkinfo; 704930Sbdedouble hertz; 711590Srgrimeschar c; 721590Srgrimeschar *namp; 731590Srgrimeschar hostname[MAXHOSTNAMELEN]; 741590SrgrimesWINDOW *wnd; 751590Srgrimesint CMDLINE; 7674671Stmmint use_kvm = 1; 771590Srgrimes 781590Srgrimesstatic WINDOW *wload; /* one line window for load average */ 791590Srgrimes 8028789Scharnierint 81126775Sdwmalonemain(int argc, char **argv) 821590Srgrimes{ 8377205Stmm char errbuf[_POSIX2_LINE_MAX], dummy; 8469140Srwatson size_t size; 85240605Smelifaro double t; 861590Srgrimes 87262643Sbrooks#ifdef USE_WIDECHAR 88199242Sume (void) setlocale(LC_ALL, ""); 89262643Sbrooks#else 90262643Sbrooks (void) setlocale(LC_TIME, ""); 91262643Sbrooks#endif 9214953Sache 931590Srgrimes argc--, argv++; 941590Srgrimes while (argc > 0) { 951590Srgrimes if (argv[0][0] == '-') { 961590Srgrimes struct cmdtab *p; 971590Srgrimes 981590Srgrimes p = lookup(&argv[0][1]); 9928149Scharnier if (p == (struct cmdtab *)-1) 10028149Scharnier errx(1, "%s: ambiguous request", &argv[0][1]); 10128149Scharnier if (p == (struct cmdtab *)0) 10228149Scharnier errx(1, "%s: unknown request", &argv[0][1]); 1031590Srgrimes curcmd = p; 1041590Srgrimes } else { 105240605Smelifaro t = strtod(argv[0], NULL) * 1000000.0; 106240605Smelifaro if (t > 0 && t < (double)UINT_MAX) 107240605Smelifaro delay = (unsigned int)t; 1081590Srgrimes } 1091590Srgrimes argc--, argv++; 1101590Srgrimes } 1111590Srgrimes kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 11274671Stmm if (kd != NULL) { 113158161Sbde /* 11474671Stmm * Try to actually read something, we may be in a jail, and 11574671Stmm * have /dev/null opened as /dev/mem. 11674671Stmm */ 117158161Sbde if (kvm_nlist(kd, namelist) != 0 || namelist[0].n_value == 0 || 11874671Stmm kvm_read(kd, namelist[0].n_value, &dummy, sizeof(dummy)) != 11974671Stmm sizeof(dummy)) { 12074671Stmm kvm_close(kd); 12174671Stmm kd = NULL; 12274671Stmm } 12374671Stmm } 1241590Srgrimes if (kd == NULL) { 125158161Sbde /* 12674671Stmm * Maybe we are lacking permissions? Retry, this time with bogus 12774671Stmm * devices. We can now use sysctl only. 12874671Stmm */ 12974671Stmm use_kvm = 0; 13077205Stmm kd = kvm_openfiles("/dev/null", "/dev/null", "/dev/null", 13177205Stmm O_RDONLY, errbuf); 13274671Stmm if (kd == NULL) { 13374671Stmm error("%s", errbuf); 13474671Stmm exit(1); 13574671Stmm } 1361590Srgrimes } 137197956Sjh signal(SIGHUP, die); 1381590Srgrimes signal(SIGINT, die); 1391590Srgrimes signal(SIGQUIT, die); 1401590Srgrimes signal(SIGTERM, die); 1411590Srgrimes 1421590Srgrimes /* 1431590Srgrimes * Initialize display. Load average appears in a one line 1441590Srgrimes * window of its own. Current command's display appears in 1451590Srgrimes * an overlapping sub-window of stdscr configured by the display 1461590Srgrimes * routines to minimize update work by curses. 1471590Srgrimes */ 1481590Srgrimes initscr(); 1491590Srgrimes CMDLINE = LINES - 1; 1501590Srgrimes wnd = (*curcmd->c_open)(); 1511590Srgrimes if (wnd == NULL) { 15228149Scharnier warnx("couldn't initialize display"); 1531590Srgrimes die(0); 1541590Srgrimes } 155158160Sbde wload = newwin(1, 0, 1, 20); 1561590Srgrimes if (wload == NULL) { 15728149Scharnier warnx("couldn't set up load average window"); 1581590Srgrimes die(0); 1591590Srgrimes } 16069140Srwatson gethostname(hostname, sizeof (hostname)); 16169140Srwatson size = sizeof(clkinfo); 16287715Smarkm if (sysctlbyname("kern.clockrate", &clkinfo, &size, NULL, 0) 16387715Smarkm || size != sizeof(clkinfo)) { 16470118Srwatson error("kern.clockrate"); 16569140Srwatson die(0); 1667011Sphk } 16770118Srwatson hertz = clkinfo.stathz; 1681590Srgrimes (*curcmd->c_init)(); 1691590Srgrimes curcmd->c_flags |= CF_INIT; 1701590Srgrimes labels(); 1711590Srgrimes 1721590Srgrimes dellave = 0.0; 1731590Srgrimes 174240605Smelifaro display(); 1751590Srgrimes noecho(); 1761590Srgrimes crmode(); 1771590Srgrimes keyboard(); 1781590Srgrimes /*NOTREACHED*/ 17940060Sobrien 18040060Sobrien return EXIT_SUCCESS; 1811590Srgrimes} 1821590Srgrimes 1831590Srgrimesvoid 184175387Sdelphijlabels(void) 1851590Srgrimes{ 1861590Srgrimes if (curcmd->c_flags & CF_LOADAV) { 187158160Sbde mvaddstr(0, 20, 1881590Srgrimes "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 189158160Sbde mvaddstr(1, 5, "Load Average"); 1901590Srgrimes } 191303684Smr if (curcmd->c_flags & CF_ZFSARC) { 192303684Smr mvaddstr(0, 20, 193303684Smr " Total MFU MRU Anon Hdr L2Hdr Other"); 194303684Smr mvaddstr(1, 5, "ZFS ARC "); 195303684Smr } 1961590Srgrimes (*curcmd->c_label)(); 1971590Srgrimes#ifdef notdef 1981590Srgrimes mvprintw(21, 25, "CPU usage on %s", hostname); 1991590Srgrimes#endif 2001590Srgrimes refresh(); 2011590Srgrimes} 2021590Srgrimes 2031590Srgrimesvoid 204246987Scharnierdisplay(void) 2051590Srgrimes{ 20687715Smarkm int i, j; 2071590Srgrimes 2081590Srgrimes /* Get the load average over the last minute. */ 2091590Srgrimes (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 2101590Srgrimes (*curcmd->c_fetch)(); 2111590Srgrimes if (curcmd->c_flags & CF_LOADAV) { 2121590Srgrimes j = 5.0*avenrun[0] + 0.5; 2131590Srgrimes dellave -= avenrun[0]; 2141590Srgrimes if (dellave >= 0.0) 2151590Srgrimes c = '<'; 2161590Srgrimes else { 2171590Srgrimes c = '>'; 2181590Srgrimes dellave = -dellave; 2191590Srgrimes } 2201590Srgrimes if (dellave < 0.1) 2211590Srgrimes c = '|'; 2221590Srgrimes dellave = avenrun[0]; 2231590Srgrimes wmove(wload, 0, 0); wclrtoeol(wload); 2241590Srgrimes for (i = (j > 50) ? 50 : j; i > 0; i--) 2251590Srgrimes waddch(wload, c); 2261590Srgrimes if (j > 50) 2271590Srgrimes wprintw(wload, " %4.1f", avenrun[0]); 2281590Srgrimes } 229303684Smr if (curcmd->c_flags & CF_ZFSARC) { 230303684Smr uint64_t arc[7] = {}; 231303684Smr size_t size = sizeof(arc[0]); 232303684Smr if (sysctlbyname("kstat.zfs.misc.arcstats.size", 233303684Smr &arc[0], &size, NULL, 0) == 0 ) { 234303684Smr GETSYSCTL("vfs.zfs.mfu_size", arc[1]); 235303684Smr GETSYSCTL("vfs.zfs.mru_size", arc[2]); 236303684Smr GETSYSCTL("vfs.zfs.anon_size", arc[3]); 237303684Smr GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]); 238303684Smr GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]); 239303684Smr GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc[6]); 240303684Smr wmove(wload, 0, 0); wclrtoeol(wload); 241303684Smr for (i = 0 ; i < sizeof(arc) / sizeof(arc[0]) ; i++) { 242303684Smr if (arc[i] > 10llu * 1024 * 1024 * 1024 ) { 243303684Smr wprintw(wload, "%7lluG", arc[i] >> 30); 244303684Smr } 245303684Smr else if (arc[i] > 10 * 1024 * 1024 ) { 246303684Smr wprintw(wload, "%7lluM", arc[i] >> 20); 247303684Smr } 248303684Smr else { 249303684Smr wprintw(wload, "%7lluK", arc[i] >> 10); 250303684Smr } 251303684Smr } 252303684Smr } 253303684Smr } 2541590Srgrimes (*curcmd->c_refresh)(); 255303684Smr if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC)) 2561590Srgrimes wrefresh(wload); 2571590Srgrimes wrefresh(wnd); 2581590Srgrimes move(CMDLINE, col); 2591590Srgrimes refresh(); 2601590Srgrimes} 2611590Srgrimes 2621590Srgrimesvoid 263175387Sdelphijload(void) 2641590Srgrimes{ 2651590Srgrimes 2661590Srgrimes (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 2671590Srgrimes mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", 2681590Srgrimes avenrun[0], avenrun[1], avenrun[2]); 2691590Srgrimes clrtoeol(); 2701590Srgrimes} 2711590Srgrimes 2721590Srgrimesvoid 273175387Sdelphijdie(int signo __unused) 2741590Srgrimes{ 2751590Srgrimes move(CMDLINE, 0); 2761590Srgrimes clrtoeol(); 2771590Srgrimes refresh(); 2781590Srgrimes endwin(); 2791590Srgrimes exit(0); 2801590Srgrimes} 2811590Srgrimes 2821590Srgrimes#include <stdarg.h> 2831590Srgrimes 2841590Srgrimesvoid 2851590Srgrimeserror(const char *fmt, ...) 2861590Srgrimes{ 2871590Srgrimes va_list ap; 2881590Srgrimes char buf[255]; 2891590Srgrimes int oy, ox; 29093058Simp 2911590Srgrimes va_start(ap, fmt); 2921590Srgrimes if (wnd) { 2931590Srgrimes getyx(stdscr, oy, ox); 29436789Simp (void) vsnprintf(buf, sizeof(buf), fmt, ap); 2951590Srgrimes clrtoeol(); 2961590Srgrimes standout(); 2971590Srgrimes mvaddstr(CMDLINE, 0, buf); 2981590Srgrimes standend(); 2991590Srgrimes move(oy, ox); 3001590Srgrimes refresh(); 3011590Srgrimes } else { 3021590Srgrimes (void) vfprintf(stderr, fmt, ap); 3031590Srgrimes fprintf(stderr, "\n"); 3041590Srgrimes } 3051590Srgrimes va_end(ap); 3061590Srgrimes} 3071590Srgrimes 3081590Srgrimesvoid 309175387Sdelphijnlisterr(struct nlist n_list[]) 3101590Srgrimes{ 3111590Srgrimes int i, n; 3121590Srgrimes 3131590Srgrimes n = 0; 3141590Srgrimes clear(); 3151590Srgrimes mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 3161590Srgrimes for (i = 0; 31787715Smarkm n_list[i].n_name != NULL && *n_list[i].n_name != '\0'; i++) 31887715Smarkm if (n_list[i].n_value == 0) 31987715Smarkm mvprintw(2 + ++n, 10, "%s", n_list[i].n_name); 3201590Srgrimes move(CMDLINE, 0); 3211590Srgrimes clrtoeol(); 3221590Srgrimes refresh(); 3231590Srgrimes endwin(); 3241590Srgrimes exit(1); 3251590Srgrimes} 326