1 /* $NetBSD: main.c,v 1.30 2001/12/06 12:40:51 blymn 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.30 2001/12/06 12:40:51 blymn Exp $"); 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 48 #include <ctype.h> 49 #include <err.h> 50 #include <limits.h> 51 #include <signal.h> 52 #include <stdarg.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.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 #define X_MAXSLP 2 68 { "_maxslp" }, 69 { "" } 70 }; 71 static int dellave; 72 73 kvm_t *kd; 74 char *memf = NULL; 75 char *nlistf = NULL; 76 sig_t sigtstpdfl; 77 double avenrun[3]; 78 int col; 79 int naptime = 5; 80 int verbose = 1; /* to report kvm read errs */ 81 int hz, stathz, maxslp; 82 char c; 83 char *namp; 84 char hostname[MAXHOSTNAMELEN + 1]; 85 WINDOW *wnd; 86 int CMDLINE; 87 int turns = 2; /* stay how many refresh-turns in 'all' mode? */ 88 int allflag; 89 int allcounter; 90 91 static WINDOW *wload; /* one line window for load average */ 92 93 static void usage(void); 94 int main(int, char **); 95 96 gid_t egid; /* XXX needed by initiostat() and initkre() */ 97 98 int 99 main(int argc, char **argv) 100 { 101 int ch; 102 char errbuf[_POSIX2_LINE_MAX]; 103 104 egid = getegid(); 105 (void)setegid(getgid()); 106 107 while ((ch = getopt(argc, argv, "M:N:nw:t:")) != -1) 108 switch(ch) { 109 case 'M': 110 memf = optarg; 111 break; 112 case 'N': 113 nlistf = optarg; 114 break; 115 case 'n': 116 nflag = !nflag; 117 break; 118 case 'w': 119 if ((naptime = atoi(optarg)) <= 0) 120 errx(1, "interval <= 0."); 121 break; 122 case 't': 123 if ((turns = atoi(optarg)) <= 0) 124 errx(1, "turns <= 0."); 125 break; 126 case '?': 127 default: 128 usage(); 129 } 130 argc -= optind; 131 argv += optind; 132 133 134 for ( ; argc > 0; argc--, argv++) { 135 struct mode *p; 136 int modefound = 0; 137 138 if (isdigit(argv[0][0])) { 139 naptime = atoi(argv[0]); 140 if (naptime <= 0) 141 naptime = 5; 142 continue; 143 } 144 145 for (p = modes; p->c_name ; p++) { 146 if (strstr(p->c_name, argv[0]) == p->c_name) { 147 curmode = p; 148 modefound++; 149 break; 150 } 151 152 if(strstr("all",argv[0]) == "all"){ 153 allcounter=0; 154 allflag=1; 155 } 156 } 157 158 159 if (!modefound && !allflag) 160 error("%s: Unknown command.", argv[0]); 161 } 162 163 /* 164 * Discard setgid privileges. If not the running kernel, we toss 165 * them away totally so that bad guys can't print interesting stuff 166 * from kernel memory, otherwise switch back to kmem for the 167 * duration of the kvm_openfiles() call. 168 */ 169 if (nlistf != NULL || memf != NULL) 170 (void)setgid(getgid()); 171 else 172 (void)setegid(egid); 173 174 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 175 if (kd == NULL) { 176 error("%s", errbuf); 177 exit(1); 178 } 179 180 /* Get rid of privs for now. */ 181 if (nlistf == NULL && memf == NULL) 182 (void)setegid(getgid()); 183 184 if (kvm_nlist(kd, namelist)) { 185 nlisterr(namelist); 186 exit(1); 187 } 188 if (namelist[X_FIRST].n_type == 0) 189 errx(1, "couldn't read namelist"); 190 signal(SIGINT, die); 191 signal(SIGQUIT, die); 192 signal(SIGTERM, die); 193 signal(SIGWINCH, redraw); 194 195 /* 196 * Initialize display. Load average appears in a one line 197 * window of its own. Current command's display appears in 198 * an overlapping sub-window of stdscr configured by the display 199 * routines to minimize update work by curses. 200 */ 201 if (initscr() == NULL) 202 { 203 warnx("couldn't initialize screen"); 204 exit(0); 205 } 206 207 CMDLINE = LINES - 1; 208 wnd = (*curmode->c_open)(); 209 if (wnd == NULL) { 210 warnx("couldn't initialize display"); 211 die(0); 212 } 213 wload = newwin(1, 0, 3, 20); 214 if (wload == NULL) { 215 warnx("couldn't set up load average window"); 216 die(0); 217 } 218 gethostname(hostname, sizeof (hostname)); 219 hostname[sizeof(hostname) - 1] = '\0'; 220 NREAD(X_HZ, &hz, sizeof hz); 221 NREAD(X_STATHZ, &stathz, sizeof stathz); 222 NREAD(X_MAXSLP, &maxslp, sizeof maxslp); 223 (*curmode->c_init)(); 224 curmode->c_flags |= CF_INIT; 225 labels(); 226 227 dellave = 0.0; 228 229 signal(SIGALRM, display); 230 display(0); 231 noecho(); 232 cbreak(); 233 keyboard(); 234 /*NOTREACHED*/ 235 } 236 237 static void 238 usage(void) 239 { 240 fprintf(stderr, "usage: systat [-n] [-M core] [-N system] [-w wait] " 241 "[-t turns]\n\t\t[display] [refresh-interval]\n"); 242 exit(1); 243 } 244 245 246 void 247 labels(void) 248 { 249 if (curmode->c_flags & CF_LOADAV) { 250 mvaddstr(2, 20, 251 "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 252 mvaddstr(3, 5, "Load Average"); 253 } 254 (*curmode->c_label)(); 255 #ifdef notdef 256 mvprintw(21, 25, "CPU usage on %s", hostname); 257 #endif 258 refresh(); 259 } 260 261 void 262 display(int signo) 263 { 264 int j; 265 sigset_t set; 266 struct mode *p; 267 268 sigemptyset(&set); 269 sigaddset(&set, SIGALRM); 270 sigprocmask(SIG_BLOCK, &set, NULL); 271 272 /* Get the load average over the last minute. */ 273 (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 274 (*curmode->c_fetch)(); 275 if (curmode->c_flags & CF_LOADAV) { 276 j = 5.0*avenrun[0] + 0.5; 277 dellave -= avenrun[0]; 278 if (dellave >= 0.0) 279 c = '<'; 280 else { 281 c = '>'; 282 dellave = -dellave; 283 } 284 if (dellave < 0.1) 285 c = '|'; 286 dellave = avenrun[0]; 287 wmove(wload, 0, 0); 288 wclrtoeol(wload); 289 whline(wload, c, (j > 50) ? 50 : j); 290 if (j > 50) 291 wprintw(wload, " %4.1f", avenrun[0]); 292 } 293 (*curmode->c_refresh)(); 294 if (curmode->c_flags & CF_LOADAV) 295 wrefresh(wload); 296 wrefresh(wnd); 297 move(CMDLINE, col); 298 refresh(); 299 300 if (allflag && signo==SIGALRM) { 301 if (allcounter >= turns){ 302 p = curmode; 303 p++; 304 if (p->c_name == NULL) 305 p = modes; 306 switch_mode(p); 307 allcounter=0; 308 } else 309 allcounter++; 310 } 311 312 sigprocmask(SIG_UNBLOCK, &set, NULL); 313 alarm(naptime); 314 } 315 316 void 317 redraw(int signo) 318 { 319 sigset_t set; 320 321 sigemptyset(&set); 322 sigaddset(&set, SIGALRM); 323 sigprocmask(SIG_BLOCK, &set, NULL); 324 wrefresh(curscr); 325 refresh(); 326 sigprocmask(SIG_UNBLOCK, &set, NULL); 327 } 328 329 void 330 die(int signo) 331 { 332 move(CMDLINE, 0); 333 clrtoeol(); 334 refresh(); 335 endwin(); 336 exit(0); 337 } 338 339 void 340 error(const char *fmt, ...) 341 { 342 va_list ap; 343 char buf[255]; 344 int oy, ox; 345 346 va_start(ap, fmt); 347 348 if (wnd) { 349 getyx(stdscr, oy, ox); 350 (void) vsnprintf(buf, sizeof(buf), fmt, ap); 351 clrtoeol(); 352 standout(); 353 mvaddstr(CMDLINE, 0, buf); 354 standend(); 355 move(oy, ox); 356 refresh(); 357 } else { 358 (void) vfprintf(stderr, fmt, ap); 359 fprintf(stderr, "\n"); 360 } 361 va_end(ap); 362 } 363 364 void 365 nlisterr(struct nlist namelist[]) 366 { 367 int i, n; 368 369 n = 0; 370 clear(); 371 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 372 for (i = 0; 373 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 374 if (namelist[i].n_value == 0) 375 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 376 move(CMDLINE, 0); 377 clrtoeol(); 378 refresh(); 379 endwin(); 380 exit(1); 381 } 382