1 1.57 rillig /* $NetBSD: main.c,v 1.58 2024/06/16 22:44:01 kre Exp $ */ 2 1.2 jtc 3 1.1 jtc /*- 4 1.1 jtc * Copyright (c) 1980, 1992, 1993 5 1.1 jtc * The Regents of the University of California. All rights reserved. 6 1.1 jtc * 7 1.1 jtc * Redistribution and use in source and binary forms, with or without 8 1.1 jtc * modification, are permitted provided that the following conditions 9 1.1 jtc * are met: 10 1.1 jtc * 1. Redistributions of source code must retain the above copyright 11 1.1 jtc * notice, this list of conditions and the following disclaimer. 12 1.1 jtc * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jtc * notice, this list of conditions and the following disclaimer in the 14 1.1 jtc * documentation and/or other materials provided with the distribution. 15 1.35 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 jtc * may be used to endorse or promote products derived from this software 17 1.1 jtc * without specific prior written permission. 18 1.1 jtc * 19 1.1 jtc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 jtc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 jtc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 jtc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 jtc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 jtc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 jtc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 jtc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 jtc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 jtc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 jtc * SUCH DAMAGE. 30 1.1 jtc */ 31 1.1 jtc 32 1.11 mrg #include <sys/cdefs.h> 33 1.1 jtc #ifndef lint 34 1.43 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\ 35 1.43 lukem The Regents of the University of California. All rights reserved."); 36 1.2 jtc #if 0 37 1.1 jtc static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 38 1.2 jtc #endif 39 1.57 rillig __RCSID("$NetBSD: main.c,v 1.58 2024/06/16 22:44:01 kre Exp $"); 40 1.1 jtc #endif /* not lint */ 41 1.1 jtc 42 1.1 jtc #include <sys/param.h> 43 1.47 christos #include <sys/sysctl.h> 44 1.47 christos #include <sys/ioctl.h> 45 1.1 jtc 46 1.28 simonb #include <ctype.h> 47 1.4 mycroft #include <err.h> 48 1.47 christos #include <errno.h> 49 1.10 explorer #include <limits.h> 50 1.1 jtc #include <signal.h> 51 1.28 simonb #include <stdarg.h> 52 1.1 jtc #include <stdio.h> 53 1.28 simonb #include <stdlib.h> 54 1.5 cgd #include <string.h> 55 1.8 thorpej #include <unistd.h> 56 1.31 dsl #include <termios.h> 57 1.4 mycroft 58 1.1 jtc #include "systat.h" 59 1.1 jtc #include "extern.h" 60 1.55 christos #include "drvstats.h" 61 1.1 jtc 62 1.58 kre static double dellave; 63 1.1 jtc 64 1.1 jtc kvm_t *kd; 65 1.8 thorpej char *memf = NULL; 66 1.8 thorpej char *nlistf = NULL; 67 1.1 jtc sig_t sigtstpdfl; 68 1.1 jtc double avenrun[3]; 69 1.1 jtc int col; 70 1.54 sevan double naptime = 1; 71 1.1 jtc int verbose = 1; /* to report kvm read errs */ 72 1.29 matt int hz, stathz, maxslp; 73 1.1 jtc char c; 74 1.1 jtc char *namp; 75 1.13 mrg char hostname[MAXHOSTNAMELEN + 1]; 76 1.1 jtc WINDOW *wnd; 77 1.1 jtc int CMDLINE; 78 1.27 hubertf int turns = 2; /* stay how many refresh-turns in 'all' mode? */ 79 1.27 hubertf int allflag; 80 1.27 hubertf int allcounter; 81 1.41 christos sig_atomic_t needsredraw = 0; 82 1.55 christos float hertz; 83 1.55 christos double etime; 84 1.56 christos bool showzero = false; 85 1.1 jtc 86 1.1 jtc static WINDOW *wload; /* one line window for load average */ 87 1.1 jtc 88 1.31 dsl static void (*sv_stop_handler)(int); 89 1.31 dsl 90 1.31 dsl static void stop(int); 91 1.46 joerg __dead static void usage(void); 92 1.8 thorpej 93 1.15 drochner gid_t egid; /* XXX needed by initiostat() and initkre() */ 94 1.15 drochner 95 1.7 jtc int 96 1.26 ad main(int argc, char **argv) 97 1.1 jtc { 98 1.8 thorpej int ch; 99 1.10 explorer char errbuf[_POSIX2_LINE_MAX]; 100 1.44 apb const char *all; 101 1.47 christos struct clockinfo clk; 102 1.47 christos size_t len; 103 1.51 mrg int bflag = 0; 104 1.1 jtc 105 1.44 apb all = "all"; 106 1.15 drochner egid = getegid(); 107 1.13 mrg (void)setegid(getgid()); 108 1.21 jwise 109 1.56 christos while ((ch = getopt(argc, argv, "M:N:bnw:t:z")) != -1) 110 1.8 thorpej switch(ch) { 111 1.9 scottr case 'M': 112 1.9 scottr memf = optarg; 113 1.9 scottr break; 114 1.9 scottr case 'N': 115 1.9 scottr nlistf = optarg; 116 1.9 scottr break; 117 1.52 mrg case 'b': 118 1.52 mrg bflag = !bflag; 119 1.52 mrg break; 120 1.23 itojun case 'n': 121 1.23 itojun nflag = !nflag; 122 1.23 itojun break; 123 1.27 hubertf case 't': 124 1.27 hubertf if ((turns = atoi(optarg)) <= 0) 125 1.56 christos errx(EXIT_FAILURE, "turns <= 0."); 126 1.27 hubertf break; 127 1.52 mrg case 'w': 128 1.52 mrg if ((naptime = strtod(optarg, NULL)) <= 0) 129 1.56 christos errx(EXIT_FAILURE, "interval <= 0."); 130 1.56 christos break; 131 1.56 christos case 'z': 132 1.56 christos showzero = true; 133 1.51 mrg break; 134 1.9 scottr case '?': 135 1.9 scottr default: 136 1.9 scottr usage(); 137 1.9 scottr } 138 1.9 scottr argc -= optind; 139 1.9 scottr argv += optind; 140 1.8 thorpej 141 1.19 jwise 142 1.19 jwise for ( ; argc > 0; argc--, argv++) { 143 1.19 jwise struct mode *p; 144 1.20 jwise int modefound = 0; 145 1.19 jwise 146 1.38 dsl if (isdigit((unsigned char)argv[0][0])) { 147 1.50 christos naptime = strtod(argv[0], NULL); 148 1.8 thorpej if (naptime <= 0) 149 1.8 thorpej naptime = 5; 150 1.19 jwise continue; 151 1.19 jwise } 152 1.1 jtc 153 1.19 jwise for (p = modes; p->c_name ; p++) { 154 1.24 jwise if (strstr(p->c_name, argv[0]) == p->c_name) { 155 1.19 jwise curmode = p; 156 1.20 jwise modefound++; 157 1.19 jwise break; 158 1.19 jwise } 159 1.27 hubertf 160 1.44 apb if (strstr(all, argv[0]) == all) { 161 1.27 hubertf allcounter=0; 162 1.27 hubertf allflag=1; 163 1.27 hubertf } 164 1.1 jtc } 165 1.19 jwise 166 1.27 hubertf 167 1.27 hubertf if (!modefound && !allflag) 168 1.19 jwise error("%s: Unknown command.", argv[0]); 169 1.1 jtc } 170 1.13 mrg 171 1.15 drochner /* 172 1.15 drochner * Discard setgid privileges. If not the running kernel, we toss 173 1.15 drochner * them away totally so that bad guys can't print interesting stuff 174 1.15 drochner * from kernel memory, otherwise switch back to kmem for the 175 1.15 drochner * duration of the kvm_openfiles() call. 176 1.15 drochner */ 177 1.15 drochner if (nlistf != NULL || memf != NULL) 178 1.15 drochner (void)setgid(getgid()); 179 1.15 drochner else 180 1.15 drochner (void)setegid(egid); 181 1.15 drochner 182 1.8 thorpej kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 183 1.54 sevan if (kd == NULL) 184 1.56 christos errx(EXIT_FAILURE, "%s", errbuf); 185 1.15 drochner 186 1.15 drochner /* Get rid of privs for now. */ 187 1.13 mrg if (nlistf == NULL && memf == NULL) 188 1.15 drochner (void)setegid(getgid()); 189 1.15 drochner 190 1.1 jtc signal(SIGINT, die); 191 1.1 jtc signal(SIGQUIT, die); 192 1.1 jtc signal(SIGTERM, die); 193 1.31 dsl sv_stop_handler = signal(SIGTSTP, stop); 194 1.1 jtc 195 1.1 jtc /* 196 1.1 jtc * Initialize display. Load average appears in a one line 197 1.1 jtc * window of its own. Current command's display appears in 198 1.1 jtc * an overlapping sub-window of stdscr configured by the display 199 1.1 jtc * routines to minimize update work by curses. 200 1.1 jtc */ 201 1.6 jtc if (initscr() == NULL) 202 1.56 christos errx(EXIT_FAILURE, "couldn't initialize screen"); 203 1.6 jtc 204 1.1 jtc CMDLINE = LINES - 1; 205 1.18 jwise wnd = (*curmode->c_open)(); 206 1.1 jtc if (wnd == NULL) { 207 1.54 sevan move(CMDLINE, 0); 208 1.54 sevan clrtoeol(); 209 1.54 sevan refresh(); 210 1.54 sevan endwin(); 211 1.4 mycroft warnx("couldn't initialize display"); 212 1.1 jtc die(0); 213 1.1 jtc } 214 1.1 jtc wload = newwin(1, 0, 3, 20); 215 1.1 jtc if (wload == NULL) { 216 1.54 sevan move(CMDLINE, 0); 217 1.54 sevan clrtoeol(); 218 1.54 sevan refresh(); 219 1.54 sevan endwin(); 220 1.4 mycroft warnx("couldn't set up load average window"); 221 1.1 jtc die(0); 222 1.1 jtc } 223 1.1 jtc gethostname(hostname, sizeof (hostname)); 224 1.13 mrg hostname[sizeof(hostname) - 1] = '\0'; 225 1.47 christos 226 1.47 christos len = sizeof(clk); 227 1.47 christos if (sysctlbyname("kern.clockrate", &clk, &len, NULL, 0)) 228 1.47 christos error("can't get \"kern.clockrate\": %s", strerror(errno)); 229 1.47 christos hz = clk.hz; 230 1.47 christos stathz = clk.stathz; 231 1.47 christos 232 1.47 christos len = sizeof(maxslp); 233 1.47 christos if (sysctlbyname("vm.maxslp", &maxslp, &len, NULL, 0)) 234 1.47 christos error("can't get \"vm.maxslp\": %s", strerror(errno)); 235 1.47 christos 236 1.18 jwise (*curmode->c_init)(); 237 1.18 jwise curmode->c_flags |= CF_INIT; 238 1.1 jtc labels(); 239 1.1 jtc 240 1.58 kre dellave = 0.0; 241 1.1 jtc 242 1.1 jtc display(0); 243 1.51 mrg if (!bflag) { 244 1.51 mrg noecho(); 245 1.51 mrg cbreak(); 246 1.51 mrg keyboard(); 247 1.51 mrg } else 248 1.51 mrg die(0); 249 1.1 jtc /*NOTREACHED*/ 250 1.1 jtc } 251 1.8 thorpej 252 1.8 thorpej static void 253 1.26 ad usage(void) 254 1.8 thorpej { 255 1.56 christos fprintf(stderr, "usage: %s [-bnz] [-M core] [-N system] [-w wait] " 256 1.56 christos "[-t turns]\n\t\t[display] [refresh-interval]\n", getprogname()); 257 1.56 christos exit(EXIT_FAILURE); 258 1.8 thorpej } 259 1.8 thorpej 260 1.1 jtc 261 1.1 jtc void 262 1.26 ad labels(void) 263 1.1 jtc { 264 1.18 jwise if (curmode->c_flags & CF_LOADAV) { 265 1.1 jtc mvaddstr(2, 20, 266 1.1 jtc "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); 267 1.1 jtc mvaddstr(3, 5, "Load Average"); 268 1.1 jtc } 269 1.18 jwise (*curmode->c_label)(); 270 1.1 jtc #ifdef notdef 271 1.1 jtc mvprintw(21, 25, "CPU usage on %s", hostname); 272 1.1 jtc #endif 273 1.1 jtc refresh(); 274 1.1 jtc } 275 1.1 jtc 276 1.1 jtc void 277 1.26 ad display(int signo) 278 1.1 jtc { 279 1.45 dsl static int skip; 280 1.25 mycroft int j; 281 1.27 hubertf struct mode *p; 282 1.45 dsl int ms_delay; 283 1.45 dsl 284 1.45 dsl if (signo == SIGALRM && skip-- > 0) 285 1.45 dsl /* Don't display on this timeout */ 286 1.45 dsl return; 287 1.22 jwise 288 1.1 jtc /* Get the load average over the last minute. */ 289 1.14 mrg (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 290 1.18 jwise (*curmode->c_fetch)(); 291 1.18 jwise if (curmode->c_flags & CF_LOADAV) { 292 1.1 jtc j = 5.0*avenrun[0] + 0.5; 293 1.1 jtc dellave -= avenrun[0]; 294 1.58 kre if (dellave >= 0.0) 295 1.1 jtc c = '<'; 296 1.1 jtc else { 297 1.1 jtc c = '>'; 298 1.1 jtc dellave = -dellave; 299 1.1 jtc } 300 1.58 kre if (dellave < 0.1) 301 1.1 jtc c = '|'; 302 1.1 jtc dellave = avenrun[0]; 303 1.25 mycroft wmove(wload, 0, 0); 304 1.25 mycroft wclrtoeol(wload); 305 1.25 mycroft whline(wload, c, (j > 50) ? 50 : j); 306 1.1 jtc if (j > 50) 307 1.1 jtc wprintw(wload, " %4.1f", avenrun[0]); 308 1.1 jtc } 309 1.18 jwise (*curmode->c_refresh)(); 310 1.18 jwise if (curmode->c_flags & CF_LOADAV) 311 1.1 jtc wrefresh(wload); 312 1.1 jtc wrefresh(wnd); 313 1.1 jtc move(CMDLINE, col); 314 1.1 jtc refresh(); 315 1.27 hubertf 316 1.27 hubertf if (allflag && signo==SIGALRM) { 317 1.27 hubertf if (allcounter >= turns){ 318 1.27 hubertf p = curmode; 319 1.27 hubertf p++; 320 1.27 hubertf if (p->c_name == NULL) 321 1.27 hubertf p = modes; 322 1.27 hubertf switch_mode(p); 323 1.27 hubertf allcounter=0; 324 1.27 hubertf } else 325 1.27 hubertf allcounter++; 326 1.45 dsl } 327 1.27 hubertf 328 1.45 dsl /* curses timeout() uses VTIME, limited to 255 1/10th secs */ 329 1.45 dsl ms_delay = naptime * 1000; 330 1.45 dsl if (ms_delay < 25500) { 331 1.45 dsl timeout(ms_delay); 332 1.45 dsl skip = 0; 333 1.45 dsl } else { 334 1.45 dsl skip = ms_delay / 25500; 335 1.45 dsl timeout(ms_delay / (skip + 1)); 336 1.45 dsl } 337 1.9 scottr } 338 1.9 scottr 339 1.9 scottr void 340 1.41 christos redraw(void) 341 1.9 scottr { 342 1.36 mycroft CMDLINE = LINES - 1; 343 1.36 mycroft labels(); 344 1.31 dsl 345 1.31 dsl display(0); 346 1.41 christos needsredraw = 0; 347 1.31 dsl } 348 1.31 dsl 349 1.31 dsl static void 350 1.31 dsl stop(int signo) 351 1.31 dsl { 352 1.31 dsl sigset_t set; 353 1.31 dsl 354 1.31 dsl signal(SIGTSTP, sv_stop_handler); 355 1.31 dsl /* unblock SIGTSTP */ 356 1.31 dsl sigemptyset(&set); 357 1.31 dsl sigaddset(&set, SIGTSTP); 358 1.9 scottr sigprocmask(SIG_UNBLOCK, &set, NULL); 359 1.31 dsl /* stop ourselves */ 360 1.31 dsl kill(0, SIGTSTP); 361 1.31 dsl /* must have been restarted */ 362 1.32 dsl signal(SIGTSTP, stop); 363 1.41 christos needsredraw = signo; 364 1.1 jtc } 365 1.1 jtc 366 1.1 jtc void 367 1.26 ad die(int signo) 368 1.1 jtc { 369 1.1 jtc move(CMDLINE, 0); 370 1.1 jtc clrtoeol(); 371 1.1 jtc refresh(); 372 1.1 jtc endwin(); 373 1.56 christos exit(EXIT_SUCCESS); 374 1.1 jtc } 375 1.1 jtc 376 1.1 jtc void 377 1.1 jtc error(const char *fmt, ...) 378 1.1 jtc { 379 1.1 jtc va_list ap; 380 1.1 jtc char buf[255]; 381 1.1 jtc int oy, ox; 382 1.26 ad 383 1.1 jtc va_start(ap, fmt); 384 1.1 jtc 385 1.1 jtc if (wnd) { 386 1.1 jtc getyx(stdscr, oy, ox); 387 1.21 jwise (void) vsnprintf(buf, sizeof(buf), fmt, ap); 388 1.1 jtc clrtoeol(); 389 1.1 jtc standout(); 390 1.1 jtc mvaddstr(CMDLINE, 0, buf); 391 1.1 jtc standend(); 392 1.1 jtc move(oy, ox); 393 1.1 jtc refresh(); 394 1.1 jtc } else { 395 1.1 jtc (void) vfprintf(stderr, fmt, ap); 396 1.1 jtc fprintf(stderr, "\n"); 397 1.1 jtc } 398 1.1 jtc va_end(ap); 399 1.1 jtc } 400 1.1 jtc 401 1.1 jtc void 402 1.49 mrg clearerror(void) 403 1.49 mrg { 404 1.49 mrg 405 1.49 mrg error("%s", ""); 406 1.49 mrg } 407 1.49 mrg 408 1.49 mrg void 409 1.39 dsl nlisterr(struct nlist name_list[]) 410 1.1 jtc { 411 1.1 jtc int i, n; 412 1.1 jtc 413 1.1 jtc n = 0; 414 1.1 jtc clear(); 415 1.1 jtc mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 416 1.1 jtc for (i = 0; 417 1.39 dsl name_list[i].n_name != NULL && *name_list[i].n_name != '\0'; i++) 418 1.39 dsl if (name_list[i].n_value == 0) 419 1.39 dsl mvprintw(2 + ++n, 10, "%s", name_list[i].n_name); 420 1.1 jtc move(CMDLINE, 0); 421 1.1 jtc clrtoeol(); 422 1.1 jtc refresh(); 423 1.1 jtc endwin(); 424 1.56 christos exit(EXIT_FAILURE); 425 1.1 jtc } 426 1.55 christos 427 1.55 christos bool 428 1.55 christos toofast(int *failcnt) 429 1.55 christos { 430 1.55 christos static char pigs[] = "pigs"; 431 1.55 christos etime = cur.cp_etime; 432 1.55 christos /* < 1 ticks - sleep for a tick */ 433 1.55 christos /* this is often triggered by repeated SIGWINCH */ 434 1.55 christos if ((etime * hertz) >= 1.0) 435 1.55 christos return false; 436 1.55 christos 437 1.55 christos if ((*failcnt)++ <= MAXFAIL) { 438 1.55 christos struct timespec interval = { 0, 1000000000L / hertz }; 439 1.55 christos while (nanosleep(&interval, &interval) == -1) 440 1.55 christos continue; 441 1.55 christos return true; 442 1.55 christos } 443 1.55 christos clear(); 444 1.55 christos mvprintw(2, 10, "The alternate system clock has died!"); 445 1.55 christos mvprintw(3, 10, "Reverting to ``pigs'' display."); 446 1.55 christos move(CMDLINE, 0); 447 1.55 christos refresh(); 448 1.55 christos failcnt = 0; 449 1.55 christos sleep(5); 450 1.55 christos command(pigs); 451 1.55 christos return true; 452 1.55 christos } 453