main.c revision 1.64
1/* $Id: main.c,v 1.64 2016/01/02 15:02:05 benno Exp $ */ 2/* 3 * Copyright (c) 2001, 2007 Can Erkin Acar 4 * Copyright (c) 2001 Daniel Hartmeier 5 * 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 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33#include <sys/types.h> 34#include <sys/sysctl.h> 35 36 37#include <ctype.h> 38#include <curses.h> 39#include <err.h> 40#include <errno.h> 41#include <fcntl.h> 42#include <limits.h> 43#include <netdb.h> 44#include <signal.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <stdarg.h> 49#include <unistd.h> 50#include <utmp.h> 51 52#include "engine.h" 53#include "systat.h" 54 55#define TIMEPOS 55 56 57double dellave; 58 59kvm_t *kd; 60char *nlistf = NULL; 61char *memf = NULL; 62double avenrun[3]; 63double naptime = 5.0; 64int verbose = 1; /* to report kvm read errs */ 65int nflag = 1; 66int ut, hz, stathz; 67char hostname[HOST_NAME_MAX+1]; 68WINDOW *wnd; 69int CMDLINE; 70char timebuf[26]; 71char uloadbuf[TIMEPOS]; 72 73 74int ucount(void); 75void usage(void); 76 77/* command prompt */ 78 79void cmd_delay(const char *); 80void cmd_count(const char *); 81void cmd_compat(const char *); 82 83struct command cm_compat = {"Command", cmd_compat}; 84struct command cm_delay = {"Seconds to delay", cmd_delay}; 85struct command cm_count = {"Number of lines to display", cmd_count}; 86 87 88/* display functions */ 89 90int 91print_header(void) 92{ 93 time_t now; 94 int start = dispstart + 1, end = dispstart + maxprint; 95 char tmpbuf[TIMEPOS]; 96 char header[MAX_LINE_BUF]; 97 98 if (end > num_disp) 99 end = num_disp; 100 101 tb_start(); 102 103 if (!paused) { 104 getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 105 106 snprintf(uloadbuf, sizeof(uloadbuf), 107 "%5d users Load %.2f %.2f %.2f", 108 ucount(), avenrun[0], avenrun[1], avenrun[2]); 109 110 time(&now); 111 strlcpy(timebuf, ctime(&now), sizeof(timebuf)); 112 } 113 114 if (num_disp && (start > 1 || end != num_disp)) 115 snprintf(tmpbuf, sizeof(tmpbuf), 116 "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp, 117 paused ? "PAUSED" : ""); 118 else 119 snprintf(tmpbuf, sizeof(tmpbuf), 120 "%s %s", uloadbuf, 121 paused ? "PAUSED" : ""); 122 123 snprintf(header, sizeof(header), "%-55s%s", tmpbuf, timebuf); 124 125 if (rawmode) 126 printf("\n\n%s\n", header); 127 else 128 mvprintw(0, 0, "%s", header); 129 130 return (1); 131} 132 133/* compatibility functions, rearrange later */ 134void 135error(const char *fmt, ...) 136{ 137 va_list ap; 138 char buf[MAX_LINE_BUF]; 139 140 va_start(ap, fmt); 141 vsnprintf(buf, sizeof buf, fmt, ap); 142 va_end(ap); 143 144 message_set(buf); 145} 146 147void 148nlisterr(struct nlist namelist[]) 149{ 150 int i, n; 151 152 n = 0; 153 clear(); 154 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 155 for (i = 0; 156 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 157 if (namelist[i].n_value == 0) 158 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 159 move(CMDLINE, 0); 160 clrtoeol(); 161 refresh(); 162 endwin(); 163 exit(1); 164} 165 166void 167die(void) 168{ 169 if (!rawmode) 170 endwin(); 171 exit(0); 172} 173 174 175int 176prefix(char *s1, char *s2) 177{ 178 179 while (*s1 == *s2) { 180 if (*s1 == '\0') 181 return (1); 182 s1++, s2++; 183 } 184 return (*s1 == '\0'); 185} 186 187/* calculate number of users on the system */ 188int 189ucount(void) 190{ 191 int nusers = 0; 192 struct utmp utmp; 193 194 if (ut < 0) 195 return (0); 196 lseek(ut, (off_t)0, SEEK_SET); 197 while (read(ut, &utmp, sizeof(utmp))) 198 if (utmp.ut_name[0] != '\0') 199 nusers++; 200 201 return (nusers); 202} 203 204/* main program functions */ 205 206void 207usage(void) 208{ 209 extern char *__progname; 210 fprintf(stderr, "usage: %s [-aBbiNn] [-d count] " 211 "[-s delay] [-w width] [view] [delay]\n", __progname); 212 exit(1); 213} 214 215void 216show_view(void) 217{ 218 if (rawmode) 219 return; 220 221 tb_start(); 222 tbprintf("%s %g", curr_view->name, naptime); 223 tb_end(); 224 message_set(tmp_buf); 225} 226 227void 228add_view_tb(field_view *v) 229{ 230 if (curr_view == v) 231 tbprintf("[%s] ", v->name); 232 else 233 tbprintf("%s ", v->name); 234} 235 236void 237show_help(void) 238{ 239 if (rawmode) 240 return; 241 242 tb_start(); 243 foreach_view(add_view_tb); 244 tb_end(); 245 message_set(tmp_buf); 246} 247 248void 249cmd_compat(const char *buf) 250{ 251 const char *s; 252 253 if (strcasecmp(buf, "help") == 0) { 254 show_help(); 255 need_update = 1; 256 return; 257 } 258 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 259 gotsig_close = 1; 260 return; 261 } 262 if (strcasecmp(buf, "stop") == 0) { 263 paused = 1; 264 gotsig_alarm = 1; 265 return; 266 } 267 if (strncasecmp(buf, "start", 5) == 0) { 268 paused = 0; 269 gotsig_alarm = 1; 270 cmd_delay(buf + 5); 271 return; 272 } 273 274 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 275 ; 276 if (*s) { 277 if (set_view(buf)) 278 error("Invalid/ambiguous view: %s", buf); 279 } else 280 cmd_delay(buf); 281} 282 283void 284cmd_delay(const char *buf) 285{ 286 double del; 287 del = atof(buf); 288 289 if (del > 0) { 290 udelay = (useconds_t)(del * 1000000); 291 gotsig_alarm = 1; 292 naptime = del; 293 } 294} 295 296void 297cmd_count(const char *buf) 298{ 299 const char *errstr; 300 301 maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr); 302 if (errstr) 303 maxprint = lines - HEADER_LINES; 304} 305 306 307int 308keyboard_callback(int ch) 309{ 310 switch (ch) { 311 case '?': 312 /* FALLTHROUGH */ 313 case 'h': 314 show_help(); 315 need_update = 1; 316 break; 317 case CTRL_G: 318 show_view(); 319 need_update = 1; 320 break; 321 case 'l': 322 command_set(&cm_count, NULL); 323 break; 324 case 's': 325 command_set(&cm_delay, NULL); 326 break; 327 case ',': 328 separate_thousands = !separate_thousands; 329 gotsig_alarm = 1; 330 break; 331 case ':': 332 command_set(&cm_compat, NULL); 333 break; 334 default: 335 return 0; 336 }; 337 338 return 1; 339} 340 341void 342initialize(void) 343{ 344 engine_initialize(); 345 346 initvmstat(); 347 initpigs(); 348 initifstat(); 349 initiostat(); 350 initsensors(); 351 initmembufs(); 352 initnetstat(); 353 initswap(); 354 initpftop(); 355 initpf(); 356 initpool(); 357 initmalloc(); 358 initnfs(); 359 initcpu(); 360} 361 362void 363gethz(void) 364{ 365 struct clockinfo cinf; 366 size_t size = sizeof(cinf); 367 int mib[2]; 368 369 mib[0] = CTL_KERN; 370 mib[1] = KERN_CLOCKRATE; 371 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 372 return; 373 stathz = cinf.stathz; 374 hz = cinf.hz; 375} 376 377int 378main(int argc, char *argv[]) 379{ 380 char errbuf[_POSIX2_LINE_MAX]; 381 const char *errstr; 382 extern char *optarg; 383 extern int optind; 384 double delay = 5; 385 386 char *viewstr = NULL; 387 388 gid_t gid; 389 int countmax = 0; 390 int maxlines = 0; 391 392 int ch; 393 394 ut = open(_PATH_UTMP, O_RDONLY); 395 if (ut < 0) { 396 warn("No utmp"); 397 } 398 399 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 400 401 gid = getgid(); 402 if (setresgid(gid, gid, gid) == -1) 403 err(1, "setresgid"); 404 405 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 406 switch (ch) { 407 case 'a': 408 maxlines = -1; 409 break; 410 case 'B': 411 averageonly = 1; 412 if (countmax < 2) 413 countmax = 2; 414 /* FALLTHROUGH */ 415 case 'b': 416 rawmode = 1; 417 interactive = 0; 418 break; 419 case 'd': 420 countmax = strtonum(optarg, 1, INT_MAX, &errstr); 421 if (errstr) 422 errx(1, "-d %s: %s", optarg, errstr); 423 break; 424 case 'i': 425 interactive = 1; 426 break; 427 case 'N': 428 nflag = 0; 429 break; 430 case 'n': 431 /* this is a noop, -n is the default */ 432 nflag = 1; 433 break; 434 case 's': 435 delay = atof(optarg); 436 if (delay <= 0) 437 delay = 5; 438 break; 439 case 'w': 440 rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr); 441 if (errstr) 442 errx(1, "-w %s: %s", optarg, errstr); 443 break; 444 default: 445 usage(); 446 /* NOTREACHED */ 447 } 448 } 449 450 if (kd == NULL) 451 warnx("kvm_openfiles: %s", errbuf); 452 453 argc -= optind; 454 argv += optind; 455 456 if (argc == 1) { 457 double del = atof(argv[0]); 458 if (del == 0) 459 viewstr = argv[0]; 460 else 461 delay = del; 462 } else if (argc == 2) { 463 viewstr = argv[0]; 464 delay = atof(argv[1]); 465 if (delay <= 0) 466 delay = 5; 467 } 468 469 udelay = (useconds_t)(delay * 1000000.0); 470 if (udelay < 1) 471 udelay = 1; 472 473 naptime = (double)udelay / 1000000.0; 474 475 gethostname(hostname, sizeof (hostname)); 476 gethz(); 477 478 initialize(); 479 480 set_order(NULL); 481 if (viewstr && set_view(viewstr)) { 482 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 483 return 1; 484 } 485 486 if (check_termcap()) { 487 rawmode = 1; 488 interactive = 0; 489 } 490 491 setup_term(maxlines); 492 493 if (rawmode && countmax == 0) 494 countmax = 1; 495 496 gotsig_alarm = 1; 497 498 engine_loop(countmax); 499 500 return 0; 501} 502