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