main.c revision 1.35
1/* $OpenBSD: main.c,v 1.35 2007/02/25 18:21:24 deraadt Exp $ */ 2/* $NetBSD: main.c,v 1.8 1996/05/10 23:16:36 thorpej Exp $ */ 3 4/*- 5 * Copyright (c) 1980, 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static char copyright[] = 35"@(#) Copyright (c) 1980, 1992, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /* not lint */ 38 39#ifndef lint 40#if 0 41static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 42#endif 43static char rcsid[] = "$OpenBSD: main.c,v 1.35 2007/02/25 18:21:24 deraadt Exp $"; 44#endif /* not lint */ 45 46#include <sys/param.h> 47#include <sys/sysctl.h> 48 49#include <err.h> 50#include <nlist.h> 51#include <signal.h> 52#include <ctype.h> 53#include <stdio.h> 54#include <string.h> 55#include <unistd.h> 56#include <utmp.h> 57#include <stdlib.h> 58#include <limits.h> 59#include <stdarg.h> 60 61#include "systat.h" 62#include "extern.h" 63 64double dellave; 65 66kvm_t *kd; 67char *nlistf = NULL; 68char *memf = NULL; 69double avenrun[3]; 70u_int naptime = 5; 71int verbose = 1; /* to report kvm read errs */ 72int nflag = 0; 73int ut, hz, stathz; 74char hostname[MAXHOSTNAMELEN]; 75WINDOW *wnd; 76int CMDLINE; 77 78WINDOW *wload; /* one line window for load average */ 79 80static void usage(void); 81 82int 83main(int argc, char *argv[]) 84{ 85 char errbuf[_POSIX2_LINE_MAX]; 86 const char *errstr; 87 gid_t gid; 88 int ch; 89 90 ut = open(_PATH_UTMP, O_RDONLY); 91 if (ut < 0) { 92 error("No utmp"); 93 exit(1); 94 } 95 96 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 97 if (kd == NULL) { 98 error("%s", errbuf); 99 exit(1); 100 } 101 102 gid = getgid(); 103 if (setresgid(gid, gid, gid) == -1) 104 err(1, "setresgid"); 105 106 while ((ch = getopt(argc, argv, "nw:")) != -1) 107 switch (ch) { 108 case 'n': 109 nflag = 1; 110 break; 111 case 'w': 112 naptime = (u_int)strtonum(optarg, 1, 1000, &errstr); 113 if (errstr) 114 errx(1, "interval %s: %s", errstr, optarg); 115 break; 116 default: 117 usage(); 118 } 119 argc -= optind; 120 argv += optind; 121 122 while (argc > 0) { 123 if (isdigit(argv[0][0])) { 124 naptime = (u_int)strtonum(argv[0], 1, 1000, &errstr); 125 if (errstr) 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--; 138 argv++; 139 } 140 141 signal(SIGINT, sigdie); 142 siginterrupt(SIGINT, 1); 143 signal(SIGQUIT, sigdie); 144 siginterrupt(SIGQUIT, 1); 145 signal(SIGTERM, sigdie); 146 siginterrupt(SIGTERM, 1); 147 signal(SIGTSTP, sigtstp); 148 siginterrupt(SIGTSTP, 1); 149 150 /* 151 * Initialize display. Load average appears in a one line 152 * window of its own. Current command's display appears in 153 * an overlapping sub-window of stdscr configured by the display 154 * routines to minimize update work by curses. 155 */ 156 if (initscr() == NULL) { 157 warnx("couldn't initialize screen"); 158 exit(0); 159 } 160 161 CMDLINE = LINES - 1; 162 wnd = (*curcmd->c_open)(); 163 if (wnd == NULL) { 164 warnx("couldn't initialize display"); 165 die(); 166 } 167 wload = newwin(1, 0, 1, 20); 168 if (wload == NULL) { 169 warnx("couldn't set up load average window"); 170 die(); 171 } 172 gethostname(hostname, sizeof (hostname)); 173 gethz(); 174 (*curcmd->c_init)(); 175 curcmd->c_flags |= CF_INIT; 176 labels(); 177 178 dellave = 0.0; 179 180 signal(SIGALRM, sigdisplay); 181 siginterrupt(SIGALRM, 1); 182 signal(SIGWINCH, sigwinch); 183 siginterrupt(SIGWINCH, 1); 184 gotdisplay = 1; 185 noecho(); 186 crmode(); 187 keyboard(); 188 /*NOTREACHED*/ 189} 190 191void 192gethz(void) 193{ 194 struct clockinfo cinf; 195 size_t size = sizeof(cinf); 196 int mib[2]; 197 198 mib[0] = CTL_KERN; 199 mib[1] = KERN_CLOCKRATE; 200 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 201 return; 202 stathz = cinf.stathz; 203 hz = cinf.hz; 204} 205 206static void 207usage(void) 208{ 209 fprintf(stderr, "usage: systat [-n] [-w wait] [display] [refresh-interval]\n"); 210 exit(1); 211} 212 213 214void 215labels(void) 216{ 217 if (curcmd->c_flags & CF_LOADAV) 218 mvprintw(0, 2 + 4, "users Load"); 219 (*curcmd->c_label)(); 220#ifdef notdef 221 mvprintw(21, 25, "CPU usage on %s", hostname); 222#endif 223 refresh(); 224} 225 226/*ARGSUSED*/ 227void 228sigdisplay(int signo) 229{ 230 gotdisplay = 1; 231} 232 233void 234display(void) 235{ 236 /* Get the load average over the last minute. */ 237 (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 238 (*curcmd->c_fetch)(); 239 if (curcmd->c_flags & CF_LOADAV) { 240 extern int ucount(); 241 char tbuf[26]; 242 time_t now; 243 244 time(&now); 245 strlcpy(tbuf, ctime(&now), sizeof tbuf); 246 247 putint(ucount(), 0, 2, 3); 248 putfloat(avenrun[0], 0, 2 + 17, 6, 2, 0); 249 putfloat(avenrun[1], 0, 2 + 23, 6, 2, 0); 250 putfloat(avenrun[2], 0, 2 + 29, 6, 2, 0); 251 mvaddstr(0, 2 + 53, tbuf); 252 } 253 (*curcmd->c_refresh)(); 254 if (curcmd->c_flags & CF_LOADAV) 255 wrefresh(wload); 256 wrefresh(wnd); 257 move(CMDLINE, 0); 258 refresh(); 259 alarm(naptime); 260} 261 262void 263load(void) 264{ 265 266 (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); 267 mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", 268 avenrun[0], avenrun[1], avenrun[2]); 269 clrtoeol(); 270} 271 272volatile sig_atomic_t gotdie; 273volatile sig_atomic_t gotdisplay; 274volatile sig_atomic_t gotwinch; 275volatile sig_atomic_t gottstp; 276 277/*ARGSUSED*/ 278void 279sigdie(int signo) 280{ 281 gotdie = 1; 282} 283 284/*ARGSUSED*/ 285void 286sigtstp(int signo) 287{ 288 gottstp = 1; 289} 290 291void 292die(void) 293{ 294 if (wnd) { 295 move(CMDLINE, 0); 296 clrtoeol(); 297 refresh(); 298 endwin(); 299 } 300 exit(0); 301} 302 303/*ARGSUSED*/ 304void 305sigwinch(int signo) 306{ 307 gotwinch = 1; 308} 309 310void 311error(const char *fmt, ...) 312{ 313 va_list ap; 314 char buf[255]; 315 int oy, ox; 316 317 va_start(ap, fmt); 318 if (wnd) { 319 getyx(stdscr, oy, ox); 320 (void) vsnprintf(buf, sizeof buf, fmt, ap); 321 clrtoeol(); 322 standout(); 323 mvaddstr(CMDLINE, 0, buf); 324 standend(); 325 move(oy, ox); 326 refresh(); 327 } else { 328 (void) vfprintf(stderr, fmt, ap); 329 fprintf(stderr, "\n"); 330 } 331 va_end(ap); 332} 333 334void 335nlisterr(struct nlist namelist[]) 336{ 337 int i, n; 338 339 n = 0; 340 clear(); 341 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 342 for (i = 0; 343 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 344 if (namelist[i].n_value == 0) 345 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 346 move(CMDLINE, 0); 347 clrtoeol(); 348 refresh(); 349 endwin(); 350 exit(1); 351} 352 353/* calculate number of users on the system */ 354int 355ucount(void) 356{ 357 int nusers = 0; 358 struct utmp utmp; 359 360 if (ut < 0) 361 return (0); 362 lseek(ut, (off_t)0, SEEK_SET); 363 while (read(ut, &utmp, sizeof(utmp))) 364 if (utmp.ut_name[0] != '\0') 365 nusers++; 366 367 return (nusers); 368} 369