--- projects/libstatgrab/src/statgrab/statgrab.c 2003/08/29 06:56:12 1.8 +++ projects/libstatgrab/src/statgrab/statgrab.c 2004/01/16 15:54:56 1.16 @@ -1,7 +1,7 @@ /* * i-scream central monitoring system * http://www.i-scream.org - * Copyright (C) 2000-2003 i-scream + * Copyright (C) 2000-2004 i-scream * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -140,11 +140,19 @@ void add_stat(stat_type type, void *stat, ...) { ++num_stats; } -/* Compare two stats by name, for sorting purposes. */ +/* Compare two stats by name for qsort and bsearch. */ int stats_compare(const void *a, const void *b) { return strcmp(((stat *)a)->name, ((stat *)b)->name); } +/* Compare up to the length of the key for bsearch. */ +int stats_compare_prefix(const void *key, const void *item) { + const char *kn = ((stat *)key)->name; + const char *in = ((stat *)item)->name; + + return strncmp(kn, in, strlen(kn)); +} + void populate_const() { static int zero = 0; @@ -260,13 +268,24 @@ void populate_fs() { if (disk != NULL) { for (i = 0; i < n; i++) { /* FIXME it'd be nicer if libstatgrab did this */ - const char *name = disk[i].device_name, - *p = strrchr(name, '/'); - if (p != NULL) - name = p + 1; - if (*name == '\0') - name = "root"; - + char *buf, *name, *p; + const char *device = disk[i].device_name; + + if (strcmp(device, "/") == 0) + device = "root"; + + buf = strdup(device); + if (buf == NULL) + die("out of memory"); + + name = buf; + if (strlen(name) == 2 && name[1] == ':') + name[1] = '\0'; + if (strncmp(name, "/dev/", 5) == 0) + name += 5; + while ((p = strchr(name, '/')) != NULL) + *p = '_'; + add_stat(STRING, &disk[i].device_name, "fs", name, "device_name", NULL); add_stat(STRING, &disk[i].fs_type, @@ -285,6 +304,8 @@ void populate_fs() { "fs", name, "used_inodes", NULL); add_stat(LONG_LONG, &disk[i].free_inodes, "fs", name, "free_inodes", NULL); + + free(buf); } } } @@ -350,7 +371,7 @@ void populate_page() { if (page != NULL) { add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL); add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL); - add_stat(LONG_LONG, &page->systime, "page", "systime", NULL); + add_stat(TIME_T, &page->systime, "page", "systime", NULL); } } @@ -468,14 +489,37 @@ void print_stats(int argc, char **argv) { } else { /* Print selected stats. */ for (i = optind; i < argc; i++) { + char *name = argv[i]; stat key; - const stat *s; + const stat *s, *end; + int (*compare)(const void *, const void *); - key.name = argv[i]; + key.name = name; + if (name[strlen(name) - 1] == '.') + compare = stats_compare_prefix; + else + compare = stats_compare; + s = (const stat *)bsearch(&key, stats, num_stats, - sizeof *stats, - stats_compare); - if (s != NULL) { + sizeof *stats, compare); + if (s == NULL) { + printf("Unknown stat %s\n", name); + continue; + } + + /* Find the range of stats the user wanted. */ + for (; s >= stats; s--) { + if (compare(&key, s) != 0) + break; + } + s++; + for (end = s; end < &stats[num_stats]; end++) { + if (compare(&key, end) != 0) + break; + } + + /* And print them. */ + for (; s < end; s++) { print_stat(s); } } @@ -484,7 +528,10 @@ void print_stats(int argc, char **argv) { void usage() { printf("Usage: statgrab [OPTION]... [STAT]...\n" - "Display system statistics (all statistics by default).\n" + "Display system statistics.\n" + "\n" + "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n" + "statistics starting with that prefix.\n" "\n"); printf(" -l Linux sysctl-style output (default)\n" " -b BSD sysctl-style output\n" @@ -557,6 +604,12 @@ int main(int argc, char **argv) { use_diffs = 1; select_interesting(argc - optind, &argv[optind]); + + /* We don't care if statgrab_init fails, because we can just display + the statistics that can be read as non-root. */ + statgrab_init(); + if (statgrab_drop_privileges() != 0) + die("Failed to drop setuid/setgid privileges"); switch (repeat_mode) { case REPEAT_NONE: