ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.3
Committed: Wed Aug 27 14:04:17 2003 UTC (21 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.2: +4 -0 lines
Log Message:
Have to pull in the definitions from config.h.

File Contents

# User Rev Content
1 tdb 1.1 /*
2     * i-scream central monitoring system
3     * http://www.i-scream.org
4     * Copyright (C) 2000-2003 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
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
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    
21 tdb 1.3 #ifdef HAVE_CONFIG_H
22     #include "config.h"
23     #endif
24    
25 tdb 1.1 #include <statgrab.h>
26     #include <string.h>
27     #include <stdio.h>
28     #include <stdarg.h>
29     #include <stdlib.h>
30     #include <unistd.h>
31    
32     typedef enum {
33     LONG_LONG = 0,
34     TIME_T,
35     FLOAT,
36     DOUBLE,
37     STRING,
38     INT
39     } stat_type;
40    
41     typedef enum {
42     DISPLAY_LINUX = 0,
43     DISPLAY_BSD,
44     DISPLAY_MRTG,
45     DISPLAY_PLAIN
46     } display_mode_type;
47    
48     typedef enum {
49     REPEAT_NONE = 0,
50     REPEAT_ONCE,
51     REPEAT_FOREVER
52     } repeat_mode_type;
53    
54     typedef struct {
55     char *name;
56     stat_type type;
57     void *stat;
58     } stat;
59    
60     stat *stats = NULL;
61     int num_stats = 0;
62     int alloc_stats = 0;
63     #define INCREMENT_STATS 64
64    
65     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    
70     /* Exit with an error message. */
71     void die(const char *s) {
72     fprintf(stderr, "fatal: %s\n", s);
73     exit(1);
74     }
75    
76     /* Remove all the recorded stats. */
77     void clear_stats() {
78     int i;
79    
80     for (i = 0; i < num_stats; i++)
81     free(stats[i].name);
82     free(stats);
83     stats = NULL;
84     num_stats = 0;
85     alloc_stats = 0;
86     }
87    
88     /* Add a stat. The varargs make up the name, joined with dots; the name is
89     terminated with a NULL. */
90     void add_stat(stat_type type, void *stat, ...) {
91     va_list ap;
92     int len = 0;
93     char *name, *p;
94    
95     /* Figure out how long the name will be, including dots and trailing
96     \0. */
97     va_start(ap, stat);
98     while (1) {
99     const char *part = va_arg(ap, const char *);
100     if (part == NULL)
101     break;
102     len += 1 + strlen(part);
103     }
104     va_end(ap);
105    
106     /* Paste the name together. */
107     name = malloc(len);
108     if (name == NULL)
109     die("out of memory");
110     p = name;
111     va_start(ap, stat);
112     while (1) {
113     const char *part = va_arg(ap, const char *);
114     int partlen;
115     if (part == NULL)
116     break;
117     partlen = strlen(part);
118     memcpy(p, part, partlen);
119     p += partlen;
120     *p++ = '.';
121     }
122     va_end(ap);
123     *--p = '\0';
124    
125     /* Replace spaces with underscores. */
126     for (p = name; *p != '\0'; p++) {
127     if (*p == ' ')
128     *p = '_';
129     }
130    
131     /* Stretch the stats array if necessary. */
132     if (num_stats >= alloc_stats) {
133     alloc_stats += INCREMENT_STATS;
134     stats = realloc(stats, alloc_stats * sizeof *stats);
135     if (stats == NULL)
136     die("out of memory");
137     }
138    
139     stats[num_stats].name = name;
140     stats[num_stats].type = type;
141     stats[num_stats].stat = stat;
142     ++num_stats;
143     }
144    
145     /* Compare two stats by name, for sorting purposes. */
146     int stats_compare(const void *a, const void *b) {
147     return strcmp(((stat *)a)->name, ((stat *)b)->name);
148     }
149    
150     /* Clear and rebuild the stats array. */
151     void get_stats(int use_diffs) {
152     cpu_states_t *cpu_s;
153     cpu_percent_t *cpu_p;
154     mem_stat_t *mem;
155     load_stat_t *load;
156     user_stat_t *user;
157     swap_stat_t *swap;
158     general_stat_t *gen;
159     disk_stat_t *disk;
160     diskio_stat_t *diskio;
161     process_stat_t *proc;
162     network_stat_t *net;
163     page_stat_t *page;
164     static int zero = 0;
165     int n, i;
166    
167     clear_stats();
168    
169     /* Constants, for use with MRTG mode. */
170     add_stat(INT, &zero, "const", "0", NULL);
171    
172     /* FIXME when only fetching some stats, it'd be more efficient to only
173     do the libstatgrab calls needed, rather than fetching everything. */
174    
175     if (use_cpu_percent) {
176     cpu_p = cpu_percent_usage();
177     if (cpu_p != NULL) {
178     add_stat(FLOAT, &cpu_p->user,
179     "cpu", "user", NULL);
180     add_stat(FLOAT, &cpu_p->kernel,
181     "cpu", "kernel", NULL);
182     add_stat(FLOAT, &cpu_p->idle,
183     "cpu", "idle", NULL);
184     add_stat(FLOAT, &cpu_p->iowait,
185     "cpu", "iowait", NULL);
186     add_stat(FLOAT, &cpu_p->swap,
187     "cpu", "swap", NULL);
188     add_stat(FLOAT, &cpu_p->nice,
189     "cpu", "nice", NULL);
190     add_stat(TIME_T, &cpu_s->systime,
191     "cpu", "time_taken", NULL);
192     }
193     } else {
194     cpu_s = use_diffs ? get_cpu_diff() : get_cpu_totals();
195     if (cpu_s != NULL) {
196     add_stat(LONG_LONG, &cpu_s->user,
197     "cpu", "user", NULL);
198     add_stat(LONG_LONG, &cpu_s->kernel,
199     "cpu", "kernel", NULL);
200     add_stat(LONG_LONG, &cpu_s->idle,
201     "cpu", "idle", NULL);
202     add_stat(LONG_LONG, &cpu_s->iowait,
203     "cpu", "iowait", NULL);
204     add_stat(LONG_LONG, &cpu_s->swap,
205     "cpu", "swap", NULL);
206     add_stat(LONG_LONG, &cpu_s->nice,
207     "cpu", "nice", NULL);
208     add_stat(LONG_LONG, &cpu_s->total,
209     "cpu", "total", NULL);
210     add_stat(TIME_T, &cpu_s->systime,
211     "cpu", "systime", NULL);
212     }
213     }
214    
215     mem = get_memory_stats();
216     if (mem != NULL) {
217     add_stat(LONG_LONG, &mem->total, "mem", "total", NULL);
218     add_stat(LONG_LONG, &mem->free, "mem", "free", NULL);
219     add_stat(LONG_LONG, &mem->used, "mem", "used", NULL);
220     add_stat(LONG_LONG, &mem->cache, "mem", "cache", NULL);
221     }
222    
223     load = get_load_stats();
224     if (load != NULL) {
225     add_stat(DOUBLE, &load->min1, "load", "min1", NULL);
226     add_stat(DOUBLE, &load->min5, "load", "min5", NULL);
227     add_stat(DOUBLE, &load->min15, "load", "min15", NULL);
228     }
229    
230     user = get_user_stats();
231     if (user != NULL) {
232     add_stat(INT, &user->num_entries, "user", "num", NULL);
233     add_stat(STRING, &user->name_list, "user", "names", NULL);
234     }
235    
236     swap = get_swap_stats();
237     if (swap != NULL) {
238     add_stat(LONG_LONG, &swap->total, "swap", "total", NULL);
239     add_stat(LONG_LONG, &swap->used, "swap", "used", NULL);
240     add_stat(LONG_LONG, &swap->free, "swap", "free", NULL);
241     }
242    
243     gen = get_general_stats();
244     if (gen != NULL) {
245     add_stat(STRING, &gen->os_name,
246     "general", "os_name", NULL);
247     add_stat(STRING, &gen->os_release,
248     "general", "os_release", NULL);
249     add_stat(STRING, &gen->os_version,
250     "general", "os_version", NULL);
251     add_stat(STRING, &gen->platform, "general", "platform", NULL);
252     add_stat(STRING, &gen->hostname, "general", "hostname", NULL);
253     add_stat(TIME_T, &gen->uptime, "general", "uptime", NULL);
254     }
255    
256     disk = get_disk_stats(&n);
257     if (disk != NULL) {
258     for (i = 0; i < n; i++) {
259     /* FIXME it'd be nicer if libstatgrab did this */
260     const char *name = disk[i].device_name,
261     *p = strrchr(name, '/');
262     if (p != NULL)
263     name = p + 1;
264     if (*name == '\0')
265     name = "root";
266    
267     add_stat(STRING, &disk[i].device_name,
268     "fs", name, "device_name", NULL);
269     add_stat(STRING, &disk[i].fs_type,
270     "fs", name, "fs_type", NULL);
271     add_stat(STRING, &disk[i].mnt_point,
272     "fs", name, "mnt_point", NULL);
273     add_stat(LONG_LONG, &disk[i].size,
274     "fs", name, "size", NULL);
275     add_stat(LONG_LONG, &disk[i].used,
276     "fs", name, "used", NULL);
277     add_stat(LONG_LONG, &disk[i].avail,
278     "fs", name, "avail", NULL);
279     add_stat(LONG_LONG, &disk[i].total_inodes,
280     "fs", name, "total_inodes", NULL);
281     add_stat(LONG_LONG, &disk[i].used_inodes,
282     "fs", name, "used_inodes", NULL);
283     add_stat(LONG_LONG, &disk[i].free_inodes,
284     "fs", name, "free_inodes", NULL);
285     }
286     }
287    
288     diskio = use_diffs ? get_diskio_stats_diff(&n) : get_diskio_stats(&n);
289     if (diskio != NULL) {
290     for (i = 0; i < n; i++) {
291     const char *name = diskio[i].disk_name;
292    
293     add_stat(STRING, &diskio[i].disk_name,
294     "disk", name, "disk_name", NULL);
295     add_stat(LONG_LONG, &diskio[i].read_bytes,
296     "disk", name, "read_bytes", NULL);
297     add_stat(LONG_LONG, &diskio[i].write_bytes,
298     "disk", name, "write_bytes", NULL);
299     add_stat(TIME_T, &diskio[i].systime,
300     "disk", name, "systime", NULL);
301     }
302     }
303    
304     proc = get_process_stats();
305     if (proc != NULL) {
306     add_stat(INT, &proc->total, "proc", "total", NULL);
307     add_stat(INT, &proc->running, "proc", "running", NULL);
308     add_stat(INT, &proc->sleeping, "proc", "sleeping", NULL);
309     add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
310     add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
311     }
312    
313     net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n);
314     if (net != NULL) {
315     for (i = 0; i < n; i++) {
316     const char *name = net[i].interface_name;
317    
318     add_stat(STRING, &net[i].interface_name,
319     "net", name, "interface_name", NULL);
320     add_stat(LONG_LONG, &net[i].tx,
321     "net", name, "tx", NULL);
322     add_stat(LONG_LONG, &net[i].rx,
323     "net", name, "rx", NULL);
324     add_stat(TIME_T, &net[i].systime,
325     "net", name, "systime", NULL);
326     }
327     }
328    
329     page = use_diffs ? get_page_stats_diff() : get_page_stats();
330     if (page != NULL) {
331     add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
332     add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
333     add_stat(LONG_LONG, &page->systime, "page", "systime", NULL);
334     }
335    
336     qsort(stats, num_stats, sizeof *stats, stats_compare);
337     }
338    
339     /* Print the value of a stat. */
340     void print_stat_value(const stat *s) {
341     void *v = s->stat;
342    
343     switch (s->type) {
344     case LONG_LONG:
345     printf("%lld", *(long long *)v);
346     break;
347     case TIME_T:
348     /* FIXME option for formatted time? */
349     printf("%ld", *(time_t *)v);
350     break;
351     case FLOAT:
352     printf("%f", *(float *)v);
353     break;
354     case DOUBLE:
355     printf("%f", *(double *)v);
356     break;
357     case STRING:
358     /* FIXME escaping? */
359     printf("%s", *(char **)v);
360     break;
361     case INT:
362     printf("%d", *(int *)v);
363     break;
364     }
365     }
366    
367     /* Print the name and value of a stat. */
368     void print_stat(const stat *s) {
369     switch (display_mode) {
370     case DISPLAY_LINUX:
371     printf("%s = ", s->name);
372     break;
373     case DISPLAY_BSD:
374     printf("%s: ", s->name);
375     break;
376     case DISPLAY_MRTG:
377     case DISPLAY_PLAIN:
378     break;
379     }
380     print_stat_value(s);
381     printf("\n");
382     }
383    
384     /* Print stats as specified on the provided command line. */
385     void print_stats(int argc, char **argv) {
386     int i;
387    
388     if (argc == optind) {
389     /* Print all stats. */
390     for (i = 0; i < num_stats; i++)
391     print_stat(&stats[i]);
392     } else {
393     /* Print selected stats. */
394     for (i = optind; i < argc; i++) {
395     stat key;
396     const stat *s;
397    
398     key.name = argv[i];
399     s = (const stat *)bsearch(&key, stats, num_stats,
400     sizeof *stats,
401     stats_compare);
402     if (s != NULL) {
403     print_stat(s);
404     }
405     }
406     }
407     }
408    
409     void usage() {
410     printf("Usage: statgrab [OPTION]... [STAT]...\n"
411     "Display system statistics (all statistics by default).\n"
412     "\n");
413     printf(" -l Linux sysctl-style output (default)\n"
414     " -b BSD sysctl-style output\n"
415     " -m MRTG-compatible output\n"
416     " -u Plain output (only show values)\n"
417     " -n Display cumulative stats once (default)\n"
418     " -s Display stat differences repeatedly\n"
419     " -o Display stat differences once\n"
420     " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n"
421     " -p Display CPU usage as percentages rather than absolute values\n"
422     "\n");
423 tdb 1.2 printf("Version %s - report bugs to <%s>.\n",
424     PACKAGE_VERSION, PACKAGE_BUGREPORT);
425 tdb 1.1 exit(1);
426     }
427    
428     int main(int argc, char **argv) {
429     opterr = 0;
430     while (1) {
431     int c = getopt(argc, argv, "lbmunsot:p");
432     if (c == -1)
433     break;
434     switch (c) {
435     case 'l':
436     display_mode = DISPLAY_LINUX;
437     break;
438     case 'b':
439     display_mode = DISPLAY_BSD;
440     break;
441     case 'm':
442     display_mode = DISPLAY_MRTG;
443     break;
444     case 'u':
445     display_mode = DISPLAY_PLAIN;
446     break;
447     case 'n':
448     repeat_mode = REPEAT_NONE;
449     break;
450     case 's':
451     repeat_mode = REPEAT_FOREVER;
452     break;
453     case 'o':
454     repeat_mode = REPEAT_ONCE;
455     break;
456     case 't':
457     repeat_time = atoi(optarg);
458     break;
459     case 'p':
460     use_cpu_percent = 1;
461     break;
462     default:
463     usage();
464     }
465     }
466    
467     if (display_mode == DISPLAY_MRTG) {
468     if ((argc - optind) != 2)
469     die("mrtg mode: must specify exactly two stats");
470     if (repeat_mode != REPEAT_NONE)
471     die("mrtg mode: cannot repeat display");
472     }
473    
474     switch (repeat_mode) {
475     case REPEAT_NONE:
476     get_stats(0);
477     print_stats(argc, argv);
478     break;
479     case REPEAT_ONCE:
480     get_stats(1);
481     sleep(repeat_time);
482     get_stats(1);
483     print_stats(argc, argv);
484     break;
485     case REPEAT_FOREVER:
486     while (1) {
487     get_stats(1);
488     print_stats(argc, argv);
489     printf("\n");
490     sleep(repeat_time);
491     }
492     }
493    
494     if (display_mode == DISPLAY_MRTG) {
495     printf("\n");
496     printf("statgrab\n");
497     }
498    
499     return 0;
500     }
501