main.c revision 1.49
1/* $Id: main.c,v 1.49 2008/11/04 19:00:08 espie 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/param.h> 35#include <sys/sysctl.h> 36 37 38#include <ctype.h> 39#include <curses.h> 40#include <err.h> 41#include <errno.h> 42#include <fcntl.h> 43#include <limits.h> 44#include <netdb.h> 45#include <signal.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <stdarg.h> 50#include <unistd.h> 51#include <utmp.h> 52 53#include "engine.h" 54#include "systat.h" 55 56double dellave; 57 58kvm_t *kd; 59char *nlistf = NULL; 60char *memf = NULL; 61double avenrun[3]; 62double naptime = 5.0; 63int verbose = 1; /* to report kvm read errs */ 64int nflag = 1; 65int ut, hz, stathz; 66char hostname[MAXHOSTNAMELEN]; 67WINDOW *wnd; 68int CMDLINE; 69 70#define TIMEPOS 55 71 72/* command prompt */ 73 74void cmd_delay(const char *); 75void cmd_count(const char *); 76void cmd_compat(const char *); 77 78struct command cm_compat = {"Command", cmd_compat}; 79struct command cm_delay = {"Seconds to delay", cmd_delay}; 80struct command cm_count = {"Number of lines to display", cmd_count}; 81 82 83/* display functions */ 84 85int 86print_header(void) 87{ 88 struct tm *tp; 89 time_t t, now; 90 order_type *ordering; 91 int start = dispstart + 1, end = dispstart + maxprint; 92 extern int ucount(); 93 char tbuf[26]; 94 95 if (end > num_disp) 96 end = num_disp; 97 98 tb_start(); 99 100#if 0 101 if (curr_mgr && curr_mgr->sort_fn != NULL) { 102 ordering = curr_mgr->order_curr; 103 if (ordering != NULL) { 104 tbprintf(", Order: %s", ordering->name); 105 if (sortdir < 0 && ordering->func != NULL) 106 tbprintf(" (rev)"); 107 } 108 } 109#endif 110 111 getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 112 113 time(&now); 114 strlcpy(tbuf, ctime(&now), sizeof tbuf); 115 tbprintf(" %d users", ucount()); 116 tbprintf(" Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]); 117 if (num_disp && (start > 1 || end != num_disp)) 118 tbprintf(" (%u-%u of %u)", start, end, num_disp); 119 120 if (paused) 121 tbprintf(" PAUSED"); 122 123 if (rawmode) 124 printf("\n\n%s\n", tmp_buf); 125 else 126 mvprintw(0, 0, "%s", tmp_buf); 127 128 mvprintw(0, TIMEPOS, "%s", tbuf); 129 130 131 return (1); 132} 133 134/* compatibility functions, rearrange later */ 135void 136error(const char *fmt, ...) 137{ 138 va_list ap; 139 char buf[MAX_LINE_BUF]; 140 141 va_start(ap, fmt); 142 vsnprintf(buf, sizeof buf, fmt, ap); 143 va_end(ap); 144 145 message_set(buf); 146} 147 148void 149nlisterr(struct nlist namelist[]) 150{ 151 int i, n; 152 153 n = 0; 154 clear(); 155 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 156 for (i = 0; 157 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 158 if (namelist[i].n_value == 0) 159 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 160 move(CMDLINE, 0); 161 clrtoeol(); 162 refresh(); 163 endwin(); 164 exit(1); 165} 166 167void 168die(void) 169{ 170 if (!rawmode) 171 endwin(); 172 exit(0); 173} 174 175 176int 177prefix(char *s1, char *s2) 178{ 179 180 while (*s1 == *s2) { 181 if (*s1 == '\0') 182 return (1); 183 s1++, s2++; 184 } 185 return (*s1 == '\0'); 186} 187 188/* calculate number of users on the system */ 189int 190ucount(void) 191{ 192 int nusers = 0; 193 struct utmp utmp; 194 195 if (ut < 0) 196 return (0); 197 lseek(ut, (off_t)0, SEEK_SET); 198 while (read(ut, &utmp, sizeof(utmp))) 199 if (utmp.ut_name[0] != '\0') 200 nusers++; 201 202 return (nusers); 203} 204 205/* main program functions */ 206 207void 208usage() 209{ 210 extern char *__progname; 211 fprintf(stderr, "usage: %s [-abin] [-d count] " 212 "[-s delay] [-w width] [view] [delay]\n", __progname); 213 exit(1); 214} 215 216void 217show_view(void) 218{ 219 if (rawmode) 220 return; 221 222 tb_start(); 223 tbprintf("%s %g", curr_view->name, naptime); 224 tb_end(); 225 message_set(tmp_buf); 226} 227 228void 229add_view_tb(field_view *v) 230{ 231 if (curr_view == v) 232 tbprintf("[%s] ", v->name); 233 else 234 tbprintf("%s ", v->name); 235} 236 237void 238show_help(void) 239{ 240 int line = 0; 241 242 if (rawmode) 243 return; 244 245 tb_start(); 246 foreach_view(add_view_tb); 247 tb_end(); 248 message_set(tmp_buf); 249} 250 251void 252cmd_compat(const char *buf) 253{ 254 const char *s; 255 256 if (strcasecmp(buf, "help") == 0) { 257 show_help(); 258 need_update = 1; 259 return; 260 } 261 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 262 gotsig_close = 1; 263 return; 264 } 265 if (strcasecmp(buf, "stop") == 0) { 266 paused = 1; 267 gotsig_alarm = 1; 268 return; 269 } 270 if (strncasecmp(buf, "start", 5) == 0) { 271 paused = 0; 272 gotsig_alarm = 1; 273 cmd_delay(buf + 5); 274 return; 275 } 276 277 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 278 ; 279 if (*s) { 280 if (set_view(buf)) 281 error("Invalid/ambiguous view: %s", buf); 282 } else 283 cmd_delay(buf); 284} 285 286void 287cmd_delay(const char *buf) 288{ 289 double del; 290 del = atof(buf); 291 292 if (del > 0) { 293 udelay = (useconds_t)(del * 1000000); 294 gotsig_alarm = 1; 295 naptime = del; 296 } 297} 298 299void 300cmd_count(const char *buf) 301{ 302 int ms; 303 ms = atoi(buf); 304 305 if (ms <= 0 || ms > lines - HEADER_LINES) 306 maxprint = lines - HEADER_LINES; 307 else 308 maxprint = ms; 309} 310 311 312int 313keyboard_callback(int ch) 314{ 315 switch (ch) { 316 case '?': 317 /* FALLTHROUGH */ 318 case 'h': 319 show_help(); 320 need_update = 1; 321 break; 322 case CTRL_G: 323 show_view(); 324 need_update = 1; 325 break; 326 case 'l': 327 command_set(&cm_count, NULL); 328 break; 329 case 's': 330 command_set(&cm_delay, NULL); 331 break; 332 case ':': 333 command_set(&cm_compat, NULL); 334 break; 335 default: 336 return 0; 337 }; 338 339 return 1; 340} 341 342void 343initialize(void) 344{ 345 engine_initialize(); 346 347 initvmstat(); 348 initpigs(); 349 initifstat(); 350 initiostat(); 351 initsensors(); 352 initmembufs(); 353 initnetstat(); 354 initswap(); 355 initpftop(); 356 initpf(); 357 initpool(); 358} 359 360void 361gethz(void) 362{ 363 struct clockinfo cinf; 364 size_t size = sizeof(cinf); 365 int mib[2]; 366 367 mib[0] = CTL_KERN; 368 mib[1] = KERN_CLOCKRATE; 369 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 370 return; 371 stathz = cinf.stathz; 372 hz = cinf.hz; 373} 374 375int 376main(int argc, char *argv[]) 377{ 378 char errbuf[_POSIX2_LINE_MAX]; 379 extern char *optarg; 380 extern int optind; 381 double delay = 5; 382 383 char *viewstr = NULL; 384 385 gid_t gid; 386 int countmax = 0; 387 int maxlines = 0; 388 389 int ch; 390 391 ut = open(_PATH_UTMP, O_RDONLY); 392 if (ut < 0) { 393 warn("No utmp"); 394 } 395 396 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 397 398 gid = getgid(); 399 if (setresgid(gid, gid, gid) == -1) 400 err(1, "setresgid"); 401 402 while ((ch = getopt(argc, argv, "abd:ins:w:")) != -1) { 403 switch (ch) { 404 case 'a': 405 maxlines = -1; 406 break; 407 case 'b': 408 rawmode = 1; 409 interactive = 0; 410 break; 411 case 'd': 412 countmax = atoi(optarg); 413 if (countmax < 0) 414 countmax = 0; 415 break; 416 case 'i': 417 interactive = 1; 418 break; 419 case 'n': 420 nflag = 1; 421 break; 422 case 's': 423 delay = atof(optarg); 424 if (delay <= 0) 425 delay = 5; 426 break; 427 case 'w': 428 rawwidth = atoi(optarg); 429 if (rawwidth < 1) 430 rawwidth = DEFAULT_WIDTH; 431 if (rawwidth >= MAX_LINE_BUF) 432 rawwidth = MAX_LINE_BUF - 1; 433 break; 434 default: 435 usage(); 436 /* NOTREACHED */ 437 } 438 } 439 440 if (kd == NULL) 441 warnx("kvm_openfiles: %s", errbuf); 442 443 argc -= optind; 444 argv += optind; 445 446 if (argc == 1) { 447 double del = atof(argv[0]); 448 if (del == 0) 449 viewstr = argv[0]; 450 else 451 delay = del; 452 } else if (argc == 2) { 453 viewstr = argv[0]; 454 delay = atof(argv[1]); 455 if (delay <= 0) 456 delay = 5; 457 } 458 459 udelay = (useconds_t)(delay * 1000000.0); 460 if (udelay < 1) 461 udelay = 1; 462 463 naptime = (double)udelay / 1000000.0; 464 465 gethostname(hostname, sizeof (hostname)); 466 gethz(); 467 468 initialize(); 469 470 set_order(NULL); 471 if (viewstr && set_view(viewstr)) { 472 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 473 return 1; 474 } 475 476 if (!isatty(STDOUT_FILENO)) { 477 rawmode = 1; 478 interactive = 0; 479 } 480 481 setup_term(maxlines); 482 483 if (rawmode && countmax == 0) 484 countmax = 1; 485 486 gotsig_alarm = 1; 487 488 engine_loop(countmax); 489 490 return 0; 491} 492