1 /* $Id: main.c,v 1.55 2009/07/21 17:07:38 sthen 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 double dellave; 57 58 kvm_t *kd; 59 char *nlistf = NULL; 60 char *memf = NULL; 61 double avenrun[3]; 62 double naptime = 5.0; 63 int verbose = 1; /* to report kvm read errs */ 64 int nflag = 1; 65 int ut, hz, stathz; 66 char hostname[MAXHOSTNAMELEN]; 67 WINDOW *wnd; 68 int CMDLINE; 69 70 #define TIMEPOS 55 71 72 int ucount(void); 73 void usage(void); 74 75 /* command prompt */ 76 77 void cmd_delay(const char *); 78 void cmd_count(const char *); 79 void cmd_compat(const char *); 80 81 struct command cm_compat = {"Command", cmd_compat}; 82 struct command cm_delay = {"Seconds to delay", cmd_delay}; 83 struct command cm_count = {"Number of lines to display", cmd_count}; 84 85 86 /* display functions */ 87 88 int 89 print_header(void) 90 { 91 time_t now; 92 int start = dispstart + 1, end = dispstart + maxprint; 93 char tbuf[26]; 94 95 if (end > num_disp) 96 end = num_disp; 97 98 tb_start(); 99 100 getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); 101 102 time(&now); 103 strlcpy(tbuf, ctime(&now), sizeof tbuf); 104 tbprintf(" %d users", ucount()); 105 tbprintf(" Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]); 106 if (num_disp && (start > 1 || end != num_disp)) 107 tbprintf(" (%u-%u of %u)", start, end, num_disp); 108 109 if (paused) 110 tbprintf(" PAUSED"); 111 112 if (rawmode) 113 printf("\n\n%s\n", tmp_buf); 114 else 115 mvprintw(0, 0, "%s", tmp_buf); 116 117 mvprintw(0, TIMEPOS, "%s", tbuf); 118 119 120 return (1); 121 } 122 123 /* compatibility functions, rearrange later */ 124 void 125 error(const char *fmt, ...) 126 { 127 va_list ap; 128 char buf[MAX_LINE_BUF]; 129 130 va_start(ap, fmt); 131 vsnprintf(buf, sizeof buf, fmt, ap); 132 va_end(ap); 133 134 message_set(buf); 135 } 136 137 void 138 nlisterr(struct nlist namelist[]) 139 { 140 int i, n; 141 142 n = 0; 143 clear(); 144 mvprintw(2, 10, "systat: nlist: can't find following symbols:"); 145 for (i = 0; 146 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) 147 if (namelist[i].n_value == 0) 148 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); 149 move(CMDLINE, 0); 150 clrtoeol(); 151 refresh(); 152 endwin(); 153 exit(1); 154 } 155 156 void 157 die(void) 158 { 159 if (!rawmode) 160 endwin(); 161 exit(0); 162 } 163 164 165 int 166 prefix(char *s1, char *s2) 167 { 168 169 while (*s1 == *s2) { 170 if (*s1 == '\0') 171 return (1); 172 s1++, s2++; 173 } 174 return (*s1 == '\0'); 175 } 176 177 /* calculate number of users on the system */ 178 int 179 ucount(void) 180 { 181 int nusers = 0; 182 struct utmp utmp; 183 184 if (ut < 0) 185 return (0); 186 lseek(ut, (off_t)0, SEEK_SET); 187 while (read(ut, &utmp, sizeof(utmp))) 188 if (utmp.ut_name[0] != '\0') 189 nusers++; 190 191 return (nusers); 192 } 193 194 /* main program functions */ 195 196 void 197 usage(void) 198 { 199 extern char *__progname; 200 fprintf(stderr, "usage: %s [-abiNn] [-d count] " 201 "[-s delay] [-w width] [view] [delay]\n", __progname); 202 exit(1); 203 } 204 205 void 206 show_view(void) 207 { 208 if (rawmode) 209 return; 210 211 tb_start(); 212 tbprintf("%s %g", curr_view->name, naptime); 213 tb_end(); 214 message_set(tmp_buf); 215 } 216 217 void 218 add_view_tb(field_view *v) 219 { 220 if (curr_view == v) 221 tbprintf("[%s] ", v->name); 222 else 223 tbprintf("%s ", v->name); 224 } 225 226 void 227 show_help(void) 228 { 229 if (rawmode) 230 return; 231 232 tb_start(); 233 foreach_view(add_view_tb); 234 tb_end(); 235 message_set(tmp_buf); 236 } 237 238 void 239 cmd_compat(const char *buf) 240 { 241 const char *s; 242 243 if (strcasecmp(buf, "help") == 0) { 244 show_help(); 245 need_update = 1; 246 return; 247 } 248 if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) { 249 gotsig_close = 1; 250 return; 251 } 252 if (strcasecmp(buf, "stop") == 0) { 253 paused = 1; 254 gotsig_alarm = 1; 255 return; 256 } 257 if (strncasecmp(buf, "start", 5) == 0) { 258 paused = 0; 259 gotsig_alarm = 1; 260 cmd_delay(buf + 5); 261 return; 262 } 263 264 for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++) 265 ; 266 if (*s) { 267 if (set_view(buf)) 268 error("Invalid/ambiguous view: %s", buf); 269 } else 270 cmd_delay(buf); 271 } 272 273 void 274 cmd_delay(const char *buf) 275 { 276 double del; 277 del = atof(buf); 278 279 if (del > 0) { 280 udelay = (useconds_t)(del * 1000000); 281 gotsig_alarm = 1; 282 naptime = del; 283 } 284 } 285 286 void 287 cmd_count(const char *buf) 288 { 289 int ms; 290 ms = atoi(buf); 291 292 if (ms <= 0 || ms > lines - HEADER_LINES) 293 maxprint = lines - HEADER_LINES; 294 else 295 maxprint = ms; 296 } 297 298 299 int 300 keyboard_callback(int ch) 301 { 302 switch (ch) { 303 case '?': 304 /* FALLTHROUGH */ 305 case 'h': 306 show_help(); 307 need_update = 1; 308 break; 309 case CTRL_G: 310 show_view(); 311 need_update = 1; 312 break; 313 case 'l': 314 command_set(&cm_count, NULL); 315 break; 316 case 's': 317 command_set(&cm_delay, NULL); 318 break; 319 case ':': 320 command_set(&cm_compat, NULL); 321 break; 322 default: 323 return 0; 324 }; 325 326 return 1; 327 } 328 329 void 330 initialize(void) 331 { 332 engine_initialize(); 333 334 initvmstat(); 335 initpigs(); 336 initifstat(); 337 initiostat(); 338 initsensors(); 339 initmembufs(); 340 initnetstat(); 341 initswap(); 342 initpftop(); 343 initpf(); 344 initpool(); 345 initmalloc(); 346 initnfs(); 347 } 348 349 void 350 gethz(void) 351 { 352 struct clockinfo cinf; 353 size_t size = sizeof(cinf); 354 int mib[2]; 355 356 mib[0] = CTL_KERN; 357 mib[1] = KERN_CLOCKRATE; 358 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 359 return; 360 stathz = cinf.stathz; 361 hz = cinf.hz; 362 } 363 364 int 365 main(int argc, char *argv[]) 366 { 367 char errbuf[_POSIX2_LINE_MAX]; 368 extern char *optarg; 369 extern int optind; 370 double delay = 5; 371 372 char *viewstr = NULL; 373 374 gid_t gid; 375 int countmax = 0; 376 int maxlines = 0; 377 378 int ch; 379 380 ut = open(_PATH_UTMP, O_RDONLY); 381 if (ut < 0) { 382 warn("No utmp"); 383 } 384 385 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 386 387 gid = getgid(); 388 if (setresgid(gid, gid, gid) == -1) 389 err(1, "setresgid"); 390 391 while ((ch = getopt(argc, argv, "Nabd:ins:w:")) != -1) { 392 switch (ch) { 393 case 'a': 394 maxlines = -1; 395 break; 396 case 'b': 397 rawmode = 1; 398 interactive = 0; 399 break; 400 case 'd': 401 countmax = atoi(optarg); 402 if (countmax < 0) 403 countmax = 0; 404 break; 405 case 'i': 406 interactive = 1; 407 break; 408 case 'N': 409 nflag = 0; 410 break; 411 case 'n': 412 /* this is a noop, -n is the default */ 413 nflag = 1; 414 break; 415 case 's': 416 delay = atof(optarg); 417 if (delay <= 0) 418 delay = 5; 419 break; 420 case 'w': 421 rawwidth = atoi(optarg); 422 if (rawwidth < 1) 423 rawwidth = DEFAULT_WIDTH; 424 if (rawwidth >= MAX_LINE_BUF) 425 rawwidth = MAX_LINE_BUF - 1; 426 break; 427 default: 428 usage(); 429 /* NOTREACHED */ 430 } 431 } 432 433 if (kd == NULL) 434 warnx("kvm_openfiles: %s", errbuf); 435 436 argc -= optind; 437 argv += optind; 438 439 if (argc == 1) { 440 double del = atof(argv[0]); 441 if (del == 0) 442 viewstr = argv[0]; 443 else 444 delay = del; 445 } else if (argc == 2) { 446 viewstr = argv[0]; 447 delay = atof(argv[1]); 448 if (delay <= 0) 449 delay = 5; 450 } 451 452 udelay = (useconds_t)(delay * 1000000.0); 453 if (udelay < 1) 454 udelay = 1; 455 456 naptime = (double)udelay / 1000000.0; 457 458 gethostname(hostname, sizeof (hostname)); 459 gethz(); 460 461 initialize(); 462 463 set_order(NULL); 464 if (viewstr && set_view(viewstr)) { 465 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 466 return 1; 467 } 468 469 if (!isatty(STDOUT_FILENO)) { 470 rawmode = 1; 471 interactive = 0; 472 } 473 474 setup_term(maxlines); 475 476 if (rawmode && countmax == 0) 477 countmax = 1; 478 479 gotsig_alarm = 1; 480 481 engine_loop(countmax); 482 483 return 0; 484 } 485