1 /* $Id: main.c,v 1.66 2016/10/13 11:22:46 otto 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 cmd_compat(const char *buf) 255 { 256 const char *s; 257 258 if (strcasecmp(buf, "help") == 0) { 259 show_help(); 260 need_update = 1; 261 return; 262 } 263 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 264 gotsig_close = 1; 265 return; 266 } 267 if (strcasecmp(buf, "stop") == 0) { 268 paused = 1; 269 gotsig_alarm = 1; 270 return; 271 } 272 if (strncasecmp(buf, "start", 5) == 0) { 273 paused = 0; 274 gotsig_alarm = 1; 275 cmd_delay(buf + 5); 276 return; 277 } 278 279 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 280 ; 281 if (*s) { 282 if (set_view(buf)) 283 error("Invalid/ambiguous view: %s", buf); 284 } else 285 cmd_delay(buf); 286 } 287 288 void 289 cmd_delay(const char *buf) 290 { 291 double del; 292 del = atof(buf); 293 294 if (del > 0) { 295 udelay = (useconds_t)(del * 1000000); 296 gotsig_alarm = 1; 297 naptime = del; 298 } 299 } 300 301 void 302 cmd_count(const char *buf) 303 { 304 const char *errstr; 305 306 maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr); 307 if (errstr) 308 maxprint = lines - HEADER_LINES; 309 } 310 311 312 int 313 keyboard_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 separate_thousands = !separate_thousands; 334 gotsig_alarm = 1; 335 break; 336 case ':': 337 command_set(&cm_compat, NULL); 338 break; 339 default: 340 return 0; 341 }; 342 343 return 1; 344 } 345 346 void 347 initialize(void) 348 { 349 engine_initialize(); 350 351 initvmstat(); 352 initpigs(); 353 initifstat(); 354 initiostat(); 355 initsensors(); 356 initmembufs(); 357 initnetstat(); 358 initswap(); 359 initpftop(); 360 initpf(); 361 initpool(); 362 initmalloc(); 363 initnfs(); 364 initcpu(); 365 } 366 367 void 368 gethz(void) 369 { 370 struct clockinfo cinf; 371 size_t size = sizeof(cinf); 372 int mib[2]; 373 374 mib[0] = CTL_KERN; 375 mib[1] = KERN_CLOCKRATE; 376 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 377 return; 378 stathz = cinf.stathz; 379 hz = cinf.hz; 380 } 381 382 int 383 main(int argc, char *argv[]) 384 { 385 char errbuf[_POSIX2_LINE_MAX]; 386 const char *errstr; 387 extern char *optarg; 388 extern int optind; 389 double delay = 5; 390 391 char *viewstr = NULL; 392 393 gid_t gid; 394 int countmax = 0; 395 int maxlines = 0; 396 397 int ch; 398 399 ut = open(_PATH_UTMP, O_RDONLY); 400 if (ut < 0) { 401 warn("No utmp"); 402 } 403 404 kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 405 406 gid = getgid(); 407 if (setresgid(gid, gid, gid) == -1) 408 err(1, "setresgid"); 409 410 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 411 switch (ch) { 412 case 'a': 413 maxlines = -1; 414 break; 415 case 'B': 416 averageonly = 1; 417 if (countmax < 2) 418 countmax = 2; 419 /* FALLTHROUGH */ 420 case 'b': 421 rawmode = 1; 422 interactive = 0; 423 break; 424 case 'd': 425 countmax = strtonum(optarg, 1, INT_MAX, &errstr); 426 if (errstr) 427 errx(1, "-d %s: %s", optarg, errstr); 428 break; 429 case 'i': 430 interactive = 1; 431 break; 432 case 'N': 433 nflag = 0; 434 break; 435 case 'n': 436 /* this is a noop, -n is the default */ 437 nflag = 1; 438 break; 439 case 's': 440 delay = atof(optarg); 441 if (delay <= 0) 442 delay = 5; 443 break; 444 case 'w': 445 rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr); 446 if (errstr) 447 errx(1, "-w %s: %s", optarg, errstr); 448 break; 449 default: 450 usage(); 451 /* NOTREACHED */ 452 } 453 } 454 455 if (kd == NULL) 456 warnx("kvm_openfiles: %s", errbuf); 457 458 argc -= optind; 459 argv += optind; 460 461 if (argc == 1) { 462 double del = atof(argv[0]); 463 if (del == 0) 464 viewstr = argv[0]; 465 else 466 delay = del; 467 } else if (argc == 2) { 468 viewstr = argv[0]; 469 delay = atof(argv[1]); 470 if (delay <= 0) 471 delay = 5; 472 } 473 474 udelay = (useconds_t)(delay * 1000000.0); 475 if (udelay < 1) 476 udelay = 1; 477 478 naptime = (double)udelay / 1000000.0; 479 480 gethostname(hostname, sizeof (hostname)); 481 gethz(); 482 483 initialize(); 484 485 set_order(NULL); 486 if (viewstr && set_view(viewstr)) { 487 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 488 return 1; 489 } 490 491 if (check_termcap()) { 492 rawmode = 1; 493 interactive = 0; 494 } 495 496 setup_term(maxlines); 497 498 if (rawmode && countmax == 0) 499 countmax = 1; 500 501 gotsig_alarm = 1; 502 503 engine_loop(countmax); 504 505 return 0; 506 } 507