1 /* $Id: main.c,v 1.51 2008/11/08 06:38:27 canacar 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 [-abin] [-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 } 347 348 void 349 gethz(void) 350 { 351 struct clockinfo cinf; 352 size_t size = sizeof(cinf); 353 int mib[2]; 354 355 mib[0] = CTL_KERN; 356 mib[1] = KERN_CLOCKRATE; 357 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 358 return; 359 stathz = cinf.stathz; 360 hz = cinf.hz; 361 } 362 363 int 364 main(int argc, char *argv[]) 365 { 366 char errbuf[_POSIX2_LINE_MAX]; 367 extern char *optarg; 368 extern int optind; 369 double delay = 5; 370 371 char *viewstr = NULL; 372 373 gid_t gid; 374 int countmax = 0; 375 int maxlines = 0; 376 377 int ch; 378 379 ut = open(_PATH_UTMP, O_RDONLY); 380 if (ut < 0) { 381 warn("No utmp"); 382 } 383 384 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 385 386 gid = getgid(); 387 if (setresgid(gid, gid, gid) == -1) 388 err(1, "setresgid"); 389 390 while ((ch = getopt(argc, argv, "abd:ins:w:")) != -1) { 391 switch (ch) { 392 case 'a': 393 maxlines = -1; 394 break; 395 case 'b': 396 rawmode = 1; 397 interactive = 0; 398 break; 399 case 'd': 400 countmax = atoi(optarg); 401 if (countmax < 0) 402 countmax = 0; 403 break; 404 case 'i': 405 interactive = 1; 406 break; 407 case 'n': 408 nflag = 1; 409 break; 410 case 's': 411 delay = atof(optarg); 412 if (delay <= 0) 413 delay = 5; 414 break; 415 case 'w': 416 rawwidth = atoi(optarg); 417 if (rawwidth < 1) 418 rawwidth = DEFAULT_WIDTH; 419 if (rawwidth >= MAX_LINE_BUF) 420 rawwidth = MAX_LINE_BUF - 1; 421 break; 422 default: 423 usage(); 424 /* NOTREACHED */ 425 } 426 } 427 428 if (kd == NULL) 429 warnx("kvm_openfiles: %s", errbuf); 430 431 argc -= optind; 432 argv += optind; 433 434 if (argc == 1) { 435 double del = atof(argv[0]); 436 if (del == 0) 437 viewstr = argv[0]; 438 else 439 delay = del; 440 } else if (argc == 2) { 441 viewstr = argv[0]; 442 delay = atof(argv[1]); 443 if (delay <= 0) 444 delay = 5; 445 } 446 447 udelay = (useconds_t)(delay * 1000000.0); 448 if (udelay < 1) 449 udelay = 1; 450 451 naptime = (double)udelay / 1000000.0; 452 453 gethostname(hostname, sizeof (hostname)); 454 gethz(); 455 456 initialize(); 457 458 set_order(NULL); 459 if (viewstr && set_view(viewstr)) { 460 fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr); 461 return 1; 462 } 463 464 if (!isatty(STDOUT_FILENO)) { 465 rawmode = 1; 466 interactive = 0; 467 } 468 469 setup_term(maxlines); 470 471 if (rawmode && countmax == 0) 472 countmax = 1; 473 474 gotsig_alarm = 1; 475 476 engine_loop(countmax); 477 478 return 0; 479 } 480