1 /* $Id: main.c,v 1.60 2013/09/07 11:43:50 reyk 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 56 #define TIMEPOS 55 57 58 double dellave; 59 60 kvm_t *kd; 61 char *nlistf = NULL; 62 char *memf = NULL; 63 double avenrun[3]; 64 double naptime = 5.0; 65 int verbose = 1; /* to report kvm read errs */ 66 int nflag = 1; 67 int ut, hz, stathz; 68 char hostname[MAXHOSTNAMELEN]; 69 WINDOW *wnd; 70 int CMDLINE; 71 char timebuf[26]; 72 char uloadbuf[TIMEPOS]; 73 74 75 int ucount(void); 76 void usage(void); 77 78 /* command prompt */ 79 80 void cmd_delay(const char *); 81 void cmd_count(const char *); 82 void cmd_compat(const char *); 83 84 struct command cm_compat = {"Command", cmd_compat}; 85 struct command cm_delay = {"Seconds to delay", cmd_delay}; 86 struct command cm_count = {"Number of lines to display", cmd_count}; 87 88 89 /* display functions */ 90 91 int 92 print_header(void) 93 { 94 time_t now; 95 int start = dispstart + 1, end = dispstart + maxprint; 96 char tmpbuf[TIMEPOS]; 97 char header[MAX_LINE_BUF]; 98 99 if (end > num_disp) 100 end = num_disp; 101 102 tb_start(); 103 104 if (!paused) { 105 getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 106 107 snprintf(uloadbuf, sizeof(uloadbuf), 108 "%5d users Load %.2f %.2f %.2f", 109 ucount(), avenrun[0], avenrun[1], avenrun[2]); 110 111 time(&now); 112 strlcpy(timebuf, ctime(&now), sizeof(timebuf)); 113 } 114 115 if (num_disp && (start > 1 || end != num_disp)) 116 snprintf(tmpbuf, sizeof(tmpbuf), 117 "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp, 118 paused ? "PAUSED" : ""); 119 else 120 snprintf(tmpbuf, sizeof(tmpbuf), 121 "%s %s", uloadbuf, 122 paused ? "PAUSED" : ""); 123 124 snprintf(header, sizeof(header), "%-55s%s", tmpbuf, timebuf); 125 126 if (rawmode) 127 printf("\n\n%s\n", header); 128 else 129 mvprintw(0, 0, "%s", header); 130 131 return (1); 132 } 133 134 /* compatibility functions, rearrange later */ 135 void 136 error(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 148 void 149 nlisterr(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 167 void 168 die(void) 169 { 170 if (!rawmode) 171 endwin(); 172 exit(0); 173 } 174 175 176 int 177 prefix(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 */ 189 int 190 ucount(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 207 void 208 usage(void) 209 { 210 extern char *__progname; 211 fprintf(stderr, "usage: %s [-aBbiNn] [-d count] " 212 "[-s delay] [-w width] [view] [delay]\n", __progname); 213 exit(1); 214 } 215 216 void 217 show_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 228 void 229 add_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 237 void 238 show_help(void) 239 { 240 if (rawmode) 241 return; 242 243 tb_start(); 244 foreach_view(add_view_tb); 245 tb_end(); 246 message_set(tmp_buf); 247 } 248 249 void 250 cmd_compat(const char *buf) 251 { 252 const char *s; 253 254 if (strcasecmp(buf, "help") == 0) { 255 show_help(); 256 need_update = 1; 257 return; 258 } 259 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 260 gotsig_close = 1; 261 return; 262 } 263 if (strcasecmp(buf, "stop") == 0) { 264 paused = 1; 265 gotsig_alarm = 1; 266 return; 267 } 268 if (strncasecmp(buf, "start", 5) == 0) { 269 paused = 0; 270 gotsig_alarm = 1; 271 cmd_delay(buf + 5); 272 return; 273 } 274 275 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 276 ; 277 if (*s) { 278 if (set_view(buf)) 279 error("Invalid/ambiguous view: %s", buf); 280 } else 281 cmd_delay(buf); 282 } 283 284 void 285 cmd_delay(const char *buf) 286 { 287 double del; 288 del = atof(buf); 289 290 if (del > 0) { 291 udelay = (useconds_t)(del * 1000000); 292 gotsig_alarm = 1; 293 naptime = del; 294 } 295 } 296 297 void 298 cmd_count(const char *buf) 299 { 300 int ms; 301 ms = atoi(buf); 302 303 if (ms <= 0 || ms > lines - HEADER_LINES) 304 maxprint = lines - HEADER_LINES; 305 else 306 maxprint = ms; 307 } 308 309 310 int 311 keyboard_callback(int ch) 312 { 313 switch (ch) { 314 case '?': 315 /* FALLTHROUGH */ 316 case 'h': 317 show_help(); 318 need_update = 1; 319 break; 320 case CTRL_G: 321 show_view(); 322 need_update = 1; 323 break; 324 case 'l': 325 command_set(&cm_count, NULL); 326 break; 327 case 's': 328 command_set(&cm_delay, NULL); 329 break; 330 case ',': 331 separate_thousands = !separate_thousands; 332 gotsig_alarm = 1; 333 break; 334 case ':': 335 command_set(&cm_compat, NULL); 336 break; 337 default: 338 return 0; 339 }; 340 341 return 1; 342 } 343 344 void 345 initialize(void) 346 { 347 engine_initialize(); 348 349 initvmstat(); 350 initpigs(); 351 initifstat(); 352 initiostat(); 353 initsensors(); 354 initmembufs(); 355 initnetstat(); 356 initswap(); 357 initpftop(); 358 initpf(); 359 initpool(); 360 initmalloc(); 361 initnfs(); 362 initcpu(); 363 } 364 365 void 366 gethz(void) 367 { 368 struct clockinfo cinf; 369 size_t size = sizeof(cinf); 370 int mib[2]; 371 372 mib[0] = CTL_KERN; 373 mib[1] = KERN_CLOCKRATE; 374 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 375 return; 376 stathz = cinf.stathz; 377 hz = cinf.hz; 378 } 379 380 int 381 main(int argc, char *argv[]) 382 { 383 char errbuf[_POSIX2_LINE_MAX]; 384 extern char *optarg; 385 extern int optind; 386 double delay = 5; 387 388 char *viewstr = NULL; 389 390 gid_t gid; 391 int countmax = 0; 392 int maxlines = 0; 393 394 int ch; 395 396 ut = open(_PATH_UTMP, O_RDONLY); 397 if (ut < 0) { 398 warn("No utmp"); 399 } 400 401 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 402 403 gid = getgid(); 404 if (setresgid(gid, gid, gid) == -1) 405 err(1, "setresgid"); 406 407 while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { 408 switch (ch) { 409 case 'a': 410 maxlines = -1; 411 break; 412 case 'B': 413 averageonly = 1; 414 if (countmax < 2) 415 countmax = 2; 416 /* FALLTHROUGH */ 417 case 'b': 418 rawmode = 1; 419 interactive = 0; 420 break; 421 case 'd': 422 countmax = atoi(optarg); 423 if (countmax < 0) 424 countmax = 0; 425 break; 426 case 'i': 427 interactive = 1; 428 break; 429 case 'N': 430 nflag = 0; 431 break; 432 case 'n': 433 /* this is a noop, -n is the default */ 434 nflag = 1; 435 break; 436 case 's': 437 delay = atof(optarg); 438 if (delay <= 0) 439 delay = 5; 440 break; 441 case 'w': 442 rawwidth = atoi(optarg); 443 if (rawwidth < 1) 444 rawwidth = DEFAULT_WIDTH; 445 if (rawwidth >= MAX_LINE_BUF) 446 rawwidth = MAX_LINE_BUF - 1; 447 break; 448 default: 449 usage(); 450 /* NOTREACHED */ 451 } 452 } 453 454 if (kd == NULL) 455 warnx("kvm_openfiles: %s", errbuf); 456 457 argc -= optind; 458 argv += optind; 459 460 if (argc == 1) { 461 double del = atof(argv[0]); 462 if (del == 0) 463 viewstr = argv[0]; 464 else 465 delay = del; 466 } else if (argc == 2) { 467 viewstr = argv[0]; 468 delay = atof(argv[1]); 469 if (delay <= 0) 470 delay = 5; 471 } 472 473 udelay = (useconds_t)(delay * 1000000.0); 474 if (udelay < 1) 475 udelay = 1; 476 477 naptime = (double)udelay / 1000000.0; 478 479 gethostname(hostname, sizeof (hostname)); 480 gethz(); 481 482 initialize(); 483 484 set_order(NULL); 485 if (viewstr && set_view(viewstr)) { 486 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 487 return 1; 488 } 489 490 if (check_termcap()) { 491 rawmode = 1; 492 interactive = 0; 493 } 494 495 setup_term(maxlines); 496 497 if (rawmode && countmax == 0) 498 countmax = 1; 499 500 gotsig_alarm = 1; 501 502 engine_loop(countmax); 503 504 return 0; 505 } 506