ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.24
Committed: Mon Apr 5 15:40:17 2004 UTC (20 years, 1 month ago) by ats
Content type: text/plain
Branch: MAIN
Changes since 1.23: +47 -42 lines
Log Message:
Rename all the functions, types and enums in the API to be consistent.
Types are now of the form "sg_mem_stats"; functions of the form
"sg_get_mem_stats"; enums of the form "SG_PROCESS_STATE_RUNNING".
(The old get_proc_snapshot follows the usual calling convention now.)

Make internal functions static where possible.

Rename non-static internal functions to have an sg_ prefix so they don't
collide with those from other libraries. In particular, strlcpy and
strlcat are now called sg_strlcpy and sg_strlcat and are always
included.

Fix saidar and statgrab to use the new API.

File Contents

# User Rev Content
1 tdb 1.1 /*
2     * i-scream central monitoring system
3     * 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.24 * $Id: statgrab.c,v 1.23 2004/04/04 21:59:16 ats 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     "cpu", "user", NULL);
174     add_stat(FLOAT, &cpu_p->kernel,
175     "cpu", "kernel", NULL);
176     add_stat(FLOAT, &cpu_p->idle,
177     "cpu", "idle", NULL);
178     add_stat(FLOAT, &cpu_p->iowait,
179     "cpu", "iowait", NULL);
180     add_stat(FLOAT, &cpu_p->swap,
181     "cpu", "swap", NULL);
182     add_stat(FLOAT, &cpu_p->nice,
183     "cpu", "nice", NULL);
184 ats 1.7 add_stat(TIME_T, &cpu_p->time_taken,
185 tdb 1.1 "cpu", "time_taken", NULL);
186     }
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     : sg_get_cpu_stats();
192 tdb 1.1 if (cpu_s != NULL) {
193     add_stat(LONG_LONG, &cpu_s->user,
194     "cpu", "user", NULL);
195     add_stat(LONG_LONG, &cpu_s->kernel,
196     "cpu", "kernel", NULL);
197     add_stat(LONG_LONG, &cpu_s->idle,
198     "cpu", "idle", NULL);
199     add_stat(LONG_LONG, &cpu_s->iowait,
200     "cpu", "iowait", NULL);
201     add_stat(LONG_LONG, &cpu_s->swap,
202     "cpu", "swap", NULL);
203     add_stat(LONG_LONG, &cpu_s->nice,
204     "cpu", "nice", NULL);
205     add_stat(LONG_LONG, &cpu_s->total,
206     "cpu", "total", NULL);
207     add_stat(TIME_T, &cpu_s->systime,
208     "cpu", "systime", NULL);
209     }
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.1 "general", "os_name", NULL);
260 ats 1.24 add_stat(STRING, &host->os_release,
261 tdb 1.1 "general", "os_release", NULL);
262 ats 1.24 add_stat(STRING, &host->os_version,
263 tdb 1.1 "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     "fs", name, "device_name", NULL);
297     add_stat(STRING, &disk[i].fs_type,
298     "fs", name, "fs_type", NULL);
299     add_stat(STRING, &disk[i].mnt_point,
300     "fs", name, "mnt_point", NULL);
301     add_stat(LONG_LONG, &disk[i].size,
302     "fs", name, "size", NULL);
303     add_stat(LONG_LONG, &disk[i].used,
304     "fs", name, "used", NULL);
305     add_stat(LONG_LONG, &disk[i].avail,
306     "fs", name, "avail", NULL);
307     add_stat(LONG_LONG, &disk[i].total_inodes,
308     "fs", name, "total_inodes", NULL);
309     add_stat(LONG_LONG, &disk[i].used_inodes,
310     "fs", name, "used_inodes", NULL);
311     add_stat(LONG_LONG, &disk[i].free_inodes,
312     "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     : 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     "disk", name, "disk_name", NULL);
331     add_stat(LONG_LONG, &diskio[i].read_bytes,
332     "disk", name, "read_bytes", NULL);
333     add_stat(LONG_LONG, &diskio[i].write_bytes,
334     "disk", name, "write_bytes", NULL);
335     add_stat(TIME_T, &diskio[i].systime,
336     "disk", name, "systime", NULL);
337     }
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     : sg_get_network_io_stats(&n);
361     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.1 "net", name, "interface_name", NULL);
367 ats 1.24 add_stat(LONG_LONG, &io[i].tx,
368 tdb 1.1 "net", name, "tx", NULL);
369 ats 1.24 add_stat(LONG_LONG, &io[i].rx,
370 tdb 1.1 "net", name, "rx", NULL);
371 ats 1.24 add_stat(LONG_LONG, &io[i].ipackets,
372 ats 1.22 "net", name, "ipackets", NULL);
373 ats 1.24 add_stat(LONG_LONG, &io[i].opackets,
374 ats 1.22 "net", name, "opackets", NULL);
375 ats 1.24 add_stat(LONG_LONG, &io[i].ierrors,
376 ats 1.22 "net", name, "ierrors", NULL);
377 ats 1.24 add_stat(LONG_LONG, &io[i].oerrors,
378 ats 1.22 "net", name, "oerrors", NULL);
379 ats 1.24 add_stat(LONG_LONG, &io[i].collisions,
380 ats 1.22 "net", name, "collisions", NULL);
381 ats 1.24 add_stat(TIME_T, &io[i].systime,
382 tdb 1.1 "net", name, "systime", NULL);
383     }
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     "net", name, "speed", NULL);
393 ats 1.20 add_stat(BOOL, &iface[i].up,
394     "net", name, "up", NULL);
395 ats 1.18 add_stat(DUPLEX, &iface[i].dup,
396     "net", name, "duplex", NULL);
397     }
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     strlen(t->name)) == 0) {
448     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     num_stats,
561     sizeof *stats,
562     compare);
563     }
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     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     " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n"
604 ats 1.5 " -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