1 /* $Id: main.c,v 1.67 2018/02/08 07:00:33 martijn 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 57 double dellave; 58 59 kvm_t *kd; 60 char *nlistf = NULL; 61 char *memf = NULL; 62 double avenrun[3]; 63 double naptime = 5.0; 64 int verbose = 1; /* to report kvm read errs */ 65 int nflag = 1; 66 int ut, hz, stathz; 67 char hostname[HOST_NAME_MAX+1]; 68 WINDOW *wnd; 69 int CMDLINE; 70 char timebuf[26]; 71 char uloadbuf[TIMEPOS]; 72 73 74 int ucount(void); 75 void usage(void); 76 77 /* command prompt */ 78 79 void cmd_delay(const char *); 80 void cmd_count(const char *); 81 void cmd_compat(const char *); 82 83 struct command cm_compat = {"Command", cmd_compat}; 84 struct command cm_delay = {"Seconds to delay", cmd_delay}; 85 struct command cm_count = {"Number of lines to display", cmd_count}; 86 87 88 /* display functions */ 89 90 int 91 print_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 */ 139 void 140 error(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 152 void 153 nlisterr(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 171 void 172 die(void) 173 { 174 if (!rawmode) 175 endwin(); 176 exit(0); 177 } 178 179 180 int 181 prefix(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 */ 193 int 194 ucount(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 211 void 212 usage(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 220 void 221 show_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 232 void 233 add_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 241 void 242 show_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 253 void 254 add_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 264 void 265 show_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 278 void 279 cmd_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 318 void 319 cmd_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 331 void 332 cmd_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 342 int 343 keyboard_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 376 void 377 initialize(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 } 396 397 void 398 gethz(void) 399 { 400 struct clockinfo cinf; 401 size_t size = sizeof(cinf); 402 int mib[2]; 403 404 mib[0] = CTL_KERN; 405 mib[1] = KERN_CLOCKRATE; 406 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 407 return; 408 stathz = cinf.stathz; 409 hz = cinf.hz; 410 } 411 412 int 413 main(int argc, char *argv[]) 414 { 415 char errbuf[_POSIX2_LINE_MAX]; 416 const char *errstr; 417 extern char *optarg; 418 extern int optind; 419 double delay = 5; 420 421 char *viewstr = NULL; 422 423 gid_t gid; 424 int countmax = 0; 425 int maxlines = 0; 426 427 int ch; 428 429 ut = open(_PATH_UTMP, O_RDONLY); 430 if (ut < 0) { 431 warn("No utmp"); 432 } 433 434 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 435 436 gid = getgid(); 437 if (setresgid(gid, gid, gid) == -1) 438 err(1, "setresgid"); 439 440 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 441 switch (ch) { 442 case 'a': 443 maxlines = -1; 444 break; 445 case 'B': 446 averageonly = 1; 447 if (countmax < 2) 448 countmax = 2; 449 /* FALLTHROUGH */ 450 case 'b': 451 rawmode = 1; 452 interactive = 0; 453 break; 454 case 'd': 455 countmax = strtonum(optarg, 1, INT_MAX, &errstr); 456 if (errstr) 457 errx(1, "-d %s: %s", optarg, errstr); 458 break; 459 case 'i': 460 interactive = 1; 461 break; 462 case 'N': 463 nflag = 0; 464 break; 465 case 'n': 466 /* this is a noop, -n is the default */ 467 nflag = 1; 468 break; 469 case 's': 470 delay = atof(optarg); 471 if (delay <= 0) 472 delay = 5; 473 break; 474 case 'w': 475 rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr); 476 if (errstr) 477 errx(1, "-w %s: %s", optarg, errstr); 478 break; 479 default: 480 usage(); 481 /* NOTREACHED */ 482 } 483 } 484 485 if (kd == NULL) 486 warnx("kvm_openfiles: %s", errbuf); 487 488 argc -= optind; 489 argv += optind; 490 491 if (argc == 1) { 492 double del = atof(argv[0]); 493 if (del == 0) 494 viewstr = argv[0]; 495 else 496 delay = del; 497 } else if (argc == 2) { 498 viewstr = argv[0]; 499 delay = atof(argv[1]); 500 if (delay <= 0) 501 delay = 5; 502 } 503 504 udelay = (useconds_t)(delay * 1000000.0); 505 if (udelay < 1) 506 udelay = 1; 507 508 naptime = (double)udelay / 1000000.0; 509 510 gethostname(hostname, sizeof (hostname)); 511 gethz(); 512 513 initialize(); 514 515 set_order(NULL); 516 if (viewstr && set_view(viewstr)) { 517 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 518 return 1; 519 } 520 521 if (check_termcap()) { 522 rawmode = 1; 523 interactive = 0; 524 } 525 526 setup_term(maxlines); 527 528 if (rawmode && countmax == 0) 529 countmax = 1; 530 531 gotsig_alarm = 1; 532 533 engine_loop(countmax); 534 535 return 0; 536 } 537