ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.29
Committed: Tue Aug 10 18:50:37 2004 UTC (19 years, 9 months ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.28: +18 -5 lines
Log Message:
Add -f option to scale floating-point values to integers for MRTG
output.

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