1 /* $OpenBSD: main.c,v 1.26 2003/06/03 02:56:17 millert Exp $ */ 2 /* $NetBSD: main.c,v 1.8 1996/05/10 23:16:36 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static char copyright[] = 35 "@(#) Copyright (c) 1980, 1992, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 42 #endif 43 static char rcsid[] = "$OpenBSD: main.c,v 1.26 2003/06/03 02:56:17 millert Exp $"; 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/sysctl.h> 48 49 #include <err.h> 50 #include <nlist.h> 51 #include <signal.h> 52 #include <ctype.h> 53 #include <stdio.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <stdlib.h> 57 #include <limits.h> 58 #include <stdarg.h> 59 60 #include "systat.h" 61 #include "extern.h" 62 63 double dellave; 64 65 kvm_t *kd; 66 char *nlistf = NULL; 67 char *memf = NULL; 68 sig_t sigtstpdfl; 69 double avenrun[3]; 70 int col; 71 int naptime = 5; 72 int verbose = 1; /* to report kvm read errs */ 73 int hz, stathz; 74 char c; 75 char *namp; 76 char hostname[MAXHOSTNAMELEN]; 77 WINDOW *wnd; 78 long CMDLINE; 79 80 WINDOW *wload; /* one line window for load average */ 81 82 static void usage(void); 83 84 int 85 main(int argc, char *argv[]) 86 { 87 int ch; 88 char errbuf[_POSIX2_LINE_MAX]; 89 90 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 91 if (kd == NULL) { 92 error("%s", errbuf); 93 exit(1); 94 } 95 96 setegid(getgid()); 97 setgid(getgid()); 98 99 while ((ch = getopt(argc, argv, "w:")) != -1) 100 switch (ch) { 101 case 'w': 102 if ((naptime = atoi(optarg)) <= 0) 103 errx(1, "interval <= 0."); 104 break; 105 default: 106 usage(); 107 } 108 argc -= optind; 109 argv += optind; 110 111 while (argc > 0) { 112 if (isdigit(argv[0][0])) { 113 naptime = atoi(argv[0]); 114 if (naptime <= 0) 115 naptime = 5; 116 } else { 117 struct cmdtab *p; 118 119 p = lookup(&argv[0][0]); 120 if (p == (struct cmdtab *)-1) 121 errx(1, "ambiguous request: %s", &argv[0][0]); 122 if (p == 0) 123 errx(1, "unknown request: %s", &argv[0][0]); 124 curcmd = p; 125 } 126 argc--; 127 argv++; 128 } 129 130 signal(SIGINT, sigdie); 131 siginterrupt(SIGINT, 1); 132 signal(SIGQUIT, sigdie); 133 siginterrupt(SIGQUIT, 1); 134 signal(SIGTERM, sigdie); 135 siginterrupt(SIGTERM, 1); 136 137 /* 138 * Initialize display. Load average appears in a one line 139 * window of its own. Current command's display appears in 140 * an overlapping sub-window of stdscr configured by the display 141 * routines to minimize update work by curses. 142 */ 143 if (initscr() == NULL) { 144 warnx("couldn't initialize screen"); 145 exit(0); 146 } 147 148 CMDLINE = LINES - 1; 149 wnd = (*curcmd->c_open)(); 150 if (wnd == NULL) { 151 warnx("couldn't initialize display"); 152 die(); 153 } 154 wload = newwin(1, 0, 3, 20); 155 if (wload == NULL) { 156 warnx("couldn't set up load average window"); 157 die(); 158 } 159 gethostname(hostname, sizeof (hostname)); 160 gethz(); 161 (*curcmd->c_init)(); 162 curcmd->c_flags |= CF_INIT; 163 labels(); 164 165 dellave = 0.0; 166 167 signal(SIGALRM, sigdisplay); 168 siginterrupt(SIGALRM, 1); 169 signal(SIGWINCH, sigwinch); 170 siginterrupt(SIGWINCH, 1); 171 gotdisplay = 1; 172 noecho(); 173 crmode(); 174 keyboard(); 175 /*NOTREACHED*/ 176 } 177 178 void 179 gethz(void) 180 { 181 struct clockinfo cinf; 182 size_t size = sizeof(cinf); 183 int mib[2]; 184 185 mib[0] = CTL_KERN; 186 mib[1] = KERN_CLOCKRATE; 187 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 188 return; 189 stathz = cinf.stathz; 190 hz = cinf.hz; 191 } 192 193 static void 194 usage(void) 195 { 196 fprintf(stderr, "usage: systat [-M core] [-N system] [-w wait]\n"); 197 fprintf(stderr, 198 " [iostat|mbufs|netstat|pigs|swap|vmstat]\n"); 199 exit(1); 200 } 201 202 203 void 204 labels(void) 205 { 206 if (curcmd->c_flags & CF_LOADAV) { 207 mvaddstr(2, 20, 208 "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 209 mvaddstr(3, 5, "Load Average"); 210 } 211 (*curcmd->c_label)(); 212 #ifdef notdef 213 mvprintw(21, 25, "CPU usage on %s", hostname); 214 #endif 215 refresh(); 216 } 217 218 void 219 sigdisplay(signo) 220 int signo; 221 { 222 gotdisplay = 1; 223 } 224 225 void 226 display(void) 227 { 228 int i, j; 229 230 /* Get the load average over the last minute. */ 231 (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 232 (*curcmd->c_fetch)(); 233 if (curcmd->c_flags & CF_LOADAV) { 234 j = 5.0*avenrun[0] + 0.5; 235 dellave -= avenrun[0]; 236 if (dellave >= 0.0) 237 c = '<'; 238 else { 239 c = '>'; 240 dellave = -dellave; 241 } 242 if (dellave < 0.05) 243 c = '|'; 244 dellave = avenrun[0]; 245 wmove(wload, 0, 0); 246 wclrtoeol(wload); 247 for (i = (j > 50) ? 50 : j; i > 0; i--) 248 waddch(wload, c); 249 if (j > 50) 250 wprintw(wload, " %4.1f", avenrun[0]); 251 } 252 (*curcmd->c_refresh)(); 253 if (curcmd->c_flags & CF_LOADAV) 254 wrefresh(wload); 255 wrefresh(wnd); 256 move(CMDLINE, col); 257 refresh(); 258 alarm(naptime); 259 } 260 261 void 262 load(void) 263 { 264 265 (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 266 mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", 267 avenrun[0], avenrun[1], avenrun[2]); 268 clrtoeol(); 269 } 270 271 volatile sig_atomic_t gotdie; 272 volatile sig_atomic_t gotdisplay; 273 volatile sig_atomic_t gotwinch; 274 275 void 276 sigdie(signo) 277 int signo; 278 { 279 gotdie = 1; 280 } 281 282 void 283 die(void) 284 { 285 if (wnd) { 286 move(CMDLINE, 0); 287 clrtoeol(); 288 refresh(); 289 endwin(); 290 } 291 exit(0); 292 } 293 294 void 295 sigwinch(int signo) 296 { 297 gotwinch = 1; 298 } 299 300 void 301 error(const char *fmt, ...) 302 { 303 va_list ap; 304 char buf[255]; 305 int oy, ox; 306 307 va_start(ap, fmt); 308 if (wnd) { 309 getyx(stdscr, oy, ox); 310 (void) vsnprintf(buf, sizeof buf, fmt, ap); 311 clrtoeol(); 312 standout(); 313 mvaddstr(CMDLINE, 0, buf); 314 standend(); 315 move(oy, ox); 316 refresh(); 317 } else { 318 (void) vfprintf(stderr, fmt, ap); 319 fprintf(stderr, "\n"); 320 } 321 va_end(ap); 322 } 323 324 void 325 nlisterr(struct nlist namelist[]) 326 { 327 int i, n; 328 329 n = 0; 330 clear(); 331 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 332 for (i = 0; 333 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 334 if (namelist[i].n_value == 0) 335 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 336 move(CMDLINE, 0); 337 clrtoeol(); 338 refresh(); 339 endwin(); 340 exit(1); 341 } 342