1 /* $NetBSD: main.c,v 1.15 1998/07/19 17:47:07 drochner 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.15 1998/07/19 17:47:07 drochner 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 while ((ch = getopt(argc, argv, "M:N:w:")) != -1) 104 switch(ch) { 105 case 'M': 106 memf = optarg; 107 break; 108 case 'N': 109 nlistf = optarg; 110 break; 111 case 'w': 112 if ((naptime = atoi(optarg)) <= 0) 113 errx(1, "interval <= 0."); 114 break; 115 case '?': 116 default: 117 usage(); 118 } 119 argc -= optind; 120 argv += optind; 121 122 while (argc > 0) { 123 if (isdigit(argv[0][0])) { 124 naptime = atoi(argv[0]); 125 if (naptime <= 0) 126 naptime = 5; 127 } else { 128 struct cmdtab *p; 129 130 p = lookup(&argv[0][0]); 131 if (p == (struct cmdtab *)-1) 132 errx(1, "ambiguous request: %s", &argv[0][0]); 133 if (p == 0) 134 errx(1, "unknown request: %s", &argv[0][0]); 135 curcmd = p; 136 } 137 argc--, argv++; 138 } 139 140 /* 141 * Discard setgid privileges. If not the running kernel, we toss 142 * them away totally so that bad guys can't print interesting stuff 143 * from kernel memory, otherwise switch back to kmem for the 144 * duration of the kvm_openfiles() call. 145 */ 146 if (nlistf != NULL || memf != NULL) 147 (void)setgid(getgid()); 148 else 149 (void)setegid(egid); 150 151 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 152 if (kd == NULL) { 153 error("%s", errbuf); 154 exit(1); 155 } 156 157 /* Get rid of privs for now. */ 158 if (nlistf == NULL && memf == NULL) 159 (void)setegid(getgid()); 160 161 if (kvm_nlist(kd, namelist)) { 162 nlisterr(namelist); 163 exit(1); 164 } 165 if (namelist[X_FIRST].n_type == 0) 166 errx(1, "couldn't read namelist"); 167 signal(SIGINT, die); 168 signal(SIGQUIT, die); 169 signal(SIGTERM, die); 170 signal(SIGWINCH, redraw); 171 172 /* 173 * Initialize display. Load average appears in a one line 174 * window of its own. Current command's display appears in 175 * an overlapping sub-window of stdscr configured by the display 176 * routines to minimize update work by curses. 177 */ 178 if (initscr() == NULL) 179 { 180 warnx("couldn't initialize screen"); 181 exit(0); 182 } 183 184 CMDLINE = LINES - 1; 185 wnd = (*curcmd->c_open)(); 186 if (wnd == NULL) { 187 warnx("couldn't initialize display"); 188 die(0); 189 } 190 wload = newwin(1, 0, 3, 20); 191 if (wload == NULL) { 192 warnx("couldn't set up load average window"); 193 die(0); 194 } 195 gethostname(hostname, sizeof (hostname)); 196 hostname[sizeof(hostname) - 1] = '\0'; 197 NREAD(X_HZ, &hz, LONG); 198 NREAD(X_STATHZ, &stathz, LONG); 199 (*curcmd->c_init)(); 200 curcmd->c_flags |= CF_INIT; 201 labels(); 202 203 dellave = 0.0; 204 205 signal(SIGALRM, display); 206 display(0); 207 noecho(); 208 crmode(); 209 keyboard(); 210 /*NOTREACHED*/ 211 } 212 213 static void 214 usage() 215 { 216 fprintf(stderr, "usage: systat [-M core] [-N system] [-w wait]\n"); 217 exit(1); 218 } 219 220 221 void 222 labels() 223 { 224 if (curcmd->c_flags & CF_LOADAV) { 225 mvaddstr(2, 20, 226 "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 227 mvaddstr(3, 5, "Load Average"); 228 } 229 (*curcmd->c_label)(); 230 #ifdef notdef 231 mvprintw(21, 25, "CPU usage on %s", hostname); 232 #endif 233 refresh(); 234 } 235 236 void 237 display(signo) 238 int signo; 239 { 240 int i, j; 241 242 /* Get the load average over the last minute. */ 243 (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 244 (*curcmd->c_fetch)(); 245 if (curcmd->c_flags & CF_LOADAV) { 246 j = 5.0*avenrun[0] + 0.5; 247 dellave -= avenrun[0]; 248 if (dellave >= 0.0) 249 c = '<'; 250 else { 251 c = '>'; 252 dellave = -dellave; 253 } 254 if (dellave < 0.1) 255 c = '|'; 256 dellave = avenrun[0]; 257 wmove(wload, 0, 0); wclrtoeol(wload); 258 for (i = (j > 50) ? 50 : j; i > 0; i--) 259 waddch(wload, c); 260 if (j > 50) 261 wprintw(wload, " %4.1f", avenrun[0]); 262 } 263 (*curcmd->c_refresh)(); 264 if (curcmd->c_flags & CF_LOADAV) 265 wrefresh(wload); 266 wrefresh(wnd); 267 move(CMDLINE, col); 268 refresh(); 269 alarm(naptime); 270 } 271 272 void 273 redraw(signo) 274 int signo; 275 { 276 sigset_t set; 277 278 sigemptyset(&set); 279 sigaddset(&set, SIGALRM); 280 sigprocmask(SIG_BLOCK, &set, NULL); 281 wrefresh(curscr); 282 refresh(); 283 sigprocmask(SIG_UNBLOCK, &set, NULL); 284 } 285 286 void 287 load() 288 { 289 290 (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 291 mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", 292 avenrun[0], avenrun[1], avenrun[2]); 293 clrtoeol(); 294 } 295 296 void 297 die(signo) 298 int signo; 299 { 300 move(CMDLINE, 0); 301 clrtoeol(); 302 refresh(); 303 endwin(); 304 exit(0); 305 } 306 307 #if __STDC__ 308 #include <stdarg.h> 309 #else 310 #include <varargs.h> 311 #endif 312 313 #if __STDC__ 314 void 315 error(const char *fmt, ...) 316 #else 317 void 318 error(fmt, va_alist) 319 char *fmt; 320 va_dcl 321 #endif 322 { 323 va_list ap; 324 char buf[255]; 325 int oy, ox; 326 #if __STDC__ 327 va_start(ap, fmt); 328 #else 329 va_start(ap); 330 #endif 331 332 if (wnd) { 333 getyx(stdscr, oy, ox); 334 (void) vsprintf(buf, fmt, ap); 335 clrtoeol(); 336 standout(); 337 mvaddstr(CMDLINE, 0, buf); 338 standend(); 339 move(oy, ox); 340 refresh(); 341 } else { 342 (void) vfprintf(stderr, fmt, ap); 343 fprintf(stderr, "\n"); 344 } 345 va_end(ap); 346 } 347 348 void 349 nlisterr(namelist) 350 struct nlist namelist[]; 351 { 352 int i, n; 353 354 n = 0; 355 clear(); 356 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 357 for (i = 0; 358 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 359 if (namelist[i].n_value == 0) 360 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 361 move(CMDLINE, 0); 362 clrtoeol(); 363 refresh(); 364 endwin(); 365 exit(1); 366 } 367