ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
(Generate patch)

Comparing projects/libstatgrab/src/statgrab/statgrab.c (file contents):
Revision 1.6 by ats, Fri Aug 29 06:48:04 2003 UTC vs.
Revision 1.12 by ats, Mon Oct 20 22:18:21 2003 UTC

# Line 66 | Line 66 | display_mode_type display_mode = DISPLAY_LINUX;
66   repeat_mode_type repeat_mode = REPEAT_NONE;
67   int repeat_time = 1;
68   int use_cpu_percent = 0;
69 + int use_diffs = 0;
70  
71   /* Exit with an error message. */
72   void die(const char *s) {
# Line 139 | Line 140 | void add_stat(stat_type type, void *stat, ...) {
140          ++num_stats;
141   }
142  
143 < /* Compare two stats by name, for sorting purposes. */
143 > /* Compare two stats by name for qsort and bsearch. */
144   int stats_compare(const void *a, const void *b) {
145          return strcmp(((stat *)a)->name, ((stat *)b)->name);
146   }
147  
148 < /* Clear and rebuild the stats array. */
149 < void get_stats(int use_diffs) {
150 <        cpu_states_t *cpu_s;
151 <        cpu_percent_t *cpu_p;
151 <        mem_stat_t *mem;
152 <        load_stat_t *load;
153 <        user_stat_t *user;
154 <        swap_stat_t *swap;
155 <        general_stat_t *gen;
156 <        disk_stat_t *disk;
157 <        diskio_stat_t *diskio;
158 <        process_stat_t *proc;
159 <        network_stat_t *net;
160 <        page_stat_t *page;
161 <        static int zero = 0;
162 <        int n, i;
148 > /* Compare up to the length of the key for bsearch. */
149 > int stats_compare_prefix(const void *key, const void *item) {
150 >        const char *kn = ((stat *)key)->name;
151 >        const char *in = ((stat *)item)->name;
152  
153 <        clear_stats();
153 >        return strncmp(kn, in, strlen(kn));
154 > }
155  
156 + void populate_const() {
157 +        static int zero = 0;
158 +
159          /* Constants, for use with MRTG mode. */
160          add_stat(INT, &zero, "const", "0", NULL);
161 + }
162  
163 <        /* FIXME when only fetching some stats, it'd be more efficient to only
170 <           do the libstatgrab calls needed, rather than fetching everything. */
171 <
163 > void populate_cpu() {
164          if (use_cpu_percent) {
165 <                cpu_p = cpu_percent_usage();
165 >                cpu_percent_t *cpu_p = cpu_percent_usage();
166 >
167                  if (cpu_p != NULL) {
168                          add_stat(FLOAT, &cpu_p->user,
169                                   "cpu", "user", NULL);
# Line 184 | Line 177 | void get_stats(int use_diffs) {
177                                   "cpu", "swap", NULL);
178                          add_stat(FLOAT, &cpu_p->nice,
179                                   "cpu", "nice", NULL);
180 <                        add_stat(TIME_T, &cpu_p->systime,
180 >                        add_stat(TIME_T, &cpu_p->time_taken,
181                                   "cpu", "time_taken", NULL);
182                  }
183          } else {
184 +                cpu_states_t *cpu_s;
185 +
186                  cpu_s = use_diffs ? get_cpu_diff() : get_cpu_totals();
187                  if (cpu_s != NULL) {
188                          add_stat(LONG_LONG, &cpu_s->user,
# Line 208 | Line 203 | void get_stats(int use_diffs) {
203                                   "cpu", "systime", NULL);
204                  }
205          }
206 + }
207  
208 <        mem = get_memory_stats();
208 > void populate_mem() {
209 >        mem_stat_t *mem = get_memory_stats();
210 >
211          if (mem != NULL) {
212                  add_stat(LONG_LONG, &mem->total, "mem", "total", NULL);
213                  add_stat(LONG_LONG, &mem->free, "mem", "free", NULL);
214                  add_stat(LONG_LONG, &mem->used, "mem", "used", NULL);
215                  add_stat(LONG_LONG, &mem->cache, "mem", "cache", NULL);
216          }
217 + }
218  
219 <        load = get_load_stats();
219 > void populate_load() {
220 >        load_stat_t *load = get_load_stats();
221 >
222          if (load != NULL) {
223                  add_stat(DOUBLE, &load->min1, "load", "min1", NULL);
224                  add_stat(DOUBLE, &load->min5, "load", "min5", NULL);
225                  add_stat(DOUBLE, &load->min15, "load", "min15", NULL);
226          }
227 + }
228  
229 <        user = get_user_stats();
229 > void populate_user() {
230 >        user_stat_t *user = get_user_stats();
231 >
232          if (user != NULL) {
233                  add_stat(INT, &user->num_entries, "user", "num", NULL);
234                  add_stat(STRING, &user->name_list, "user", "names", NULL);
235          }
236 + }
237  
238 <        swap = get_swap_stats();
238 > void populate_swap() {
239 >        swap_stat_t *swap = get_swap_stats();
240 >
241          if (swap != NULL) {
242                  add_stat(LONG_LONG, &swap->total, "swap", "total", NULL);
243                  add_stat(LONG_LONG, &swap->used, "swap", "used", NULL);
244                  add_stat(LONG_LONG, &swap->free, "swap", "free", NULL);
245          }
246 + }
247  
248 <        gen = get_general_stats();
248 > void populate_general() {
249 >        general_stat_t *gen = get_general_stats();
250 >
251          if (gen != NULL) {
252                  add_stat(STRING, &gen->os_name,
253                           "general", "os_name", NULL);
# Line 249 | Line 259 | void get_stats(int use_diffs) {
259                  add_stat(STRING, &gen->hostname, "general", "hostname", NULL);
260                  add_stat(TIME_T, &gen->uptime, "general", "uptime", NULL);
261          }
262 + }
263  
264 <        disk = get_disk_stats(&n);
264 > void populate_fs() {
265 >        int n, i;
266 >        disk_stat_t *disk = get_disk_stats(&n);
267 >
268          if (disk != NULL) {
269                  for (i = 0; i < n; i++) {
270                          /* FIXME it'd be nicer if libstatgrab did this */
271 <                        const char *name = disk[i].device_name,
272 <                                   *p = strrchr(name, '/');
273 <                        if (p != NULL)
274 <                                name = p + 1;
275 <                        if (*name == '\0')
276 <                                name = "root";
277 <        
271 >                        char *buf, *name, *p;
272 >                        const char *device = disk[i].device_name;
273 >
274 >                        if (strcmp(device, "/") == 0)
275 >                                device = "root";
276 >
277 >                        buf = strdup(device);
278 >                        if (buf == NULL)
279 >                                die("out of memory");
280 >
281 >                        name = buf;
282 >                        if (strncmp(name, "/dev/", 5) == 0)
283 >                                name += 5;
284 >                        while ((p = strchr(name, '/')) != NULL)
285 >                                *p = '_';
286 >
287                          add_stat(STRING, &disk[i].device_name,
288                                   "fs", name, "device_name", NULL);
289                          add_stat(STRING, &disk[i].fs_type,
# Line 279 | Line 302 | void get_stats(int use_diffs) {
302                                   "fs", name, "used_inodes", NULL);
303                          add_stat(LONG_LONG, &disk[i].free_inodes,
304                                   "fs", name, "free_inodes", NULL);
305 +
306 +                        free(buf);
307                  }
308          }
309 + }
310  
311 + void populate_disk() {
312 +        int n, i;
313 +        diskio_stat_t *diskio;
314 +
315          diskio = use_diffs ? get_diskio_stats_diff(&n) : get_diskio_stats(&n);
316          if (diskio != NULL) {
317                  for (i = 0; i < n; i++) {
# Line 297 | Line 327 | void get_stats(int use_diffs) {
327                                   "disk", name, "systime", NULL);
328                  }
329          }
330 + }
331  
332 <        proc = get_process_stats();
332 > void populate_proc() {
333 >        process_stat_t *proc = get_process_stats();
334 >
335          if (proc != NULL) {
336                  add_stat(INT, &proc->total, "proc", "total", NULL);
337                  add_stat(INT, &proc->running, "proc", "running", NULL);
# Line 306 | Line 339 | void get_stats(int use_diffs) {
339                  add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
340                  add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
341          }
342 + }
343  
344 + void populate_net() {
345 +        int n, i;
346 +        network_stat_t *net;
347 +
348          net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n);
349          if (net != NULL) {
350                  for (i = 0; i < n; i++) {
# Line 322 | Line 360 | void get_stats(int use_diffs) {
360                                   "net", name, "systime", NULL);
361                  }
362          }
363 + }
364  
365 + void populate_page() {
366 +        page_stat_t *page;
367 +
368          page = use_diffs ? get_page_stats_diff() : get_page_stats();
369          if (page != NULL) {
370                  add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
371                  add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
372 <                add_stat(LONG_LONG, &page->systime, "page", "systime", NULL);
372 >                add_stat(TIME_T, &page->systime, "page", "systime", NULL);
373          }
374 + }
375  
376 + typedef struct {
377 +        const char *name;
378 +        void (*populate)();
379 +        int interesting;
380 + } toplevel;
381 + toplevel toplevels[] = {
382 +        {"const.", populate_const, 0},
383 +        {"cpu.", populate_cpu, 0},
384 +        {"mem.", populate_mem, 0},
385 +        {"load.", populate_load, 0},
386 +        {"user.", populate_user, 0},
387 +        {"swap.", populate_swap, 0},
388 +        {"general.", populate_general, 0},
389 +        {"fs.", populate_fs, 0},
390 +        {"disk.", populate_disk, 0},
391 +        {"proc.", populate_proc, 0},
392 +        {"net.", populate_net, 0},
393 +        {"page.", populate_page, 0},
394 +        {NULL, NULL, 0}
395 + };
396 +
397 + /* Set the "interesting" flag on the sections that we actually need to
398 +   fetch. */
399 + void select_interesting(int argc, char **argv) {
400 +        toplevel *t;
401 +
402 +        if (argc == 0) {
403 +                for (t = &toplevels[0]; t->name != NULL; t++)
404 +                        t->interesting = 1;
405 +        } else {
406 +                int i;
407 +
408 +                for (i = 0; i < argc; i++) {
409 +                        for (t = &toplevels[0]; t->name != NULL; t++) {
410 +                                if (strncmp(argv[i], t->name,
411 +                                            strlen(t->name)) == 0) {
412 +                                        t->interesting = 1;
413 +                                        break;
414 +                                }
415 +                        }
416 +                }
417 +        }
418 + }
419 +
420 + /* Clear and rebuild the stats array. */
421 + void get_stats() {
422 +        toplevel *t;
423 +
424 +        clear_stats();
425 +
426 +        for (t = &toplevels[0]; t->name != NULL; t++) {
427 +                if (t->interesting)
428 +                        t->populate();
429 +        }
430 +
431          qsort(stats, num_stats, sizeof *stats, stats_compare);
432   }
433  
# Line 389 | Line 487 | void print_stats(int argc, char **argv) {
487          } else {
488                  /* Print selected stats. */
489                  for (i = optind; i < argc; i++) {
490 +                        char *name = argv[i];
491                          stat key;
492 <                        const stat *s;
492 >                        const stat *s, *end;
493 >                        int (*compare)(const void *, const void *);
494  
495 <                        key.name = argv[i];
495 >                        key.name = name;
496 >                        if (name[strlen(name) - 1] == '.')
497 >                                compare = stats_compare_prefix;
498 >                        else
499 >                                compare = stats_compare;
500 >
501                          s = (const stat *)bsearch(&key, stats, num_stats,
502 <                                                  sizeof *stats,
503 <                                                  stats_compare);
504 <                        if (s != NULL) {
502 >                                                  sizeof *stats, compare);
503 >                        if (s == NULL) {
504 >                                printf("Unknown stat %s\n", name);
505 >                                continue;
506 >                        }
507 >
508 >                        /* Find the range of stats the user wanted. */
509 >                        for (; s >= stats; s--) {
510 >                                if (compare(&key, s) != 0)
511 >                                        break;
512 >                        }
513 >                        s++;
514 >                        for (end = s; end < &stats[num_stats]; end++) {
515 >                                if (compare(&key, end) != 0)
516 >                                        break;
517 >                        }
518 >
519 >                        /* And print them. */
520 >                        for (; s < end; s++) {
521                                  print_stat(s);
522                          }
523                  }
# Line 405 | Line 526 | void print_stats(int argc, char **argv) {
526  
527   void usage() {
528          printf("Usage: statgrab [OPTION]... [STAT]...\n"
529 <               "Display system statistics (all statistics by default).\n"
529 >               "Display system statistics.\n"
530 >               "\n"
531 >               "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n"
532 >               "statistics starting with that prefix.\n"
533                 "\n");
534          printf("  -l         Linux sysctl-style output (default)\n"
535                 "  -b         BSD sysctl-style output\n"
# Line 472 | Line 596 | int main(int argc, char **argv) {
596          if (use_cpu_percent && repeat_mode == REPEAT_NONE)
597                  die("CPU percentage usage display requires stat differences");
598  
599 +        if (repeat_mode == REPEAT_NONE)
600 +                use_diffs = 0;
601 +        else
602 +                use_diffs = 1;
603 +
604 +        select_interesting(argc - optind, &argv[optind]);
605 +
606 +        /* We don't care if statgrab_init fails, because we can just display
607 +           the statistics that can be read as non-root. */
608 +        statgrab_init();
609 + #ifdef ALLBSD
610 +        if (setegid(getgid()) != 0)
611 +                die("Failed to lose effective group");
612 + #endif
613 +
614          switch (repeat_mode) {
615          case REPEAT_NONE:
616 <                get_stats(0);
616 >                get_stats();
617                  print_stats(argc, argv);
618                  break;
619          case REPEAT_ONCE:
620 <                get_stats(1);
620 >                get_stats();
621                  sleep(repeat_time);
622 <                get_stats(1);
622 >                get_stats();
623                  print_stats(argc, argv);
624                  break;
625          case REPEAT_FOREVER:
626                  while (1) {
627 <                        get_stats(1);
627 >                        get_stats();
628                          print_stats(argc, argv);
629                          printf("\n");
630                          sleep(repeat_time);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines