ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
(Generate patch)

Comparing projects/libstatgrab/src/statgrab/statgrab.c (file contents):
Revision 1.2 by tdb, Wed Aug 27 14:00:12 2003 UTC vs.
Revision 1.29 by ats, Tue Aug 10 18:50:37 2004 UTC

# Line 1 | Line 1
1   /*
2 < * i-scream central monitoring system
2 > * i-scream libstatgrab
3   * http://www.i-scream.org
4 < * Copyright (C) 2000-2003 i-scream
4 > * Copyright (C) 2000-2004 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
# Line 16 | Line 16
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 + * $Id$
21   */
22  
23 + #ifdef HAVE_CONFIG_H
24 + #include "config.h"
25 + #endif
26 +
27   #include <statgrab.h>
28   #include <string.h>
29   #include <stdio.h>
# Line 31 | Line 37 | typedef enum {
37          FLOAT,
38          DOUBLE,
39          STRING,
40 <        INT
40 >        INT,
41 >        BOOL,
42 >        DUPLEX
43   } stat_type;
44  
45   typedef enum {
# Line 62 | Line 70 | 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 + int use_diffs = 0;
74 + long float_scale_factor = 0;
75  
76   /* Exit with an error message. */
77   void die(const char *s) {
# Line 75 | Line 85 | void clear_stats() {
85  
86          for (i = 0; i < num_stats; i++)
87                  free(stats[i].name);
78        free(stats);
79        stats = NULL;
88          num_stats = 0;
81        alloc_stats = 0;
89   }
90  
91   /* Add a stat. The varargs make up the name, joined with dots; the name is
# Line 138 | Line 145 | void add_stat(stat_type type, void *stat, ...) {
145          ++num_stats;
146   }
147  
148 < /* Compare two stats by name, for sorting purposes. */
148 > /* Compare two stats by name for qsort and bsearch. */
149   int stats_compare(const void *a, const void *b) {
150          return strcmp(((stat *)a)->name, ((stat *)b)->name);
151   }
152  
153 < /* Clear and rebuild the stats array. */
154 < void get_stats(int use_diffs) {
155 <        cpu_states_t *cpu_s;
156 <        cpu_percent_t *cpu_p;
150 <        mem_stat_t *mem;
151 <        load_stat_t *load;
152 <        user_stat_t *user;
153 <        swap_stat_t *swap;
154 <        general_stat_t *gen;
155 <        disk_stat_t *disk;
156 <        diskio_stat_t *diskio;
157 <        process_stat_t *proc;
158 <        network_stat_t *net;
159 <        page_stat_t *page;
160 <        static int zero = 0;
161 <        int n, i;
153 > /* 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 <        clear_stats();
158 >        return strncmp(kn, in, strlen(kn));
159 > }
160  
161 + void populate_const() {
162 +        static int zero = 0;
163 +
164          /* Constants, for use with MRTG mode. */
165          add_stat(INT, &zero, "const", "0", NULL);
166 + }
167  
168 <        /* FIXME when only fetching some stats, it'd be more efficient to only
169 <           do the libstatgrab calls needed, rather than fetching everything. */
170 <
168 > void populate_cpu() {
169          if (use_cpu_percent) {
170 <                cpu_p = cpu_percent_usage();
170 >                sg_cpu_percents *cpu_p = sg_get_cpu_percents();
171 >
172                  if (cpu_p != NULL) {
173                          add_stat(FLOAT, &cpu_p->user,
174 <                                 "cpu", "user", NULL);
174 >                                 "cpu", "user", NULL);
175                          add_stat(FLOAT, &cpu_p->kernel,
176 <                                 "cpu", "kernel", NULL);
176 >                                 "cpu", "kernel", NULL);
177                          add_stat(FLOAT, &cpu_p->idle,
178 <                                 "cpu", "idle", NULL);
178 >                                 "cpu", "idle", NULL);
179                          add_stat(FLOAT, &cpu_p->iowait,
180 <                                 "cpu", "iowait", NULL);
180 >                                 "cpu", "iowait", NULL);
181                          add_stat(FLOAT, &cpu_p->swap,
182 <                                 "cpu", "swap", NULL);
182 >                                 "cpu", "swap", NULL);
183                          add_stat(FLOAT, &cpu_p->nice,
184 <                                 "cpu", "nice", NULL);
185 <                        add_stat(TIME_T, &cpu_s->systime,
186 <                                 "cpu", "time_taken", NULL);
184 >                                 "cpu", "nice", NULL);
185 >                        add_stat(TIME_T, &cpu_p->time_taken,
186 >                                 "cpu", "time_taken", NULL);
187                  }
188          } else {
189 <                cpu_s = use_diffs ? get_cpu_diff() : get_cpu_totals();
189 >                sg_cpu_stats *cpu_s;
190 >
191 >                cpu_s = use_diffs ? sg_get_cpu_stats_diff()
192 >                                  : sg_get_cpu_stats();
193                  if (cpu_s != NULL) {
194                          add_stat(LONG_LONG, &cpu_s->user,
195 <                                 "cpu", "user", NULL);
195 >                                 "cpu", "user", NULL);
196                          add_stat(LONG_LONG, &cpu_s->kernel,
197 <                                 "cpu", "kernel", NULL);
197 >                                 "cpu", "kernel", NULL);
198                          add_stat(LONG_LONG, &cpu_s->idle,
199 <                                 "cpu", "idle", NULL);
199 >                                 "cpu", "idle", NULL);
200                          add_stat(LONG_LONG, &cpu_s->iowait,
201 <                                 "cpu", "iowait", NULL);
201 >                                 "cpu", "iowait", NULL);
202                          add_stat(LONG_LONG, &cpu_s->swap,
203 <                                 "cpu", "swap", NULL);
203 >                                 "cpu", "swap", NULL);
204                          add_stat(LONG_LONG, &cpu_s->nice,
205 <                                 "cpu", "nice", NULL);
205 >                                 "cpu", "nice", NULL);
206                          add_stat(LONG_LONG, &cpu_s->total,
207 <                                 "cpu", "total", NULL);
207 >                                 "cpu", "total", NULL);
208                          add_stat(TIME_T, &cpu_s->systime,
209 <                                 "cpu", "systime", NULL);
209 >                                 "cpu", "systime", NULL);
210                  }
211          }
212 + }
213  
214 <        mem = get_memory_stats();
214 > void populate_mem() {
215 >        sg_mem_stats *mem = sg_get_mem_stats();
216 >
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 + }
224  
225 <        load = get_load_stats();
225 > void populate_load() {
226 >        sg_load_stats *load = sg_get_load_stats();
227 >
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 + }
234  
235 <        user = get_user_stats();
235 > void populate_user() {
236 >        sg_user_stats *user = sg_get_user_stats();
237 >
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 + }
243  
244 <        swap = get_swap_stats();
244 > void populate_swap() {
245 >        sg_swap_stats *swap = sg_get_swap_stats();
246 >
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 + }
253  
254 <        gen = get_general_stats();
255 <        if (gen != NULL) {
256 <                add_stat(STRING, &gen->os_name,
257 <                         "general", "os_name", NULL);
258 <                add_stat(STRING, &gen->os_release,
259 <                         "general", "os_release", NULL);
260 <                add_stat(STRING, &gen->os_version,
261 <                         "general", "os_version", NULL);
262 <                add_stat(STRING, &gen->platform, "general", "platform", NULL);
263 <                add_stat(STRING, &gen->hostname, "general", "hostname", NULL);
264 <                add_stat(TIME_T, &gen->uptime, "general", "uptime", NULL);
254 > void populate_general() {
255 >        /* FIXME this should be renamed to host. */
256 >        sg_host_info *host = sg_get_host_info();
257 >
258 >        if (host != NULL) {
259 >                add_stat(STRING, &host->os_name,
260 >                         "general", "os_name", NULL);
261 >                add_stat(STRING, &host->os_release,
262 >                         "general", "os_release", NULL);
263 >                add_stat(STRING, &host->os_version,
264 >                         "general", "os_version", NULL);
265 >                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          }
269 + }
270  
271 <        disk = get_disk_stats(&n);
271 > void populate_fs() {
272 >        int n, i;
273 >        sg_fs_stats *disk = sg_get_fs_stats(&n);
274 >
275          if (disk != NULL) {
276                  for (i = 0; i < n; i++) {
277                          /* FIXME it'd be nicer if libstatgrab did this */
278 <                        const char *name = disk[i].device_name,
279 <                                   *p = strrchr(name, '/');
280 <                        if (p != NULL)
281 <                                name = p + 1;
282 <                        if (*name == '\0')
283 <                                name = "root";
284 <        
278 >                        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 >                        if (strlen(name) == 2 && name[1] == ':')
290 >                                name[1] = '\0';
291 >                        if (strncmp(name, "/dev/", 5) == 0)
292 >                                name += 5;
293 >                        while ((p = strchr(name, '/')) != NULL)
294 >                                *p = '_';
295 >
296                          add_stat(STRING, &disk[i].device_name,
297 <                                 "fs", name, "device_name", NULL);
297 >                                 "fs", name, "device_name", NULL);
298                          add_stat(STRING, &disk[i].fs_type,
299 <                                 "fs", name, "fs_type", NULL);
299 >                                 "fs", name, "fs_type", NULL);
300                          add_stat(STRING, &disk[i].mnt_point,
301 <                                 "fs", name, "mnt_point", NULL);
301 >                                 "fs", name, "mnt_point", NULL);
302                          add_stat(LONG_LONG, &disk[i].size,
303 <                                 "fs", name, "size", NULL);
303 >                                 "fs", name, "size", NULL);
304                          add_stat(LONG_LONG, &disk[i].used,
305 <                                 "fs", name, "used", NULL);
305 >                                 "fs", name, "used", NULL);
306                          add_stat(LONG_LONG, &disk[i].avail,
307 <                                 "fs", name, "avail", NULL);
307 >                                 "fs", name, "avail", NULL);
308                          add_stat(LONG_LONG, &disk[i].total_inodes,
309 <                                 "fs", name, "total_inodes", NULL);
309 >                                 "fs", name, "total_inodes", NULL);
310                          add_stat(LONG_LONG, &disk[i].used_inodes,
311 <                                 "fs", name, "used_inodes", NULL);
311 >                                 "fs", name, "used_inodes", NULL);
312                          add_stat(LONG_LONG, &disk[i].free_inodes,
313 <                                 "fs", name, "free_inodes", NULL);
313 >                                 "fs", name, "free_inodes", NULL);
314 >
315 >                        free(buf);
316                  }
317          }
318 + }
319  
320 <        diskio = use_diffs ? get_diskio_stats_diff(&n) : get_diskio_stats(&n);
320 > void populate_disk() {
321 >        int n, i;
322 >        sg_disk_io_stats *diskio;
323 >
324 >        diskio = use_diffs ? sg_get_disk_io_stats_diff(&n)
325 >                           : sg_get_disk_io_stats(&n);
326          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 <                                 "disk", name, "disk_name", NULL);
331 >                                 "disk", name, "disk_name", NULL);
332                          add_stat(LONG_LONG, &diskio[i].read_bytes,
333 <                                 "disk", name, "read_bytes", NULL);
333 >                                 "disk", name, "read_bytes", NULL);
334                          add_stat(LONG_LONG, &diskio[i].write_bytes,
335 <                                 "disk", name, "write_bytes", NULL);
335 >                                 "disk", name, "write_bytes", NULL);
336                          add_stat(TIME_T, &diskio[i].systime,
337 <                                 "disk", name, "systime", NULL);
337 >                                 "disk", name, "systime", NULL);
338                  }
339          }
340 + }
341  
342 <        proc = get_process_stats();
342 > void populate_proc() {
343 >        /* FIXME expose individual process info too */
344 >        sg_process_count *proc = sg_get_process_count();
345 >
346          if (proc != NULL) {
347                  add_stat(INT, &proc->total, "proc", "total", NULL);
348                  add_stat(INT, &proc->running, "proc", "running", NULL);
# Line 305 | Line 350 | void get_stats(int use_diffs) {
350                  add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
351                  add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
352          }
353 + }
354  
355 <        net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n);
356 <        if (net != NULL) {
357 <                for (i = 0; i < n; i++) {
358 <                        const char *name = net[i].interface_name;
355 > void populate_net() {
356 >        int num_io, num_iface, i;
357 >        sg_network_io_stats *io;
358 >        sg_network_iface_stats *iface;
359 >
360 >        io = use_diffs ? sg_get_network_io_stats_diff(&num_io)
361 >                       : sg_get_network_io_stats(&num_io);
362 >        if (io != NULL) {
363 >                for (i = 0; i < num_io; i++) {
364 >                        const char *name = io[i].interface_name;
365          
366 <                        add_stat(STRING, &net[i].interface_name,
367 <                                 "net", name, "interface_name", NULL);
368 <                        add_stat(LONG_LONG, &net[i].tx,
369 <                                 "net", name, "tx", NULL);
370 <                        add_stat(LONG_LONG, &net[i].rx,
371 <                                 "net", name, "rx", NULL);
372 <                        add_stat(TIME_T, &net[i].systime,
373 <                                 "net", name, "systime", NULL);
366 >                        add_stat(STRING, &io[i].interface_name,
367 >                                 "net", name, "interface_name", NULL);
368 >                        add_stat(LONG_LONG, &io[i].tx,
369 >                                 "net", name, "tx", NULL);
370 >                        add_stat(LONG_LONG, &io[i].rx,
371 >                                 "net", name, "rx", NULL);
372 >                        add_stat(LONG_LONG, &io[i].ipackets,
373 >                                 "net", name, "ipackets", NULL);
374 >                        add_stat(LONG_LONG, &io[i].opackets,
375 >                                 "net", name, "opackets", NULL);
376 >                        add_stat(LONG_LONG, &io[i].ierrors,
377 >                                 "net", name, "ierrors", NULL);
378 >                        add_stat(LONG_LONG, &io[i].oerrors,
379 >                                 "net", name, "oerrors", NULL);
380 >                        add_stat(LONG_LONG, &io[i].collisions,
381 >                                 "net", name, "collisions", NULL);
382 >                        add_stat(TIME_T, &io[i].systime,
383 >                                 "net", name, "systime", NULL);
384                  }
385          }
386  
387 <        page = use_diffs ? get_page_stats_diff() : get_page_stats();
387 >        iface = sg_get_network_iface_stats(&num_iface);
388 >        if (iface != NULL) {
389 >                for (i = 0; i < num_iface; i++) {
390 >                        const char *name = iface[i].interface_name;
391 >                        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 >
409 >                        add_stat(INT, &iface[i].speed,
410 >                                 "net", name, "speed", NULL);
411 >                        add_stat(BOOL, &iface[i].up,
412 >                                 "net", name, "up", NULL);
413 >                        add_stat(DUPLEX, &iface[i].dup,
414 >                                 "net", name, "duplex", NULL);
415 >                }
416 >        }
417 > }
418 >
419 > void populate_page() {
420 >        sg_page_stats *page;
421 >
422 >        page = use_diffs ? sg_get_page_stats_diff() : sg_get_page_stats();
423          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 <                add_stat(LONG_LONG, &page->systime, "page", "systime", NULL);
426 >                add_stat(TIME_T, &page->systime, "page", "systime", NULL);
427          }
428 + }
429  
430 <        qsort(stats, num_stats, sizeof *stats, stats_compare);
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 >                                            strlen(t->name)) == 0) {
466 >                                        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 +
485 +        if (stats != NULL)
486 +                qsort(stats, num_stats, sizeof *stats, stats_compare);
487 + }
488 +
489   /* Print the value of a stat. */
490   void print_stat_value(const stat *s) {
491          void *v = s->stat;
492 +        double fv;
493 +        long l;
494  
495          switch (s->type) {
496          case LONG_LONG:
# Line 342 | Line 498 | void print_stat_value(const stat *s) {
498                  break;
499          case TIME_T:
500                  /* FIXME option for formatted time? */
501 <                printf("%ld", *(time_t *)v);
501 >                l = *(time_t *)v;
502 >                printf("%ld", l);
503                  break;
504          case FLOAT:
348                printf("%f", *(float *)v);
349                break;
505          case DOUBLE:
506 <                printf("%f", *(double *)v);
506 >                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                  break;
517          case STRING:
518                  /* FIXME escaping? */
# Line 357 | Line 521 | void print_stat_value(const stat *s) {
521          case INT:
522                  printf("%d", *(int *)v);
523                  break;
524 +        case BOOL:
525 +                printf("%s", *(int *)v ? "true" : "false");
526 +                break;
527 +        case DUPLEX:
528 +                switch (*(sg_iface_duplex *) v) {
529 +                case SG_IFACE_DUPLEX_FULL:
530 +                        printf("full");
531 +                        break;
532 +                case SG_IFACE_DUPLEX_HALF:
533 +                        printf("half");
534 +                        break;
535 +                default:
536 +                        printf("unknown");
537 +                        break;
538 +                }
539 +                break;
540          }
541   }
542  
# Line 388 | Line 568 | void print_stats(int argc, char **argv) {
568          } else {
569                  /* Print selected stats. */
570                  for (i = optind; i < argc; i++) {
571 +                        char *name = argv[i];
572                          stat key;
573 <                        const stat *s;
573 >                        const stat *s, *end;
574 >                        int (*compare)(const void *, const void *);
575  
576 <                        key.name = argv[i];
577 <                        s = (const stat *)bsearch(&key, stats, num_stats,
578 <                                                  sizeof *stats,
579 <                                                  stats_compare);
580 <                        if (s != NULL) {
576 >                        key.name = name;
577 >                        if (name[strlen(name) - 1] == '.')
578 >                                compare = stats_compare_prefix;
579 >                        else
580 >                                compare = stats_compare;
581 >
582 >                        if (stats == NULL) {
583 >                                s = NULL;
584 >                        } else {
585 >                                s = (const stat *)bsearch(&key, stats,
586 >                                                          num_stats,
587 >                                                          sizeof *stats,
588 >                                                          compare);
589 >                        }
590 >
591 >                        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                                  print_stat(s);
610                          }
611                  }
# Line 404 | Line 614 | void print_stats(int argc, char **argv) {
614  
615   void usage() {
616          printf("Usage: statgrab [OPTION]... [STAT]...\n"
617 <               "Display system statistics (all statistics by default).\n"
617 >               "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                 "\n");
622 <        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"
622 >        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                 "  -t DELAY   When repeating, wait DELAY seconds between updates (default 1)\n"
630 <               "  -p         Display CPU usage as percentages rather than absolute values\n"
630 >               "  -p     Display CPU usage differences as percentages rather than\n"
631 >               "             absolute values\n"
632 >               "  -f SCALE   Display floating-point values as integers scaled by FACTOR\n"
633                 "\n");
634          printf("Version %s - report bugs to <%s>.\n",
635 <                PACKAGE_VERSION, PACKAGE_BUGREPORT);
635 >               PACKAGE_VERSION, PACKAGE_BUGREPORT);
636          exit(1);
637   }
638  
639   int main(int argc, char **argv) {
640          opterr = 0;
641          while (1) {
642 <                int c = getopt(argc, argv, "lbmunsot:p");
642 >                int c = getopt(argc, argv, "lbmunsot:pf:");
643                  if (c == -1)
644                          break;
645                  switch (c) {
# Line 455 | Line 670 | int main(int argc, char **argv) {
670                  case 'p':
671                          use_cpu_percent = 1;
672                          break;
673 +                case 'f':
674 +                        float_scale_factor = atol(optarg);
675 +                        break;
676                  default:
677                          usage();
678                  }
# Line 463 | Line 681 | int main(int argc, char **argv) {
681          if (display_mode == DISPLAY_MRTG) {
682                  if ((argc - optind) != 2)
683                          die("mrtg mode: must specify exactly two stats");
684 <                if (repeat_mode != REPEAT_NONE)
684 >                if (repeat_mode == REPEAT_FOREVER)
685                          die("mrtg mode: cannot repeat display");
686          }
687  
688 +        if (use_cpu_percent && repeat_mode == REPEAT_NONE)
689 +                die("CPU percentage usage display requires stat differences");
690 +
691 +        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 +        /* We don't care if sg_init fails, because we can just display
699 +           the statistics that can be read as non-root. */
700 +        sg_init();
701 +        if (sg_drop_privileges() != 0)
702 +                die("Failed to drop setuid/setgid privileges");
703 +
704          switch (repeat_mode) {
705          case REPEAT_NONE:
706 <                get_stats(0);
706 >                get_stats();
707                  print_stats(argc, argv);
708                  break;
709          case REPEAT_ONCE:
710 <                get_stats(1);
710 >                get_stats();
711                  sleep(repeat_time);
712 <                get_stats(1);
712 >                get_stats();
713                  print_stats(argc, argv);
714                  break;
715          case REPEAT_FOREVER:
716                  while (1) {
717 <                        get_stats(1);
717 >                        get_stats();
718                          print_stats(argc, argv);
719                          printf("\n");
720                          sleep(repeat_time);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines