main.c revision 1.68
1/* $Id: main.c,v 1.68 2018/05/30 13:43:51 krw 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 (80 - 8 - 20 - 1) 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 char *ctim; 105 106 getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 107 108 snprintf(uloadbuf, sizeof(uloadbuf), 109 "%4d users Load %.2f %.2f %.2f", 110 ucount(), avenrun[0], avenrun[1], avenrun[2]); 111 112 time(&now); 113 ctim = ctime(&now); 114 ctim[11+8] = '\0'; 115 strlcpy(timebuf, ctim + 11, sizeof(timebuf)); 116 } 117 118 if (num_disp && (start > 1 || end != num_disp)) 119 snprintf(tmpbuf, sizeof(tmpbuf), 120 "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp, 121 paused ? "PAUSED" : ""); 122 else 123 snprintf(tmpbuf, sizeof(tmpbuf), 124 "%s %s", uloadbuf, 125 paused ? "PAUSED" : ""); 126 127 snprintf(header, sizeof(header), "%-*s %19.19s %s", TIMEPOS - 1, 128 tmpbuf, hostname, timebuf); 129 130 if (rawmode) 131 printf("\n\n%s\n", header); 132 else 133 mvprintw(0, 0, "%s", header); 134 135 return (1); 136} 137 138/* compatibility functions, rearrange later */ 139void 140error(const char *fmt, ...) 141{ 142 va_list ap; 143 char buf[MAX_LINE_BUF]; 144 145 va_start(ap, fmt); 146 vsnprintf(buf, sizeof buf, fmt, ap); 147 va_end(ap); 148 149 message_set(buf); 150} 151 152void 153nlisterr(struct nlist namelist[]) 154{ 155 int i, n; 156 157 n = 0; 158 clear(); 159 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 160 for (i = 0; 161 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 162 if (namelist[i].n_value == 0) 163 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 164 move(CMDLINE, 0); 165 clrtoeol(); 166 refresh(); 167 endwin(); 168 exit(1); 169} 170 171void 172die(void) 173{ 174 if (!rawmode) 175 endwin(); 176 exit(0); 177} 178 179 180int 181prefix(char *s1, char *s2) 182{ 183 184 while (*s1 == *s2) { 185 if (*s1 == '\0') 186 return (1); 187 s1++, s2++; 188 } 189 return (*s1 == '\0'); 190} 191 192/* calculate number of users on the system */ 193int 194ucount(void) 195{ 196 int nusers = 0; 197 struct utmp utmp; 198 199 if (ut < 0) 200 return (0); 201 lseek(ut, (off_t)0, SEEK_SET); 202 while (read(ut, &utmp, sizeof(utmp))) 203 if (utmp.ut_name[0] != '\0') 204 nusers++; 205 206 return (nusers); 207} 208 209/* main program functions */ 210 211void 212usage(void) 213{ 214 extern char *__progname; 215 fprintf(stderr, "usage: %s [-aBbiNn] [-d count] " 216 "[-s delay] [-w width] [view] [delay]\n", __progname); 217 exit(1); 218} 219 220void 221show_view(void) 222{ 223 if (rawmode) 224 return; 225 226 tb_start(); 227 tbprintf("%s %g", curr_view->name, naptime); 228 tb_end(); 229 message_set(tmp_buf); 230} 231 232void 233add_view_tb(field_view *v) 234{ 235 if (curr_view == v) 236 tbprintf("[%s] ", v->name); 237 else 238 tbprintf("%s ", v->name); 239} 240 241void 242show_help(void) 243{ 244 if (rawmode) 245 return; 246 247 tb_start(); 248 foreach_view(add_view_tb); 249 tb_end(); 250 message_set(tmp_buf); 251} 252 253void 254add_order_tb(order_type *o) 255{ 256 if (curr_view->mgr->order_curr == o) 257 tbprintf("[%s%s(%c)] ", o->name, 258 o->func != NULL && sortdir == -1 ? "^" : "", 259 (char) o->hotkey); 260 else 261 tbprintf("%s(%c) ", o->name, (char) o->hotkey); 262} 263 264void 265show_order(void) 266{ 267 if (rawmode) 268 return; 269 270 tb_start(); 271 if (foreach_order(add_order_tb) == -1) { 272 tbprintf("No orders available"); 273 } 274 tb_end(); 275 message_set(tmp_buf); 276} 277 278void 279cmd_compat(const char *buf) 280{ 281 const char *s; 282 283 if (strcasecmp(buf, "help") == 0) { 284 show_help(); 285 need_update = 1; 286 return; 287 } 288 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 289 gotsig_close = 1; 290 return; 291 } 292 if (strcasecmp(buf, "stop") == 0) { 293 paused = 1; 294 gotsig_alarm = 1; 295 return; 296 } 297 if (strncasecmp(buf, "start", 5) == 0) { 298 paused = 0; 299 gotsig_alarm = 1; 300 cmd_delay(buf + 5); 301 return; 302 } 303 if (strncasecmp(buf, "order", 5) == 0) { 304 show_order(); 305 need_update = 1; 306 return; 307 } 308 309 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 310 ; 311 if (*s) { 312 if (set_view(buf)) 313 error("Invalid/ambiguous view: %s", buf); 314 } else 315 cmd_delay(buf); 316} 317 318void 319cmd_delay(const char *buf) 320{ 321 double del; 322 del = atof(buf); 323 324 if (del > 0) { 325 udelay = (useconds_t)(del * 1000000); 326 gotsig_alarm = 1; 327 naptime = del; 328 } 329} 330 331void 332cmd_count(const char *buf) 333{ 334 const char *errstr; 335 336 maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr); 337 if (errstr) 338 maxprint = lines - HEADER_LINES; 339} 340 341 342int 343keyboard_callback(int ch) 344{ 345 switch (ch) { 346 case '?': 347 /* FALLTHROUGH */ 348 case 'h': 349 show_help(); 350 need_update = 1; 351 break; 352 case CTRL_G: 353 show_view(); 354 need_update = 1; 355 break; 356 case 'l': 357 command_set(&cm_count, NULL); 358 break; 359 case 's': 360 command_set(&cm_delay, NULL); 361 break; 362 case ',': 363 separate_thousands = !separate_thousands; 364 gotsig_alarm = 1; 365 break; 366 case ':': 367 command_set(&cm_compat, NULL); 368 break; 369 default: 370 return 0; 371 }; 372 373 return 1; 374} 375 376void 377initialize(void) 378{ 379 engine_initialize(); 380 381 initvmstat(); 382 initpigs(); 383 initifstat(); 384 initiostat(); 385 initsensors(); 386 initmembufs(); 387 initnetstat(); 388 initswap(); 389 initpftop(); 390 initpf(); 391 initpool(); 392 initmalloc(); 393 initnfs(); 394 initcpu(); 395 inituvm(); 396} 397 398void 399gethz(void) 400{ 401 struct clockinfo cinf; 402 size_t size = sizeof(cinf); 403 int mib[2]; 404 405 mib[0] = CTL_KERN; 406 mib[1] = KERN_CLOCKRATE; 407 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 408 return; 409 stathz = cinf.stathz; 410 hz = cinf.hz; 411} 412 413int 414main(int argc, char *argv[]) 415{ 416 char errbuf[_POSIX2_LINE_MAX]; 417 const char *errstr; 418 extern char *optarg; 419 extern int optind; 420 double delay = 5; 421 422 char *viewstr = NULL; 423 424 gid_t gid; 425 int countmax = 0; 426 int maxlines = 0; 427 428 int ch; 429 430 ut = open(_PATH_UTMP, O_RDONLY); 431 if (ut < 0) { 432 warn("No utmp"); 433 } 434 435 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 436 437 gid = getgid(); 438 if (setresgid(gid, gid, gid) == -1) 439 err(1, "setresgid"); 440 441 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 442 switch (ch) { 443 case 'a': 444 maxlines = -1; 445 break; 446 case 'B': 447 averageonly = 1; 448 if (countmax < 2) 449 countmax = 2; 450 /* FALLTHROUGH */ 451 case 'b': 452 rawmode = 1; 453 interactive = 0; 454 break; 455 case 'd': 456 countmax = strtonum(optarg, 1, INT_MAX, &errstr); 457 if (errstr) 458 errx(1, "-d %s: %s", optarg, errstr); 459 break; 460 case 'i': 461 interactive = 1; 462 break; 463 case 'N': 464 nflag = 0; 465 break; 466 case 'n': 467 /* this is a noop, -n is the default */ 468 nflag = 1; 469 break; 470 case 's': 471 delay = atof(optarg); 472 if (delay <= 0) 473 delay = 5; 474 break; 475 case 'w': 476 rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr); 477 if (errstr) 478 errx(1, "-w %s: %s", optarg, errstr); 479 break; 480 default: 481 usage(); 482 /* NOTREACHED */ 483 } 484 } 485 486 if (kd == NULL) 487 warnx("kvm_openfiles: %s", errbuf); 488 489 argc -= optind; 490 argv += optind; 491 492 if (argc == 1) { 493 double del = atof(argv[0]); 494 if (del == 0) 495 viewstr = argv[0]; 496 else 497 delay = del; 498 } else if (argc == 2) { 499 viewstr = argv[0]; 500 delay = atof(argv[1]); 501 if (delay <= 0) 502 delay = 5; 503 } 504 505 udelay = (useconds_t)(delay * 1000000.0); 506 if (udelay < 1) 507 udelay = 1; 508 509 naptime = (double)udelay / 1000000.0; 510 511 gethostname(hostname, sizeof (hostname)); 512 gethz(); 513 514 initialize(); 515 516 set_order(NULL); 517 if (viewstr && set_view(viewstr)) { 518 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 519 return 1; 520 } 521 522 if (check_termcap()) { 523 rawmode = 1; 524 interactive = 0; 525 } 526 527 setup_term(maxlines); 528 529 if (rawmode && countmax == 0) 530 countmax = 1; 531 532 gotsig_alarm = 1; 533 534 engine_loop(countmax); 535 536 return 0; 537} 538