| 1 | 
   | 
 /*  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 2 | 
   | 
  * i-scream central monitoring system | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 3 | 
   | 
  * http://www.i-scream.org | 
 
 
 
 
 
 
 
 
 
 
 
 | 4 | 
 < | 
  * Copyright (C) 2000-2003 i-scream | 
 
 
 
 
 
 
 
 
 
 | 4 | 
 > | 
  * Copyright (C) 2000-2004 i-scream | 
 
 
 
 
 
 
 
 
 
 
 
 | 5 | 
   | 
  *  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 6 | 
   | 
  * This program is free software; you can redistribute it and/or | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 7 | 
   | 
  * modify it under the terms of the GNU General Public License | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 16 | 
   | 
  * You should have received a copy of the GNU General Public License | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 17 | 
   | 
  * along with this program; if not, write to the Free Software | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 18 | 
   | 
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
 
 
 
 
 
 
 
 
 | 19 | 
 + | 
  * | 
 
 
 
 
 
 
 
 
 | 20 | 
 + | 
  * $Id$ | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 21 | 
   | 
  */ | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 22 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 23 | 
   | 
 #ifdef HAVE_CONFIG_H | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 37 | 
   | 
         FLOAT, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 38 | 
   | 
         DOUBLE, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 39 | 
   | 
         STRING, | 
 
 
 
 
 
 
 
 
 
 
 
 | 40 | 
 < | 
         INT | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 40 | 
 > | 
         INT, | 
 
 
 
 
 
 | 41 | 
 > | 
         DUPLEX | 
 
 
 
 
 
 
 
 
 
 
 
 | 42 | 
   | 
 } stat_type; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 43 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 44 | 
   | 
 typedef enum { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 143 | 
   | 
         ++num_stats; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 144 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 145 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 | 146 | 
 < | 
 /* Compare two stats by name, for sorting purposes. */ | 
 
 
 
 
 
 
 
 
 
 | 146 | 
 > | 
 /* Compare two stats by name for qsort and bsearch. */ | 
 
 
 
 
 
 
 
 
 
 
 
 | 147 | 
   | 
 int stats_compare(const void *a, const void *b) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 148 | 
   | 
         return strcmp(((stat *)a)->name, ((stat *)b)->name); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 149 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 150 | 
   | 
  | 
 
 
 
 
 
 
 
 
 | 151 | 
 + | 
 /* Compare up to the length of the key for bsearch. */ | 
 
 
 
 
 
 
 
 
 | 152 | 
 + | 
 int stats_compare_prefix(const void *key, const void *item) { | 
 
 
 
 
 
 
 
 
 | 153 | 
 + | 
         const char *kn = ((stat *)key)->name; | 
 
 
 
 
 
 
 
 
 | 154 | 
 + | 
         const char *in = ((stat *)item)->name; | 
 
 
 
 
 
 
 
 
 | 155 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 | 156 | 
 + | 
         return strncmp(kn, in, strlen(kn)); | 
 
 
 
 
 
 
 
 
 | 157 | 
 + | 
 } | 
 
 
 
 
 
 
 
 
 | 158 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 159 | 
   | 
 void populate_const() { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 160 | 
   | 
         static int zero = 0; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 161 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 271 | 
   | 
         if (disk != NULL) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 272 | 
   | 
                 for (i = 0; i < n; i++) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 273 | 
   | 
                         /* FIXME it'd be nicer if libstatgrab did this */ | 
 
 
 
 
 
 
 
 
 
 
 
 | 274 | 
 < | 
                         const char *name = disk[i].device_name, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 275 | 
 < | 
                                    *p = strrchr(name, '/'); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 276 | 
 < | 
                         if (p != NULL) | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 277 | 
 < | 
                                 name = p + 1; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 278 | 
 < | 
                         if (*name == '\0') | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 279 | 
 < | 
                                 name = "root"; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 280 | 
 < | 
          | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 274 | 
 > | 
                         char *buf, *name, *p; | 
 
 
 
 
 
 | 275 | 
 > | 
                         const char *device = disk[i].device_name; | 
 
 
 
 
 
 | 276 | 
 > | 
  | 
 
 
 
 
 
 | 277 | 
 > | 
                         if (strcmp(device, "/") == 0) | 
 
 
 
 
 
 | 278 | 
 > | 
                                 device = "root"; | 
 
 
 
 
 
 | 279 | 
 > | 
  | 
 
 
 
 
 
 | 280 | 
 > | 
                         buf = strdup(device); | 
 
 
 
 
 
 | 281 | 
 > | 
                         if (buf == NULL) | 
 
 
 
 
 
 | 282 | 
 > | 
                                 die("out of memory"); | 
 
 
 
 
 
 | 283 | 
 > | 
  | 
 
 
 
 
 
 | 284 | 
 > | 
                         name = buf; | 
 
 
 
 
 
 | 285 | 
 > | 
                         if (strlen(name) == 2 && name[1] == ':') | 
 
 
 
 
 
 | 286 | 
 > | 
                                 name[1] = '\0'; | 
 
 
 
 
 
 | 287 | 
 > | 
                         if (strncmp(name, "/dev/", 5) == 0) | 
 
 
 
 
 
 | 288 | 
 > | 
                                 name += 5; | 
 
 
 
 
 
 | 289 | 
 > | 
                         while ((p = strchr(name, '/')) != NULL) | 
 
 
 
 
 
 | 290 | 
 > | 
                                 *p = '_'; | 
 
 
 
 
 
 | 291 | 
 > | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 | 292 | 
   | 
                         add_stat(STRING, &disk[i].device_name, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 293 | 
   | 
                                  "fs", name, "device_name", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 294 | 
   | 
                         add_stat(STRING, &disk[i].fs_type, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 307 | 
   | 
                                  "fs", name, "used_inodes", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 308 | 
   | 
                         add_stat(LONG_LONG, &disk[i].free_inodes, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 309 | 
   | 
                                  "fs", name, "free_inodes", NULL); | 
 
 
 
 
 
 
 
 
 | 310 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 | 311 | 
 + | 
                         free(buf); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 312 | 
   | 
                 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 313 | 
   | 
         } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 314 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 349 | 
   | 
 void populate_net() { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 350 | 
   | 
         int n, i; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 351 | 
   | 
         network_stat_t *net; | 
 
 
 
 
 
 
 
 
 | 352 | 
 + | 
         network_iface_stat_t *iface; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 353 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 354 | 
   | 
         net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 355 | 
   | 
         if (net != NULL) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 366 | 
   | 
                                  "net", name, "systime", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 367 | 
   | 
                 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 368 | 
   | 
         } | 
 
 
 
 
 
 
 
 
 | 369 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 | 370 | 
 + | 
         iface = get_network_iface_stats(&n); | 
 
 
 
 
 
 
 
 
 | 371 | 
 + | 
         if (iface != NULL) { | 
 
 
 
 
 
 
 
 
 | 372 | 
 + | 
                 for (i = 0; i < n; i++) { | 
 
 
 
 
 
 
 
 
 | 373 | 
 + | 
                         const char *name = iface[i].interface_name; | 
 
 
 
 
 
 
 
 
 | 374 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 | 375 | 
 + | 
                         add_stat(INT, &iface[i].speed, | 
 
 
 
 
 
 
 
 
 | 376 | 
 + | 
                                  "net", name, "speed", NULL); | 
 
 
 
 
 
 
 
 
 | 377 | 
 + | 
                         add_stat(DUPLEX, &iface[i].dup, | 
 
 
 
 
 
 
 
 
 | 378 | 
 + | 
                                  "net", name, "duplex", NULL); | 
 
 
 
 
 
 
 
 
 | 379 | 
 + | 
                 } | 
 
 
 
 
 
 
 
 
 | 380 | 
 + | 
         } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 381 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 382 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 383 | 
   | 
 void populate_page() { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 387 | 
   | 
         if (page != NULL) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 388 | 
   | 
                 add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 389 | 
   | 
                 add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 | 390 | 
 < | 
                 add_stat(LONG_LONG, &page->systime, "page", "systime", NULL); | 
 
 
 
 
 
 
 
 
 
 | 390 | 
 > | 
                 add_stat(TIME_T, &page->systime, "page", "systime", NULL); | 
 
 
 
 
 
 
 
 
 
 
 
 | 391 | 
   | 
         } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 392 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 393 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 474 | 
   | 
         case INT: | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 475 | 
   | 
                 printf("%d", *(int *)v); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 476 | 
   | 
                 break; | 
 
 
 
 
 
 
 
 
 | 477 | 
 + | 
         case DUPLEX: | 
 
 
 
 
 
 
 
 
 | 478 | 
 + | 
                 switch (*(statgrab_duplex *) v) { | 
 
 
 
 
 
 
 
 
 | 479 | 
 + | 
                 case FULL_DUPLEX: | 
 
 
 
 
 
 
 
 
 | 480 | 
 + | 
                         printf("full"); | 
 
 
 
 
 
 
 
 
 | 481 | 
 + | 
                         break; | 
 
 
 
 
 
 
 
 
 | 482 | 
 + | 
                 case HALF_DUPLEX: | 
 
 
 
 
 
 
 
 
 | 483 | 
 + | 
                         printf("half"); | 
 
 
 
 
 
 
 
 
 | 484 | 
 + | 
                         break; | 
 
 
 
 
 
 
 
 
 | 485 | 
 + | 
                 default: | 
 
 
 
 
 
 
 
 
 | 486 | 
 + | 
                         printf("unknown"); | 
 
 
 
 
 
 
 
 
 | 487 | 
 + | 
                         break; | 
 
 
 
 
 
 
 
 
 | 488 | 
 + | 
                 } | 
 
 
 
 
 
 
 
 
 | 489 | 
 + | 
                 break; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 490 | 
   | 
         } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 491 | 
   | 
 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 492 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 518 | 
   | 
         } else { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 519 | 
   | 
                 /* Print selected stats. */ | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 520 | 
   | 
                 for (i = optind; i < argc; i++) { | 
 
 
 
 
 
 
 
 
 | 521 | 
 + | 
                         char *name = argv[i]; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 522 | 
   | 
                         stat key; | 
 
 
 
 
 
 
 
 
 
 
 
 | 523 | 
 < | 
                         const stat *s; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 523 | 
 > | 
                         const stat *s, *end; | 
 
 
 
 
 
 | 524 | 
 > | 
                         int (*compare)(const void *, const void *); | 
 
 
 
 
 
 
 
 
 
 
 
 | 525 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 | 526 | 
 < | 
                         key.name = argv[i]; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 526 | 
 > | 
                         key.name = name; | 
 
 
 
 
 
 | 527 | 
 > | 
                         if (name[strlen(name) - 1] == '.') | 
 
 
 
 
 
 | 528 | 
 > | 
                                 compare = stats_compare_prefix; | 
 
 
 
 
 
 | 529 | 
 > | 
                         else | 
 
 
 
 
 
 | 530 | 
 > | 
                                 compare = stats_compare; | 
 
 
 
 
 
 | 531 | 
 > | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 | 532 | 
   | 
                         s = (const stat *)bsearch(&key, stats, num_stats, | 
 
 
 
 
 
 
 
 
 
 
 
 | 533 | 
 < | 
                                                   sizeof *stats, | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 534 | 
 < | 
                                                   stats_compare); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 535 | 
 < | 
                         if (s != NULL) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 533 | 
 > | 
                                                   sizeof *stats, compare); | 
 
 
 
 
 
 | 534 | 
 > | 
                         if (s == NULL) { | 
 
 
 
 
 
 | 535 | 
 > | 
                                 printf("Unknown stat %s\n", name); | 
 
 
 
 
 
 | 536 | 
 > | 
                                 continue; | 
 
 
 
 
 
 | 537 | 
 > | 
                         } | 
 
 
 
 
 
 | 538 | 
 > | 
  | 
 
 
 
 
 
 | 539 | 
 > | 
                         /* Find the range of stats the user wanted. */ | 
 
 
 
 
 
 | 540 | 
 > | 
                         for (; s >= stats; s--) { | 
 
 
 
 
 
 | 541 | 
 > | 
                                 if (compare(&key, s) != 0) | 
 
 
 
 
 
 | 542 | 
 > | 
                                         break; | 
 
 
 
 
 
 | 543 | 
 > | 
                         } | 
 
 
 
 
 
 | 544 | 
 > | 
                         s++; | 
 
 
 
 
 
 | 545 | 
 > | 
                         for (end = s; end < &stats[num_stats]; end++) { | 
 
 
 
 
 
 | 546 | 
 > | 
                                 if (compare(&key, end) != 0) | 
 
 
 
 
 
 | 547 | 
 > | 
                                         break; | 
 
 
 
 
 
 | 548 | 
 > | 
                         } | 
 
 
 
 
 
 | 549 | 
 > | 
  | 
 
 
 
 
 
 | 550 | 
 > | 
                         /* And print them. */ | 
 
 
 
 
 
 | 551 | 
 > | 
                         for (; s < end; s++) { | 
 
 
 
 
 
 
 
 
 
 
 
 | 552 | 
   | 
                                 print_stat(s); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 553 | 
   | 
                         } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 554 | 
   | 
                 } | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 557 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 558 | 
   | 
 void usage() { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 559 | 
   | 
         printf("Usage: statgrab [OPTION]... [STAT]...\n" | 
 
 
 
 
 
 
 
 
 
 
 
 | 560 | 
 < | 
                "Display system statistics (all statistics by default).\n" | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 560 | 
 > | 
                "Display system statistics.\n" | 
 
 
 
 
 
 | 561 | 
 > | 
                "\n" | 
 
 
 
 
 
 | 562 | 
 > | 
                "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n" | 
 
 
 
 
 
 | 563 | 
 > | 
                "statistics starting with that prefix.\n" | 
 
 
 
 
 
 
 
 
 
 
 
 | 564 | 
   | 
                "\n"); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 565 | 
   | 
         printf("  -l         Linux sysctl-style output (default)\n" | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 566 | 
   | 
                "  -b         BSD sysctl-style output\n" | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 633 | 
   | 
                 use_diffs = 1; | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 634 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 635 | 
   | 
         select_interesting(argc - optind, &argv[optind]); | 
 
 
 
 
 
 
 
 
 | 636 | 
 + | 
  | 
 
 
 
 
 
 
 
 
 | 637 | 
 + | 
         /* We don't care if statgrab_init fails, because we can just display | 
 
 
 
 
 
 
 
 
 | 638 | 
 + | 
            the statistics that can be read as non-root. */ | 
 
 
 
 
 
 
 
 
 | 639 | 
 + | 
         statgrab_init(); | 
 
 
 
 
 
 
 
 
 | 640 | 
 + | 
         if (statgrab_drop_privileges() != 0) | 
 
 
 
 
 
 
 
 
 | 641 | 
 + | 
                 die("Failed to drop setuid/setgid privileges"); | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 642 | 
   | 
  | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 643 | 
   | 
         switch (repeat_mode) { | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 | 644 | 
   | 
         case REPEAT_NONE: |