ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.27
Committed: Fri Jul 16 11:17:16 2004 UTC (19 years, 10 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.26: +24 -7 lines
Log Message:
Make sure that network interfaces get an interface_name stat, even if they
don't have IO stats (like for loopback interfaces on Solaris).

File Contents

# User Rev Content
1 tdb 1.1 /*
2 tdb 1.25 * i-scream libstatgrab
3 tdb 1.1 * http://www.i-scream.org
4 tdb 1.16 * Copyright (C) 2000-2004 i-scream
5 tdb 1.1 *
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 tdb 1.17 *
20 ats 1.27 * $Id: statgrab.c,v 1.26 2004/04/07 15:50:26 tdb Exp $
21 tdb 1.1 */
22    
23 tdb 1.3 #ifdef HAVE_CONFIG_H
24     #include "config.h"
25     #endif
26    
27 tdb 1.1 #include <statgrab.h>
28     #include <string.h>
29     #include <stdio.h>
30     #include <stdarg.h>
31     #include <stdlib.h>
32     #include <unistd.h>
33    
34     typedef enum {
35     LONG_LONG = 0,
36     TIME_T,
37     FLOAT,
38     DOUBLE,
39     STRING,
40 ats 1.18 INT,
41 ats 1.20 BOOL,
42 ats 1.18 DUPLEX
43 tdb 1.1 } stat_type;
44    
45     typedef enum {
46     DISPLAY_LINUX = 0,
47     DISPLAY_BSD,
48     DISPLAY_MRTG,
49     DISPLAY_PLAIN
50     } display_mode_type;
51    
52     typedef enum {
53     REPEAT_NONE = 0,
54     REPEAT_ONCE,
55     REPEAT_FOREVER
56     } repeat_mode_type;
57    
58     typedef struct {
59     char *name;
60     stat_type type;
61     void *stat;
62     } stat;
63    
64     stat *stats = NULL;
65     int num_stats = 0;
66     int alloc_stats = 0;
67     #define INCREMENT_STATS 64
68    
69     display_mode_type display_mode = DISPLAY_LINUX;
70     repeat_mode_type repeat_mode = REPEAT_NONE;
71     int repeat_time = 1;
72     int use_cpu_percent = 0;
73 ats 1.8 int use_diffs = 0;
74 tdb 1.1
75     /* Exit with an error message. */
76     void die(const char *s) {
77     fprintf(stderr, "fatal: %s\n", s);
78     exit(1);
79     }
80    
81     /* Remove all the recorded stats. */
82     void clear_stats() {
83     int i;
84    
85     for (i = 0; i < num_stats; i++)
86     free(stats[i].name);
87     num_stats = 0;
88     }
89    
90     /* Add a stat. The varargs make up the name, joined with dots; the name is
91     terminated with a NULL. */
92     void add_stat(stat_type type, void *stat, ...) {
93     va_list ap;
94     int len = 0;
95     char *name, *p;
96    
97     /* Figure out how long the name will be, including dots and trailing
98     \0. */
99     va_start(ap, stat);
100     while (1) {
101     const char *part = va_arg(ap, const char *);
102     if (part == NULL)
103     break;
104     len += 1 + strlen(part);
105     }
106     va_end(ap);
107    
108     /* Paste the name together. */
109     name = malloc(len);
110     if (name == NULL)
111     die("out of memory");
112     p = name;
113     va_start(ap, stat);
114     while (1) {
115     const char *part = va_arg(ap, const char *);
116     int partlen;
117     if (part == NULL)
118     break;
119     partlen = strlen(part);
120     memcpy(p, part, partlen);
121     p += partlen;
122     *p++ = '.';
123     }
124     va_end(ap);
125     *--p = '\0';
126    
127     /* Replace spaces with underscores. */
128     for (p = name; *p != '\0'; p++) {
129     if (*p == ' ')
130     *p = '_';
131     }
132    
133     /* Stretch the stats array if necessary. */
134     if (num_stats >= alloc_stats) {
135     alloc_stats += INCREMENT_STATS;
136     stats = realloc(stats, alloc_stats * sizeof *stats);
137     if (stats == NULL)
138     die("out of memory");
139     }
140    
141     stats[num_stats].name = name;
142     stats[num_stats].type = type;
143     stats[num_stats].stat = stat;
144     ++num_stats;
145     }
146    
147 ats 1.9 /* Compare two stats by name for qsort and bsearch. */
148 tdb 1.1 int stats_compare(const void *a, const void *b) {
149     return strcmp(((stat *)a)->name, ((stat *)b)->name);
150     }
151    
152 ats 1.9 /* Compare up to the length of the key for bsearch. */
153     int stats_compare_prefix(const void *key, const void *item) {
154     const char *kn = ((stat *)key)->name;
155     const char *in = ((stat *)item)->name;
156    
157     return strncmp(kn, in, strlen(kn));
158     }
159    
160 ats 1.8 void populate_const() {
161 tdb 1.1 static int zero = 0;
162    
163     /* Constants, for use with MRTG mode. */
164     add_stat(INT, &zero, "const", "0", NULL);
165 ats 1.8 }
166 tdb 1.1
167 ats 1.8 void populate_cpu() {
168     if (use_cpu_percent) {
169 ats 1.24 sg_cpu_percents *cpu_p = sg_get_cpu_percents();
170 tdb 1.1
171     if (cpu_p != NULL) {
172     add_stat(FLOAT, &cpu_p->user,
173 tdb 1.26 "cpu", "user", NULL);
174 tdb 1.1 add_stat(FLOAT, &cpu_p->kernel,
175 tdb 1.26 "cpu", "kernel", NULL);
176 tdb 1.1 add_stat(FLOAT, &cpu_p->idle,
177 tdb 1.26 "cpu", "idle", NULL);
178 tdb 1.1 add_stat(FLOAT, &cpu_p->iowait,
179 tdb 1.26 "cpu", "iowait", NULL);
180 tdb 1.1 add_stat(FLOAT, &cpu_p->swap,
181 tdb 1.26 "cpu", "swap", NULL);
182 tdb 1.1 add_stat(FLOAT, &cpu_p->nice,
183 tdb 1.26 "cpu", "nice", NULL);
184 ats 1.7 add_stat(TIME_T, &cpu_p->time_taken,
185 tdb 1.26 "cpu", "time_taken", NULL);
186 tdb 1.1 }
187     } else {
188 ats 1.24 sg_cpu_stats *cpu_s;
189 ats 1.8
190 ats 1.24 cpu_s = use_diffs ? sg_get_cpu_stats_diff()
191 tdb 1.26 : sg_get_cpu_stats();
192 tdb 1.1 if (cpu_s != NULL) {
193     add_stat(LONG_LONG, &cpu_s->user,
194 tdb 1.26 "cpu", "user", NULL);
195 tdb 1.1 add_stat(LONG_LONG, &cpu_s->kernel,
196 tdb 1.26 "cpu", "kernel", NULL);
197 tdb 1.1 add_stat(LONG_LONG, &cpu_s->idle,
198 tdb 1.26 "cpu", "idle", NULL);
199 tdb 1.1 add_stat(LONG_LONG, &cpu_s->iowait,
200 tdb 1.26 "cpu", "iowait", NULL);
201 tdb 1.1 add_stat(LONG_LONG, &cpu_s->swap,
202 tdb 1.26 "cpu", "swap", NULL);
203 tdb 1.1 add_stat(LONG_LONG, &cpu_s->nice,
204 tdb 1.26 "cpu", "nice", NULL);
205 tdb 1.1 add_stat(LONG_LONG, &cpu_s->total,
206 tdb 1.26 "cpu", "total", NULL);
207 tdb 1.1 add_stat(TIME_T, &cpu_s->systime,
208 tdb 1.26 "cpu", "systime", NULL);
209 tdb 1.1 }
210     }
211 ats 1.8 }
212    
213     void populate_mem() {
214 ats 1.24 sg_mem_stats *mem = sg_get_mem_stats();
215 tdb 1.1
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 ats 1.8 }
223    
224     void populate_load() {
225 ats 1.24 sg_load_stats *load = sg_get_load_stats();
226 tdb 1.1
227     if (load != NULL) {
228     add_stat(DOUBLE, &load->min1, "load", "min1", NULL);
229     add_stat(DOUBLE, &load->min5, "load", "min5", NULL);
230     add_stat(DOUBLE, &load->min15, "load", "min15", NULL);
231     }
232 ats 1.8 }
233    
234     void populate_user() {
235 ats 1.24 sg_user_stats *user = sg_get_user_stats();
236 tdb 1.1
237     if (user != NULL) {
238     add_stat(INT, &user->num_entries, "user", "num", NULL);
239     add_stat(STRING, &user->name_list, "user", "names", NULL);
240     }
241 ats 1.8 }
242    
243     void populate_swap() {
244 ats 1.24 sg_swap_stats *swap = sg_get_swap_stats();
245 tdb 1.1
246     if (swap != NULL) {
247     add_stat(LONG_LONG, &swap->total, "swap", "total", NULL);
248     add_stat(LONG_LONG, &swap->used, "swap", "used", NULL);
249     add_stat(LONG_LONG, &swap->free, "swap", "free", NULL);
250     }
251 ats 1.8 }
252    
253     void populate_general() {
254 ats 1.24 /* FIXME this should be renamed to host. */
255     sg_host_info *host = sg_get_host_info();
256 tdb 1.1
257 ats 1.24 if (host != NULL) {
258     add_stat(STRING, &host->os_name,
259 tdb 1.26 "general", "os_name", NULL);
260 ats 1.24 add_stat(STRING, &host->os_release,
261 tdb 1.26 "general", "os_release", NULL);
262 ats 1.24 add_stat(STRING, &host->os_version,
263 tdb 1.26 "general", "os_version", NULL);
264 ats 1.24 add_stat(STRING, &host->platform, "general", "platform", NULL);
265     add_stat(STRING, &host->hostname, "general", "hostname", NULL);
266     add_stat(TIME_T, &host->uptime, "general", "uptime", NULL);
267 tdb 1.1 }
268 ats 1.8 }
269    
270     void populate_fs() {
271     int n, i;
272 ats 1.24 sg_fs_stats *disk = sg_get_fs_stats(&n);
273 tdb 1.1
274     if (disk != NULL) {
275     for (i = 0; i < n; i++) {
276     /* FIXME it'd be nicer if libstatgrab did this */
277 ats 1.10 char *buf, *name, *p;
278     const char *device = disk[i].device_name;
279    
280     if (strcmp(device, "/") == 0)
281     device = "root";
282    
283     buf = strdup(device);
284     if (buf == NULL)
285     die("out of memory");
286    
287     name = buf;
288 ats 1.13 if (strlen(name) == 2 && name[1] == ':')
289     name[1] = '\0';
290 ats 1.10 if (strncmp(name, "/dev/", 5) == 0)
291     name += 5;
292     while ((p = strchr(name, '/')) != NULL)
293     *p = '_';
294    
295 tdb 1.1 add_stat(STRING, &disk[i].device_name,
296 tdb 1.26 "fs", name, "device_name", NULL);
297 tdb 1.1 add_stat(STRING, &disk[i].fs_type,
298 tdb 1.26 "fs", name, "fs_type", NULL);
299 tdb 1.1 add_stat(STRING, &disk[i].mnt_point,
300 tdb 1.26 "fs", name, "mnt_point", NULL);
301 tdb 1.1 add_stat(LONG_LONG, &disk[i].size,
302 tdb 1.26 "fs", name, "size", NULL);
303 tdb 1.1 add_stat(LONG_LONG, &disk[i].used,
304 tdb 1.26 "fs", name, "used", NULL);
305 tdb 1.1 add_stat(LONG_LONG, &disk[i].avail,
306 tdb 1.26 "fs", name, "avail", NULL);
307 tdb 1.1 add_stat(LONG_LONG, &disk[i].total_inodes,
308 tdb 1.26 "fs", name, "total_inodes", NULL);
309 tdb 1.1 add_stat(LONG_LONG, &disk[i].used_inodes,
310 tdb 1.26 "fs", name, "used_inodes", NULL);
311 tdb 1.1 add_stat(LONG_LONG, &disk[i].free_inodes,
312 tdb 1.26 "fs", name, "free_inodes", NULL);
313 ats 1.10
314     free(buf);
315 tdb 1.1 }
316     }
317 ats 1.8 }
318    
319     void populate_disk() {
320     int n, i;
321 ats 1.24 sg_disk_io_stats *diskio;
322 tdb 1.1
323 ats 1.24 diskio = use_diffs ? sg_get_disk_io_stats_diff(&n)
324 tdb 1.26 : sg_get_disk_io_stats(&n);
325 tdb 1.1 if (diskio != NULL) {
326     for (i = 0; i < n; i++) {
327     const char *name = diskio[i].disk_name;
328    
329     add_stat(STRING, &diskio[i].disk_name,
330 tdb 1.26 "disk", name, "disk_name", NULL);
331 tdb 1.1 add_stat(LONG_LONG, &diskio[i].read_bytes,
332 tdb 1.26 "disk", name, "read_bytes", NULL);
333 tdb 1.1 add_stat(LONG_LONG, &diskio[i].write_bytes,
334 tdb 1.26 "disk", name, "write_bytes", NULL);
335 tdb 1.1 add_stat(TIME_T, &diskio[i].systime,
336 tdb 1.26 "disk", name, "systime", NULL);
337 tdb 1.1 }
338     }
339 ats 1.8 }
340    
341     void populate_proc() {
342 ats 1.24 /* FIXME expose individual process info too */
343     sg_process_count *proc = sg_get_process_count();
344 tdb 1.1
345     if (proc != NULL) {
346     add_stat(INT, &proc->total, "proc", "total", NULL);
347     add_stat(INT, &proc->running, "proc", "running", NULL);
348     add_stat(INT, &proc->sleeping, "proc", "sleeping", NULL);
349     add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
350     add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
351     }
352 ats 1.8 }
353    
354     void populate_net() {
355 ats 1.27 int num_io, num_iface, i;
356 ats 1.24 sg_network_io_stats *io;
357     sg_network_iface_stats *iface;
358 tdb 1.1
359 ats 1.27 io = use_diffs ? sg_get_network_io_stats_diff(&num_io)
360     : sg_get_network_io_stats(&num_io);
361 ats 1.24 if (io != NULL) {
362 ats 1.27 for (i = 0; i < num_io; i++) {
363 ats 1.24 const char *name = io[i].interface_name;
364 tdb 1.1
365 ats 1.24 add_stat(STRING, &io[i].interface_name,
366 tdb 1.26 "net", name, "interface_name", NULL);
367 ats 1.24 add_stat(LONG_LONG, &io[i].tx,
368 tdb 1.26 "net", name, "tx", NULL);
369 ats 1.24 add_stat(LONG_LONG, &io[i].rx,
370 tdb 1.26 "net", name, "rx", NULL);
371 ats 1.24 add_stat(LONG_LONG, &io[i].ipackets,
372 tdb 1.26 "net", name, "ipackets", NULL);
373 ats 1.24 add_stat(LONG_LONG, &io[i].opackets,
374 tdb 1.26 "net", name, "opackets", NULL);
375 ats 1.24 add_stat(LONG_LONG, &io[i].ierrors,
376 tdb 1.26 "net", name, "ierrors", NULL);
377 ats 1.24 add_stat(LONG_LONG, &io[i].oerrors,
378 tdb 1.26 "net", name, "oerrors", NULL);
379 ats 1.24 add_stat(LONG_LONG, &io[i].collisions,
380 tdb 1.26 "net", name, "collisions", NULL);
381 ats 1.24 add_stat(TIME_T, &io[i].systime,
382 tdb 1.26 "net", name, "systime", NULL);
383 tdb 1.1 }
384     }
385 ats 1.18
386 ats 1.27 iface = sg_get_network_iface_stats(&num_iface);
387 ats 1.18 if (iface != NULL) {
388 ats 1.27 for (i = 0; i < num_iface; i++) {
389 ats 1.18 const char *name = iface[i].interface_name;
390 ats 1.27 int had_io = 0, j;
391    
392     /* If there wasn't a corresponding io stat,
393     add interface_name from here. */
394     if (io != NULL) {
395     for (j = 0; j < num_io; j++) {
396     if (strcmp(io[j].interface_name,
397     name) == 0) {
398     had_io = 1;
399     break;
400     }
401     }
402     }
403     if (!had_io) {
404     add_stat(STRING, &iface[i].interface_name,
405     "net", name, "interface_name", NULL);
406     }
407 ats 1.18
408     add_stat(INT, &iface[i].speed,
409 tdb 1.26 "net", name, "speed", NULL);
410 ats 1.20 add_stat(BOOL, &iface[i].up,
411 tdb 1.26 "net", name, "up", NULL);
412 ats 1.18 add_stat(DUPLEX, &iface[i].dup,
413 tdb 1.26 "net", name, "duplex", NULL);
414 ats 1.18 }
415     }
416 ats 1.8 }
417    
418     void populate_page() {
419 ats 1.24 sg_page_stats *page;
420 tdb 1.1
421 ats 1.24 page = use_diffs ? sg_get_page_stats_diff() : sg_get_page_stats();
422 tdb 1.1 if (page != NULL) {
423     add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
424     add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
425 ats 1.11 add_stat(TIME_T, &page->systime, "page", "systime", NULL);
426 tdb 1.1 }
427 ats 1.8 }
428    
429     typedef struct {
430     const char *name;
431     void (*populate)();
432     int interesting;
433     } toplevel;
434     toplevel toplevels[] = {
435     {"const.", populate_const, 0},
436     {"cpu.", populate_cpu, 0},
437     {"mem.", populate_mem, 0},
438     {"load.", populate_load, 0},
439     {"user.", populate_user, 0},
440     {"swap.", populate_swap, 0},
441     {"general.", populate_general, 0},
442     {"fs.", populate_fs, 0},
443     {"disk.", populate_disk, 0},
444     {"proc.", populate_proc, 0},
445     {"net.", populate_net, 0},
446     {"page.", populate_page, 0},
447     {NULL, NULL, 0}
448     };
449    
450     /* Set the "interesting" flag on the sections that we actually need to
451     fetch. */
452     void select_interesting(int argc, char **argv) {
453     toplevel *t;
454    
455     if (argc == 0) {
456     for (t = &toplevels[0]; t->name != NULL; t++)
457     t->interesting = 1;
458     } else {
459     int i;
460    
461     for (i = 0; i < argc; i++) {
462     for (t = &toplevels[0]; t->name != NULL; t++) {
463     if (strncmp(argv[i], t->name,
464 tdb 1.26 strlen(t->name)) == 0) {
465 ats 1.8 t->interesting = 1;
466     break;
467     }
468     }
469     }
470     }
471     }
472    
473     /* Clear and rebuild the stats array. */
474     void get_stats() {
475     toplevel *t;
476    
477     clear_stats();
478    
479     for (t = &toplevels[0]; t->name != NULL; t++) {
480     if (t->interesting)
481     t->populate();
482     }
483 tdb 1.1
484 ats 1.21 if (stats != NULL)
485     qsort(stats, num_stats, sizeof *stats, stats_compare);
486 tdb 1.1 }
487    
488     /* Print the value of a stat. */
489     void print_stat_value(const stat *s) {
490     void *v = s->stat;
491 ats 1.23 long l;
492 tdb 1.1
493     switch (s->type) {
494     case LONG_LONG:
495     printf("%lld", *(long long *)v);
496     break;
497     case TIME_T:
498     /* FIXME option for formatted time? */
499 ats 1.23 l = *(time_t *)v;
500     printf("%ld", l);
501 tdb 1.1 break;
502     case FLOAT:
503     printf("%f", *(float *)v);
504     break;
505     case DOUBLE:
506     printf("%f", *(double *)v);
507     break;
508     case STRING:
509     /* FIXME escaping? */
510     printf("%s", *(char **)v);
511     break;
512     case INT:
513     printf("%d", *(int *)v);
514 ats 1.20 break;
515     case BOOL:
516     printf("%s", *(int *)v ? "true" : "false");
517 ats 1.18 break;
518     case DUPLEX:
519 ats 1.24 switch (*(sg_iface_duplex *) v) {
520     case SG_IFACE_DUPLEX_FULL:
521 ats 1.18 printf("full");
522     break;
523 ats 1.24 case SG_IFACE_DUPLEX_HALF:
524 ats 1.18 printf("half");
525     break;
526     default:
527     printf("unknown");
528     break;
529     }
530 tdb 1.1 break;
531     }
532     }
533    
534     /* Print the name and value of a stat. */
535     void print_stat(const stat *s) {
536     switch (display_mode) {
537     case DISPLAY_LINUX:
538     printf("%s = ", s->name);
539     break;
540     case DISPLAY_BSD:
541     printf("%s: ", s->name);
542     break;
543     case DISPLAY_MRTG:
544     case DISPLAY_PLAIN:
545     break;
546     }
547     print_stat_value(s);
548     printf("\n");
549     }
550    
551     /* Print stats as specified on the provided command line. */
552     void print_stats(int argc, char **argv) {
553     int i;
554    
555     if (argc == optind) {
556     /* Print all stats. */
557     for (i = 0; i < num_stats; i++)
558     print_stat(&stats[i]);
559     } else {
560     /* Print selected stats. */
561     for (i = optind; i < argc; i++) {
562 ats 1.9 char *name = argv[i];
563 tdb 1.1 stat key;
564 ats 1.9 const stat *s, *end;
565     int (*compare)(const void *, const void *);
566    
567     key.name = name;
568     if (name[strlen(name) - 1] == '.')
569     compare = stats_compare_prefix;
570     else
571     compare = stats_compare;
572 tdb 1.1
573 ats 1.21 if (stats == NULL) {
574     s = NULL;
575     } else {
576     s = (const stat *)bsearch(&key, stats,
577 tdb 1.26 num_stats,
578     sizeof *stats,
579     compare);
580 ats 1.21 }
581    
582 ats 1.9 if (s == NULL) {
583     printf("Unknown stat %s\n", name);
584     continue;
585     }
586    
587     /* Find the range of stats the user wanted. */
588     for (; s >= stats; s--) {
589     if (compare(&key, s) != 0)
590     break;
591     }
592     s++;
593     for (end = s; end < &stats[num_stats]; end++) {
594     if (compare(&key, end) != 0)
595     break;
596     }
597    
598     /* And print them. */
599     for (; s < end; s++) {
600 tdb 1.1 print_stat(s);
601     }
602     }
603     }
604     }
605    
606     void usage() {
607     printf("Usage: statgrab [OPTION]... [STAT]...\n"
608 ats 1.9 "Display system statistics.\n"
609     "\n"
610     "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n"
611     "statistics starting with that prefix.\n"
612 tdb 1.1 "\n");
613 tdb 1.26 printf(" -l Linux sysctl-style output (default)\n"
614     " -b BSD sysctl-style output\n"
615     " -m MRTG-compatible output\n"
616     " -u Plain output (only show values)\n"
617     " -n Display cumulative stats once (default)\n"
618     " -s Display stat differences repeatedly\n"
619     " -o Display stat differences once\n"
620 tdb 1.1 " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n"
621 tdb 1.26 " -p Display CPU usage differences as percentages rather than\n"
622     " absolute values\n"
623 tdb 1.1 "\n");
624 tdb 1.2 printf("Version %s - report bugs to <%s>.\n",
625 ats 1.5 PACKAGE_VERSION, PACKAGE_BUGREPORT);
626 tdb 1.1 exit(1);
627     }
628    
629     int main(int argc, char **argv) {
630     opterr = 0;
631     while (1) {
632     int c = getopt(argc, argv, "lbmunsot:p");
633     if (c == -1)
634     break;
635     switch (c) {
636     case 'l':
637     display_mode = DISPLAY_LINUX;
638     break;
639     case 'b':
640     display_mode = DISPLAY_BSD;
641     break;
642     case 'm':
643     display_mode = DISPLAY_MRTG;
644     break;
645     case 'u':
646     display_mode = DISPLAY_PLAIN;
647     break;
648     case 'n':
649     repeat_mode = REPEAT_NONE;
650     break;
651     case 's':
652     repeat_mode = REPEAT_FOREVER;
653     break;
654     case 'o':
655     repeat_mode = REPEAT_ONCE;
656     break;
657     case 't':
658     repeat_time = atoi(optarg);
659     break;
660     case 'p':
661     use_cpu_percent = 1;
662     break;
663     default:
664     usage();
665     }
666     }
667    
668     if (display_mode == DISPLAY_MRTG) {
669     if ((argc - optind) != 2)
670     die("mrtg mode: must specify exactly two stats");
671 ats 1.5 if (repeat_mode == REPEAT_FOREVER)
672 tdb 1.1 die("mrtg mode: cannot repeat display");
673     }
674 ats 1.5
675     if (use_cpu_percent && repeat_mode == REPEAT_NONE)
676     die("CPU percentage usage display requires stat differences");
677 tdb 1.1
678 ats 1.8 if (repeat_mode == REPEAT_NONE)
679     use_diffs = 0;
680     else
681     use_diffs = 1;
682    
683     select_interesting(argc - optind, &argv[optind]);
684    
685 ats 1.12 /* We don't care if statgrab_init fails, because we can just display
686     the statistics that can be read as non-root. */
687 ats 1.24 sg_init();
688     if (sg_drop_privileges() != 0)
689 ats 1.15 die("Failed to drop setuid/setgid privileges");
690 ats 1.12
691 tdb 1.1 switch (repeat_mode) {
692     case REPEAT_NONE:
693 ats 1.8 get_stats();
694 tdb 1.1 print_stats(argc, argv);
695     break;
696     case REPEAT_ONCE:
697 ats 1.8 get_stats();
698 tdb 1.1 sleep(repeat_time);
699 ats 1.8 get_stats();
700 tdb 1.1 print_stats(argc, argv);
701     break;
702     case REPEAT_FOREVER:
703     while (1) {
704 ats 1.8 get_stats();
705 tdb 1.1 print_stats(argc, argv);
706     printf("\n");
707     sleep(repeat_time);
708     }
709     }
710    
711     if (display_mode == DISPLAY_MRTG) {
712     printf("\n");
713     printf("statgrab\n");
714     }
715    
716     return 0;
717     }
718