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