--- projects/libstatgrab/src/statgrab/statgrab.c 2004/04/06 14:53:00 1.25 +++ projects/libstatgrab/src/statgrab/statgrab.c 2010/10/03 18:35:59 1.38 @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id: statgrab.c,v 1.25 2004/04/06 14:53:00 tdb Exp $ + * $Id: statgrab.c,v 1.38 2010/10/03 18:35:59 tdb Exp $ */ #ifdef HAVE_CONFIG_H @@ -33,6 +33,7 @@ typedef enum { LONG_LONG = 0, + BYTES, TIME_T, FLOAT, DOUBLE, @@ -59,9 +60,13 @@ typedef struct { char *name; stat_type type; void *stat; -} stat; +} stat_item; +/* AIX: +statgrab.c:63: error: 'stat' redeclared as different kind of symbol +/usr/include/sys/stat.h:320: error: previous declaration of 'stat' was here + */ -stat *stats = NULL; +stat_item *stat_items = NULL; int num_stats = 0; int alloc_stats = 0; #define INCREMENT_STATS 64 @@ -71,6 +76,8 @@ repeat_mode_type repeat_mode = REPEAT_NONE; int repeat_time = 1; int use_cpu_percent = 0; int use_diffs = 0; +long float_scale_factor = 0; +long long bytes_scale_factor = 0; /* Exit with an error message. */ void die(const char *s) { @@ -83,7 +90,7 @@ void clear_stats() { int i; for (i = 0; i < num_stats; i++) - free(stats[i].name); + free(stat_items[i].name); num_stats = 0; } @@ -118,41 +125,42 @@ void add_stat(stat_type type, void *stat, ...) { break; partlen = strlen(part); memcpy(p, part, partlen); - p += partlen; + + /* Replace spaces and dots with underscores. */ + while (partlen-- > 0) { + if (*p == ' ' || *p == '.') + *p = '_'; + p++; + } + *p++ = '.'; } va_end(ap); *--p = '\0'; - /* Replace spaces with underscores. */ - for (p = name; *p != '\0'; p++) { - if (*p == ' ') - *p = '_'; - } - /* Stretch the stats array if necessary. */ if (num_stats >= alloc_stats) { alloc_stats += INCREMENT_STATS; - stats = realloc(stats, alloc_stats * sizeof *stats); - if (stats == NULL) + stat_items = realloc(stat_items, alloc_stats * sizeof *stat_items); + if (stat_items == NULL) die("out of memory"); } - stats[num_stats].name = name; - stats[num_stats].type = type; - stats[num_stats].stat = stat; + stat_items[num_stats].name = name; + stat_items[num_stats].type = type; + stat_items[num_stats].stat = stat; ++num_stats; } /* 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); + return strcmp(((stat_item *)a)->name, ((stat_item *)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; + const char *kn = ((stat_item *)key)->name; + const char *in = ((stat_item *)item)->name; return strncmp(kn, in, strlen(kn)); } @@ -170,42 +178,42 @@ void populate_cpu() { if (cpu_p != NULL) { add_stat(FLOAT, &cpu_p->user, - "cpu", "user", NULL); + "cpu", "user", NULL); add_stat(FLOAT, &cpu_p->kernel, - "cpu", "kernel", NULL); + "cpu", "kernel", NULL); add_stat(FLOAT, &cpu_p->idle, - "cpu", "idle", NULL); + "cpu", "idle", NULL); add_stat(FLOAT, &cpu_p->iowait, - "cpu", "iowait", NULL); + "cpu", "iowait", NULL); add_stat(FLOAT, &cpu_p->swap, - "cpu", "swap", NULL); + "cpu", "swap", NULL); add_stat(FLOAT, &cpu_p->nice, - "cpu", "nice", NULL); + "cpu", "nice", NULL); add_stat(TIME_T, &cpu_p->time_taken, - "cpu", "time_taken", NULL); + "cpu", "time_taken", NULL); } } else { sg_cpu_stats *cpu_s; cpu_s = use_diffs ? sg_get_cpu_stats_diff() - : sg_get_cpu_stats(); + : sg_get_cpu_stats(); if (cpu_s != NULL) { add_stat(LONG_LONG, &cpu_s->user, - "cpu", "user", NULL); + "cpu", "user", NULL); add_stat(LONG_LONG, &cpu_s->kernel, - "cpu", "kernel", NULL); + "cpu", "kernel", NULL); add_stat(LONG_LONG, &cpu_s->idle, - "cpu", "idle", NULL); + "cpu", "idle", NULL); add_stat(LONG_LONG, &cpu_s->iowait, - "cpu", "iowait", NULL); + "cpu", "iowait", NULL); add_stat(LONG_LONG, &cpu_s->swap, - "cpu", "swap", NULL); + "cpu", "swap", NULL); add_stat(LONG_LONG, &cpu_s->nice, - "cpu", "nice", NULL); + "cpu", "nice", NULL); add_stat(LONG_LONG, &cpu_s->total, - "cpu", "total", NULL); + "cpu", "total", NULL); add_stat(TIME_T, &cpu_s->systime, - "cpu", "systime", NULL); + "cpu", "systime", NULL); } } } @@ -214,10 +222,10 @@ void populate_mem() { sg_mem_stats *mem = sg_get_mem_stats(); if (mem != NULL) { - add_stat(LONG_LONG, &mem->total, "mem", "total", NULL); - add_stat(LONG_LONG, &mem->free, "mem", "free", NULL); - add_stat(LONG_LONG, &mem->used, "mem", "used", NULL); - add_stat(LONG_LONG, &mem->cache, "mem", "cache", NULL); + add_stat(BYTES, &mem->total, "mem", "total", NULL); + add_stat(BYTES, &mem->free, "mem", "free", NULL); + add_stat(BYTES, &mem->used, "mem", "used", NULL); + add_stat(BYTES, &mem->cache, "mem", "cache", NULL); } } @@ -244,9 +252,9 @@ void populate_swap() { sg_swap_stats *swap = sg_get_swap_stats(); if (swap != NULL) { - add_stat(LONG_LONG, &swap->total, "swap", "total", NULL); - add_stat(LONG_LONG, &swap->used, "swap", "used", NULL); - add_stat(LONG_LONG, &swap->free, "swap", "free", NULL); + add_stat(BYTES, &swap->total, "swap", "total", NULL); + add_stat(BYTES, &swap->used, "swap", "used", NULL); + add_stat(BYTES, &swap->free, "swap", "free", NULL); } } @@ -256,11 +264,11 @@ void populate_general() { if (host != NULL) { add_stat(STRING, &host->os_name, - "general", "os_name", NULL); + "general", "os_name", NULL); add_stat(STRING, &host->os_release, - "general", "os_release", NULL); + "general", "os_release", NULL); add_stat(STRING, &host->os_version, - "general", "os_version", NULL); + "general", "os_version", NULL); add_stat(STRING, &host->platform, "general", "platform", NULL); add_stat(STRING, &host->hostname, "general", "hostname", NULL); add_stat(TIME_T, &host->uptime, "general", "uptime", NULL); @@ -293,23 +301,37 @@ void populate_fs() { *p = '_'; add_stat(STRING, &disk[i].device_name, - "fs", name, "device_name", NULL); + "fs", name, "device_name", NULL); add_stat(STRING, &disk[i].fs_type, - "fs", name, "fs_type", NULL); + "fs", name, "fs_type", NULL); add_stat(STRING, &disk[i].mnt_point, - "fs", name, "mnt_point", NULL); - add_stat(LONG_LONG, &disk[i].size, - "fs", name, "size", NULL); - add_stat(LONG_LONG, &disk[i].used, - "fs", name, "used", NULL); - add_stat(LONG_LONG, &disk[i].avail, - "fs", name, "avail", NULL); + "fs", name, "mnt_point", NULL); + add_stat(BYTES, &disk[i].size, + "fs", name, "size", NULL); + add_stat(BYTES, &disk[i].used, + "fs", name, "used", NULL); + add_stat(BYTES, &disk[i].avail, + "fs", name, "avail", NULL); add_stat(LONG_LONG, &disk[i].total_inodes, - "fs", name, "total_inodes", NULL); + "fs", name, "total_inodes", NULL); add_stat(LONG_LONG, &disk[i].used_inodes, - "fs", name, "used_inodes", NULL); + "fs", name, "used_inodes", NULL); add_stat(LONG_LONG, &disk[i].free_inodes, - "fs", name, "free_inodes", NULL); + "fs", name, "free_inodes", NULL); + add_stat(LONG_LONG, &disk[i].avail_inodes, + "fs", name, "avail_inodes", NULL); + add_stat(LONG_LONG, &disk[i].io_size, + "fs", name, "io_size", NULL); + add_stat(LONG_LONG, &disk[i].block_size, + "fs", name, "block_size", NULL); + add_stat(LONG_LONG, &disk[i].total_blocks, + "fs", name, "total_blocks", NULL); + add_stat(LONG_LONG, &disk[i].free_blocks, + "fs", name, "free_blocks", NULL); + add_stat(LONG_LONG, &disk[i].avail_blocks, + "fs", name, "avail_blocks", NULL); + add_stat(LONG_LONG, &disk[i].used_blocks, + "fs", name, "used_blocks", NULL); free(buf); } @@ -321,19 +343,19 @@ void populate_disk() { sg_disk_io_stats *diskio; diskio = use_diffs ? sg_get_disk_io_stats_diff(&n) - : sg_get_disk_io_stats(&n); + : sg_get_disk_io_stats(&n); if (diskio != NULL) { for (i = 0; i < n; i++) { const char *name = diskio[i].disk_name; add_stat(STRING, &diskio[i].disk_name, - "disk", name, "disk_name", NULL); - add_stat(LONG_LONG, &diskio[i].read_bytes, - "disk", name, "read_bytes", NULL); - add_stat(LONG_LONG, &diskio[i].write_bytes, - "disk", name, "write_bytes", NULL); + "disk", name, "disk_name", NULL); + add_stat(BYTES, &diskio[i].read_bytes, + "disk", name, "read_bytes", NULL); + add_stat(BYTES, &diskio[i].write_bytes, + "disk", name, "write_bytes", NULL); add_stat(TIME_T, &diskio[i].systime, - "disk", name, "systime", NULL); + "disk", name, "systime", NULL); } } } @@ -352,48 +374,65 @@ void populate_proc() { } void populate_net() { - int n, i; + int num_io, num_iface, i; sg_network_io_stats *io; sg_network_iface_stats *iface; - io = use_diffs ? sg_get_network_io_stats_diff(&n) - : sg_get_network_io_stats(&n); + io = use_diffs ? sg_get_network_io_stats_diff(&num_io) + : sg_get_network_io_stats(&num_io); if (io != NULL) { - for (i = 0; i < n; i++) { + for (i = 0; i < num_io; i++) { const char *name = io[i].interface_name; add_stat(STRING, &io[i].interface_name, - "net", name, "interface_name", NULL); - add_stat(LONG_LONG, &io[i].tx, - "net", name, "tx", NULL); - add_stat(LONG_LONG, &io[i].rx, - "net", name, "rx", NULL); + "net", name, "interface_name", NULL); + add_stat(BYTES, &io[i].tx, + "net", name, "tx", NULL); + add_stat(BYTES, &io[i].rx, + "net", name, "rx", NULL); add_stat(LONG_LONG, &io[i].ipackets, - "net", name, "ipackets", NULL); + "net", name, "ipackets", NULL); add_stat(LONG_LONG, &io[i].opackets, - "net", name, "opackets", NULL); + "net", name, "opackets", NULL); add_stat(LONG_LONG, &io[i].ierrors, - "net", name, "ierrors", NULL); + "net", name, "ierrors", NULL); add_stat(LONG_LONG, &io[i].oerrors, - "net", name, "oerrors", NULL); + "net", name, "oerrors", NULL); add_stat(LONG_LONG, &io[i].collisions, - "net", name, "collisions", NULL); + "net", name, "collisions", NULL); add_stat(TIME_T, &io[i].systime, - "net", name, "systime", NULL); + "net", name, "systime", NULL); } } - iface = sg_get_network_iface_stats(&n); + iface = sg_get_network_iface_stats(&num_iface); if (iface != NULL) { - for (i = 0; i < n; i++) { + for (i = 0; i < num_iface; i++) { const char *name = iface[i].interface_name; + int had_io = 0, j; + /* If there wasn't a corresponding io stat, + add interface_name from here. */ + if (io != NULL) { + for (j = 0; j < num_io; j++) { + if (strcmp(io[j].interface_name, + name) == 0) { + had_io = 1; + break; + } + } + } + if (!had_io) { + add_stat(STRING, &iface[i].interface_name, + "net", name, "interface_name", NULL); + } + add_stat(INT, &iface[i].speed, - "net", name, "speed", NULL); + "net", name, "speed", NULL); add_stat(BOOL, &iface[i].up, - "net", name, "up", NULL); - add_stat(DUPLEX, &iface[i].dup, - "net", name, "duplex", NULL); + "net", name, "up", NULL); + add_stat(DUPLEX, &iface[i].duplex, + "net", name, "duplex", NULL); } } } @@ -444,7 +483,7 @@ void select_interesting(int argc, char **argv) { for (i = 0; i < argc; i++) { for (t = &toplevels[0]; t->name != NULL; t++) { if (strncmp(argv[i], t->name, - strlen(t->name)) == 0) { + strlen(t->name)) == 0) { t->interesting = 1; break; } @@ -453,7 +492,7 @@ void select_interesting(int argc, char **argv) { } } -/* Clear and rebuild the stats array. */ +/* Clear and rebuild the stat_items array. */ void get_stats() { toplevel *t; @@ -464,29 +503,53 @@ void get_stats() { t->populate(); } - if (stats != NULL) - qsort(stats, num_stats, sizeof *stats, stats_compare); + if (stat_items != NULL) + qsort(stat_items, num_stats, sizeof *stat_items, stats_compare); } -/* Print the value of a stat. */ -void print_stat_value(const stat *s) { +/* Print the value of a stat_item. */ +void print_stat_value(const stat_item *s) { void *v = s->stat; - long l; + double fv; + long lv; + long long llv; switch (s->type) { case LONG_LONG: +#ifdef WIN32 /* Windows printf does not understand %lld, so use %I64d instead */ + printf("%I64d", *(long long *)v); +#else printf("%lld", *(long long *)v); +#endif break; + case BYTES: + llv = *(long long *)v; + if (bytes_scale_factor != 0) { + llv /= bytes_scale_factor; + } +#ifdef WIN32 + printf("%I64d", llv); +#else + printf("%lld", llv); +#endif + break; case TIME_T: /* FIXME option for formatted time? */ - l = *(time_t *)v; - printf("%ld", l); + lv = *(time_t *)v; + printf("%ld", lv); break; case FLOAT: - printf("%f", *(float *)v); - break; case DOUBLE: - printf("%f", *(double *)v); + if (s->type == FLOAT) { + fv = *(float *)v; + } else { + fv = *(double *)v; + } + if (float_scale_factor != 0) { + printf("%ld", (long)(float_scale_factor * fv)); + } else { + printf("%f", fv); + } break; case STRING: /* FIXME escaping? */ @@ -515,7 +578,7 @@ void print_stat_value(const stat *s) { } /* Print the name and value of a stat. */ -void print_stat(const stat *s) { +void print_stat(const stat_item *s) { switch (display_mode) { case DISPLAY_LINUX: printf("%s = ", s->name); @@ -538,13 +601,13 @@ void print_stats(int argc, char **argv) { if (argc == optind) { /* Print all stats. */ for (i = 0; i < num_stats; i++) - print_stat(&stats[i]); + print_stat(&stat_items[i]); } else { /* Print selected stats. */ for (i = optind; i < argc; i++) { char *name = argv[i]; - stat key; - const stat *s, *end; + stat_item key; + const stat_item *s, *end; int (*compare)(const void *, const void *); key.name = name; @@ -553,13 +616,13 @@ void print_stats(int argc, char **argv) { else compare = stats_compare; - if (stats == NULL) { + if (stat_items == NULL) { s = NULL; } else { - s = (const stat *)bsearch(&key, stats, - num_stats, - sizeof *stats, - compare); + s = (const stat_item *)bsearch(&key, stat_items, + num_stats, + sizeof *stat_items, + compare); } if (s == NULL) { @@ -568,12 +631,12 @@ void print_stats(int argc, char **argv) { } /* Find the range of stats the user wanted. */ - for (; s >= stats; s--) { + for (; s >= stat_items; s--) { if (compare(&key, s) != 0) break; } s++; - for (end = s; end < &stats[num_stats]; end++) { + for (end = s; end < &stat_items[num_stats]; end++) { if (compare(&key, end) != 0) break; } @@ -603,6 +666,10 @@ void usage() { " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n" " -p Display CPU usage differences as percentages rather than\n" " absolute values\n" + " -f FACTOR Display floating-point values as integers scaled by FACTOR\n" + " -K Display byte counts in kibibytes\n" + " -M Display byte counts in mebibytes\n" + " -G Display byte counts in gibibytes\n" "\n"); printf("Version %s - report bugs to <%s>.\n", PACKAGE_VERSION, PACKAGE_BUGREPORT); @@ -612,7 +679,7 @@ void usage() { int main(int argc, char **argv) { opterr = 0; while (1) { - int c = getopt(argc, argv, "lbmunsot:p"); + int c = getopt(argc, argv, "lbmunsot:pf:KMG"); if (c == -1) break; switch (c) { @@ -643,6 +710,18 @@ int main(int argc, char **argv) { case 'p': use_cpu_percent = 1; break; + case 'f': + float_scale_factor = atol(optarg); + break; + case 'K': + bytes_scale_factor = 1024; + break; + case 'M': + bytes_scale_factor = 1024 * 1024; + break; + case 'G': + bytes_scale_factor = 1024 * 1024 * 1024; + break; default: usage(); } @@ -665,9 +744,10 @@ int main(int argc, char **argv) { select_interesting(argc - optind, &argv[optind]); - /* We don't care if statgrab_init fails, because we can just display + /* We don't care if sg_init fails, because we can just display the statistics that can be read as non-root. */ sg_init(); + sg_snapshot(); if (sg_drop_privileges() != 0) die("Failed to drop setuid/setgid privileges"); @@ -679,6 +759,7 @@ int main(int argc, char **argv) { case REPEAT_ONCE: get_stats(); sleep(repeat_time); + sg_snapshot(); get_stats(); print_stats(argc, argv); break; @@ -688,6 +769,7 @@ int main(int argc, char **argv) { print_stats(argc, argv); printf("\n"); sleep(repeat_time); + sg_snapshot(); } } @@ -695,6 +777,8 @@ int main(int argc, char **argv) { printf("\n"); printf("statgrab\n"); } + + sg_shutdown(); return 0; }