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