main.c revision 1.62
1/* $Id: main.c,v 1.62 2015/03/12 01:03:00 claudio 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 int ms; 300 ms = atoi(buf); 301 302 if (ms <= 0 || ms > lines - HEADER_LINES) 303 maxprint = lines - HEADER_LINES; 304 else 305 maxprint = ms; 306} 307 308 309int 310keyboard_callback(int ch) 311{ 312 switch (ch) { 313 case '?': 314 /* FALLTHROUGH */ 315 case 'h': 316 show_help(); 317 need_update = 1; 318 break; 319 case CTRL_G: 320 show_view(); 321 need_update = 1; 322 break; 323 case 'l': 324 command_set(&cm_count, NULL); 325 break; 326 case 's': 327 command_set(&cm_delay, NULL); 328 break; 329 case ',': 330 separate_thousands = !separate_thousands; 331 gotsig_alarm = 1; 332 break; 333 case ':': 334 command_set(&cm_compat, NULL); 335 break; 336 default: 337 return 0; 338 }; 339 340 return 1; 341} 342 343void 344initialize(void) 345{ 346 engine_initialize(); 347 348 initvmstat(); 349 initpigs(); 350 initifstat(); 351 initiostat(); 352 initsensors(); 353 initmembufs(); 354 initnetstat(); 355 initswap(); 356 initpftop(); 357 initpf(); 358 initpool(); 359 initmalloc(); 360 initnfs(); 361 initcpu(); 362} 363 364void 365gethz(void) 366{ 367 struct clockinfo cinf; 368 size_t size = sizeof(cinf); 369 int mib[2]; 370 371 mib[0] = CTL_KERN; 372 mib[1] = KERN_CLOCKRATE; 373 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 374 return; 375 stathz = cinf.stathz; 376 hz = cinf.hz; 377} 378 379int 380main(int argc, char *argv[]) 381{ 382 char errbuf[_POSIX2_LINE_MAX]; 383 extern char *optarg; 384 extern int optind; 385 double delay = 5; 386 387 char *viewstr = NULL; 388 389 gid_t gid; 390 int countmax = 0; 391 int maxlines = 0; 392 393 int ch; 394 395 ut = open(_PATH_UTMP, O_RDONLY); 396 if (ut < 0) { 397 warn("No utmp"); 398 } 399 400 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 401 402 gid = getgid(); 403 if (setresgid(gid, gid, gid) == -1) 404 err(1, "setresgid"); 405 406 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 407 switch (ch) { 408 case 'a': 409 maxlines = -1; 410 break; 411 case 'B': 412 averageonly = 1; 413 if (countmax < 2) 414 countmax = 2; 415 /* FALLTHROUGH */ 416 case 'b': 417 rawmode = 1; 418 interactive = 0; 419 break; 420 case 'd': 421 countmax = atoi(optarg); 422 if (countmax < 0) 423 countmax = 0; 424 break; 425 case 'i': 426 interactive = 1; 427 break; 428 case 'N': 429 nflag = 0; 430 break; 431 case 'n': 432 /* this is a noop, -n is the default */ 433 nflag = 1; 434 break; 435 case 's': 436 delay = atof(optarg); 437 if (delay <= 0) 438 delay = 5; 439 break; 440 case 'w': 441 rawwidth = atoi(optarg); 442 if (rawwidth < 1) 443 rawwidth = DEFAULT_WIDTH; 444 if (rawwidth >= MAX_LINE_BUF) 445 rawwidth = MAX_LINE_BUF - 1; 446 break; 447 default: 448 usage(); 449 /* NOTREACHED */ 450 } 451 } 452 453 if (kd == NULL) 454 warnx("kvm_openfiles: %s", errbuf); 455 456 argc -= optind; 457 argv += optind; 458 459 if (argc == 1) { 460 double del = atof(argv[0]); 461 if (del == 0) 462 viewstr = argv[0]; 463 else 464 delay = del; 465 } else if (argc == 2) { 466 viewstr = argv[0]; 467 delay = atof(argv[1]); 468 if (delay <= 0) 469 delay = 5; 470 } 471 472 udelay = (useconds_t)(delay * 1000000.0); 473 if (udelay < 1) 474 udelay = 1; 475 476 naptime = (double)udelay / 1000000.0; 477 478 gethostname(hostname, sizeof (hostname)); 479 gethz(); 480 481 initialize(); 482 483 set_order(NULL); 484 if (viewstr && set_view(viewstr)) { 485 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 486 return 1; 487 } 488 489 if (check_termcap()) { 490 rawmode = 1; 491 interactive = 0; 492 } 493 494 setup_term(maxlines); 495 496 if (rawmode && countmax == 0) 497 countmax = 1; 498 499 gotsig_alarm = 1; 500 501 engine_loop(countmax); 502 503 return 0; 504} 505