ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.26
Committed: Wed Apr 7 15:50:26 2004 UTC (20 years, 8 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_10
Changes since 1.25: +60 -60 lines
Log Message:
More whitespace tidyup (spaces->tabs).

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 tdb 1.26 * $Id: statgrab.c,v 1.25 2004/04/06 14:53:00 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     int n, i;
356 ats 1.24 sg_network_io_stats *io;
357     sg_network_iface_stats *iface;
358 tdb 1.1
359 ats 1.24 io = use_diffs ? sg_get_network_io_stats_diff(&n)
360 tdb 1.26 : sg_get_network_io_stats(&n);
361 ats 1.24 if (io != NULL) {
362 tdb 1.1 for (i = 0; i < n; 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.24 iface = sg_get_network_iface_stats(&n);
387 ats 1.18 if (iface != NULL) {
388     for (i = 0; i < n; i++) {
389     const char *name = iface[i].interface_name;
390    
391     add_stat(INT, &iface[i].speed,
392 tdb 1.26 "net", name, "speed", NULL);
393 ats 1.20 add_stat(BOOL, &iface[i].up,
394 tdb 1.26 "net", name, "up", NULL);
395 ats 1.18 add_stat(DUPLEX, &iface[i].dup,
396 tdb 1.26 "net", name, "duplex", NULL);
397 ats 1.18 }
398     }
399 ats 1.8 }
400    
401     void populate_page() {
402 ats 1.24 sg_page_stats *page;
403 tdb 1.1
404 ats 1.24 page = use_diffs ? sg_get_page_stats_diff() : sg_get_page_stats();
405 tdb 1.1 if (page != NULL) {
406     add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
407     add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
408 ats 1.11 add_stat(TIME_T, &page->systime, "page", "systime", NULL);
409 tdb 1.1 }
410 ats 1.8 }
411    
412     typedef struct {
413     const char *name;
414     void (*populate)();
415     int interesting;
416     } toplevel;
417     toplevel toplevels[] = {
418     {"const.", populate_const, 0},
419     {"cpu.", populate_cpu, 0},
420     {"mem.", populate_mem, 0},
421     {"load.", populate_load, 0},
422     {"user.", populate_user, 0},
423     {"swap.", populate_swap, 0},
424     {"general.", populate_general, 0},
425     {"fs.", populate_fs, 0},
426     {"disk.", populate_disk, 0},
427     {"proc.", populate_proc, 0},
428     {"net.", populate_net, 0},
429     {"page.", populate_page, 0},
430     {NULL, NULL, 0}
431     };
432    
433     /* Set the "interesting" flag on the sections that we actually need to
434     fetch. */
435     void select_interesting(int argc, char **argv) {
436     toplevel *t;
437    
438     if (argc == 0) {
439     for (t = &toplevels[0]; t->name != NULL; t++)
440     t->interesting = 1;
441     } else {
442     int i;
443    
444     for (i = 0; i < argc; i++) {
445     for (t = &toplevels[0]; t->name != NULL; t++) {
446     if (strncmp(argv[i], t->name,
447 tdb 1.26 strlen(t->name)) == 0) {
448 ats 1.8 t->interesting = 1;
449     break;
450     }
451     }
452     }
453     }
454     }
455    
456     /* Clear and rebuild the stats array. */
457     void get_stats() {
458     toplevel *t;
459    
460     clear_stats();
461    
462     for (t = &toplevels[0]; t->name != NULL; t++) {
463     if (t->interesting)
464     t->populate();
465     }
466 tdb 1.1
467 ats 1.21 if (stats != NULL)
468     qsort(stats, num_stats, sizeof *stats, stats_compare);
469 tdb 1.1 }
470    
471     /* Print the value of a stat. */
472     void print_stat_value(const stat *s) {
473     void *v = s->stat;
474 ats 1.23 long l;
475 tdb 1.1
476     switch (s->type) {
477     case LONG_LONG:
478     printf("%lld", *(long long *)v);
479     break;
480     case TIME_T:
481     /* FIXME option for formatted time? */
482 ats 1.23 l = *(time_t *)v;
483     printf("%ld", l);
484 tdb 1.1 break;
485     case FLOAT:
486     printf("%f", *(float *)v);
487     break;
488     case DOUBLE:
489     printf("%f", *(double *)v);
490     break;
491     case STRING:
492     /* FIXME escaping? */
493     printf("%s", *(char **)v);
494     break;
495     case INT:
496     printf("%d", *(int *)v);
497 ats 1.20 break;
498     case BOOL:
499     printf("%s", *(int *)v ? "true" : "false");
500 ats 1.18 break;
501     case DUPLEX:
502 ats 1.24 switch (*(sg_iface_duplex *) v) {
503     case SG_IFACE_DUPLEX_FULL:
504 ats 1.18 printf("full");
505     break;
506 ats 1.24 case SG_IFACE_DUPLEX_HALF:
507 ats 1.18 printf("half");
508     break;
509     default:
510     printf("unknown");
511     break;
512     }
513 tdb 1.1 break;
514     }
515     }
516    
517     /* Print the name and value of a stat. */
518     void print_stat(const stat *s) {
519     switch (display_mode) {
520     case DISPLAY_LINUX:
521     printf("%s = ", s->name);
522     break;
523     case DISPLAY_BSD:
524     printf("%s: ", s->name);
525     break;
526     case DISPLAY_MRTG:
527     case DISPLAY_PLAIN:
528     break;
529     }
530     print_stat_value(s);
531     printf("\n");
532     }
533    
534     /* Print stats as specified on the provided command line. */
535     void print_stats(int argc, char **argv) {
536     int i;
537    
538     if (argc == optind) {
539     /* Print all stats. */
540     for (i = 0; i < num_stats; i++)
541     print_stat(&stats[i]);
542     } else {
543     /* Print selected stats. */
544     for (i = optind; i < argc; i++) {
545 ats 1.9 char *name = argv[i];
546 tdb 1.1 stat key;
547 ats 1.9 const stat *s, *end;
548     int (*compare)(const void *, const void *);
549    
550     key.name = name;
551     if (name[strlen(name) - 1] == '.')
552     compare = stats_compare_prefix;
553     else
554     compare = stats_compare;
555 tdb 1.1
556 ats 1.21 if (stats == NULL) {
557     s = NULL;
558     } else {
559     s = (const stat *)bsearch(&key, stats,
560 tdb 1.26 num_stats,
561     sizeof *stats,
562     compare);
563 ats 1.21 }
564    
565 ats 1.9 if (s == NULL) {
566     printf("Unknown stat %s\n", name);
567     continue;
568     }
569    
570     /* Find the range of stats the user wanted. */
571     for (; s >= stats; s--) {
572     if (compare(&key, s) != 0)
573     break;
574     }
575     s++;
576     for (end = s; end < &stats[num_stats]; end++) {
577     if (compare(&key, end) != 0)
578     break;
579     }
580    
581     /* And print them. */
582     for (; s < end; s++) {
583 tdb 1.1 print_stat(s);
584     }
585     }
586     }
587     }
588    
589     void usage() {
590     printf("Usage: statgrab [OPTION]... [STAT]...\n"
591 ats 1.9 "Display system statistics.\n"
592     "\n"
593     "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n"
594     "statistics starting with that prefix.\n"
595 tdb 1.1 "\n");
596 tdb 1.26 printf(" -l Linux sysctl-style output (default)\n"
597     " -b BSD sysctl-style output\n"
598     " -m MRTG-compatible output\n"
599     " -u Plain output (only show values)\n"
600     " -n Display cumulative stats once (default)\n"
601     " -s Display stat differences repeatedly\n"
602     " -o Display stat differences once\n"
603 tdb 1.1 " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n"
604 tdb 1.26 " -p Display CPU usage differences as percentages rather than\n"
605     " absolute values\n"
606 tdb 1.1 "\n");
607 tdb 1.2 printf("Version %s - report bugs to <%s>.\n",
608 ats 1.5 PACKAGE_VERSION, PACKAGE_BUGREPORT);
609 tdb 1.1 exit(1);
610     }
611    
612     int main(int argc, char **argv) {
613     opterr = 0;
614     while (1) {
615     int c = getopt(argc, argv, "lbmunsot:p");
616     if (c == -1)
617     break;
618     switch (c) {
619     case 'l':
620     display_mode = DISPLAY_LINUX;
621     break;
622     case 'b':
623     display_mode = DISPLAY_BSD;
624     break;
625     case 'm':
626     display_mode = DISPLAY_MRTG;
627     break;
628     case 'u':
629     display_mode = DISPLAY_PLAIN;
630     break;
631     case 'n':
632     repeat_mode = REPEAT_NONE;
633     break;
634     case 's':
635     repeat_mode = REPEAT_FOREVER;
636     break;
637     case 'o':
638     repeat_mode = REPEAT_ONCE;
639     break;
640     case 't':
641     repeat_time = atoi(optarg);
642     break;
643     case 'p':
644     use_cpu_percent = 1;
645     break;
646     default:
647     usage();
648     }
649     }
650    
651     if (display_mode == DISPLAY_MRTG) {
652     if ((argc - optind) != 2)
653     die("mrtg mode: must specify exactly two stats");
654 ats 1.5 if (repeat_mode == REPEAT_FOREVER)
655 tdb 1.1 die("mrtg mode: cannot repeat display");
656     }
657 ats 1.5
658     if (use_cpu_percent && repeat_mode == REPEAT_NONE)
659     die("CPU percentage usage display requires stat differences");
660 tdb 1.1
661 ats 1.8 if (repeat_mode == REPEAT_NONE)
662     use_diffs = 0;
663     else
664     use_diffs = 1;
665    
666     select_interesting(argc - optind, &argv[optind]);
667    
668 ats 1.12 /* We don't care if statgrab_init fails, because we can just display
669     the statistics that can be read as non-root. */
670 ats 1.24 sg_init();
671     if (sg_drop_privileges() != 0)
672 ats 1.15 die("Failed to drop setuid/setgid privileges");
673 ats 1.12
674 tdb 1.1 switch (repeat_mode) {
675     case REPEAT_NONE:
676 ats 1.8 get_stats();
677 tdb 1.1 print_stats(argc, argv);
678     break;
679     case REPEAT_ONCE:
680 ats 1.8 get_stats();
681 tdb 1.1 sleep(repeat_time);
682 ats 1.8 get_stats();
683 tdb 1.1 print_stats(argc, argv);
684     break;
685     case REPEAT_FOREVER:
686     while (1) {
687 ats 1.8 get_stats();
688 tdb 1.1 print_stats(argc, argv);
689     printf("\n");
690     sleep(repeat_time);
691     }
692     }
693    
694     if (display_mode == DISPLAY_MRTG) {
695     printf("\n");
696     printf("statgrab\n");
697     }
698    
699     return 0;
700     }
701