1 /* $Id: main.c,v 1.59 2011/04/05 07:35:32 mpf 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 [-abiNn] [-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 } 363 364 void 365 gethz(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 379 int 380 main(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, O_RDONLY, errbuf); 401 402 gid = getgid(); 403 if (setresgid(gid, gid, gid) == -1) 404 err(1, "setresgid"); 405 406 while ((ch = getopt(argc, argv, "Nabd:ins:w:")) != -1) { 407 switch (ch) { 408 case 'a': 409 maxlines = -1; 410 break; 411 case 'b': 412 rawmode = 1; 413 interactive = 0; 414 break; 415 case 'd': 416 countmax = atoi(optarg); 417 if (countmax < 0) 418 countmax = 0; 419 break; 420 case 'i': 421 interactive = 1; 422 break; 423 case 'N': 424 nflag = 0; 425 break; 426 case 'n': 427 /* this is a noop, -n is the default */ 428 nflag = 1; 429 break; 430 case 's': 431 delay = atof(optarg); 432 if (delay <= 0) 433 delay = 5; 434 break; 435 case 'w': 436 rawwidth = atoi(optarg); 437 if (rawwidth < 1) 438 rawwidth = DEFAULT_WIDTH; 439 if (rawwidth >= MAX_LINE_BUF) 440 rawwidth = MAX_LINE_BUF - 1; 441 break; 442 default: 443 usage(); 444 /* NOTREACHED */ 445 } 446 } 447 448 if (kd == NULL) 449 warnx("kvm_openfiles: %s", errbuf); 450 451 argc -= optind; 452 argv += optind; 453 454 if (argc == 1) { 455 double del = atof(argv[0]); 456 if (del == 0) 457 viewstr = argv[0]; 458 else 459 delay = del; 460 } else if (argc == 2) { 461 viewstr = argv[0]; 462 delay = atof(argv[1]); 463 if (delay <= 0) 464 delay = 5; 465 } 466 467 udelay = (useconds_t)(delay * 1000000.0); 468 if (udelay < 1) 469 udelay = 1; 470 471 naptime = (double)udelay / 1000000.0; 472 473 gethostname(hostname, sizeof (hostname)); 474 gethz(); 475 476 initialize(); 477 478 set_order(NULL); 479 if (viewstr && set_view(viewstr)) { 480 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 481 return 1; 482 } 483 484 if (check_termcap()) { 485 rawmode = 1; 486 interactive = 0; 487 } 488 489 setup_term(maxlines); 490 491 if (rawmode && countmax == 0) 492 countmax = 1; 493 494 gotsig_alarm = 1; 495 496 engine_loop(countmax); 497 498 return 0; 499 } 500