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