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