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.38 by tdb, Sun Oct 3 18:35:59 2010 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 27 | Line 33
33  
34   typedef enum {
35          LONG_LONG = 0,
36 +        BYTES,
37          TIME_T,
38          FLOAT,
39          DOUBLE,
40          STRING,
41 <        INT
41 >        INT,
42 >        BOOL,
43 >        DUPLEX
44   } stat_type;
45  
46   typedef enum {
# Line 51 | Line 60 | typedef struct {
60          char *name;
61          stat_type type;
62          void *stat;
63 < } stat;
63 > } stat_item;
64 > /* AIX:
65 > statgrab.c:63: error: 'stat' redeclared as different kind of symbol
66 > /usr/include/sys/stat.h:320: error: previous declaration of 'stat' was here
67 > */
68  
69 < stat *stats = NULL;
69 > stat_item *stat_items = NULL;
70   int num_stats = 0;
71   int alloc_stats = 0;
72   #define INCREMENT_STATS 64
# Line 62 | Line 75 | display_mode_type display_mode = DISPLAY_LINUX;
75   repeat_mode_type repeat_mode = REPEAT_NONE;
76   int repeat_time = 1;
77   int use_cpu_percent = 0;
78 + int use_diffs = 0;
79 + long float_scale_factor = 0;
80 + long long bytes_scale_factor = 0;
81  
82   /* Exit with an error message. */
83   void die(const char *s) {
# Line 74 | Line 90 | void clear_stats() {
90          int i;
91  
92          for (i = 0; i < num_stats; i++)
93 <                free(stats[i].name);
78 <        free(stats);
79 <        stats = NULL;
93 >                free(stat_items[i].name);
94          num_stats = 0;
81        alloc_stats = 0;
95   }
96  
97   /* Add a stat. The varargs make up the name, joined with dots; the name is
# Line 112 | Line 125 | void add_stat(stat_type type, void *stat, ...) {
125                          break;
126                  partlen = strlen(part);
127                  memcpy(p, part, partlen);
128 <                p += partlen;
128 >
129 >                /* Replace spaces and dots with underscores. */
130 >                while (partlen-- > 0) {
131 >                        if (*p == ' ' || *p == '.')
132 >                                *p = '_';
133 >                        p++;
134 >                }
135 >
136                  *p++ = '.';
137          }
138          va_end(ap);
139          *--p = '\0';
140  
121        /* Replace spaces with underscores. */
122        for (p = name; *p != '\0'; p++) {
123                if (*p == ' ')
124                        *p = '_';
125        }
126
141          /* Stretch the stats array if necessary. */
142          if (num_stats >= alloc_stats) {
143                  alloc_stats += INCREMENT_STATS;
144 <                stats = realloc(stats, alloc_stats * sizeof *stats);
145 <                if (stats == NULL)
144 >                stat_items = realloc(stat_items, alloc_stats * sizeof *stat_items);
145 >                if (stat_items == NULL)
146                          die("out of memory");
147          }
148  
149 <        stats[num_stats].name = name;
150 <        stats[num_stats].type = type;
151 <        stats[num_stats].stat = stat;
149 >        stat_items[num_stats].name = name;
150 >        stat_items[num_stats].type = type;
151 >        stat_items[num_stats].stat = stat;
152          ++num_stats;
153   }
154  
155 < /* Compare two stats by name, for sorting purposes. */
155 > /* Compare two stats by name for qsort and bsearch. */
156   int stats_compare(const void *a, const void *b) {
157 <        return strcmp(((stat *)a)->name, ((stat *)b)->name);
157 >        return strcmp(((stat_item *)a)->name, ((stat_item *)b)->name);
158   }
159  
160 < /* Clear and rebuild the stats array. */
161 < void get_stats(int use_diffs) {
162 <        cpu_states_t *cpu_s;
163 <        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;
160 > /* Compare up to the length of the key for bsearch. */
161 > int stats_compare_prefix(const void *key, const void *item) {
162 >        const char *kn = ((stat_item *)key)->name;
163 >        const char *in = ((stat_item *)item)->name;
164  
165 <        clear_stats();
165 >        return strncmp(kn, in, strlen(kn));
166 > }
167  
168 + void populate_const() {
169 +        static int zero = 0;
170 +
171          /* Constants, for use with MRTG mode. */
172          add_stat(INT, &zero, "const", "0", NULL);
173 + }
174  
175 <        /* FIXME when only fetching some stats, it'd be more efficient to only
169 <           do the libstatgrab calls needed, rather than fetching everything. */
170 <
175 > void populate_cpu() {
176          if (use_cpu_percent) {
177 <                cpu_p = cpu_percent_usage();
177 >                sg_cpu_percents *cpu_p = sg_get_cpu_percents();
178 >
179                  if (cpu_p != NULL) {
180                          add_stat(FLOAT, &cpu_p->user,
181 <                                 "cpu", "user", NULL);
181 >                                 "cpu", "user", NULL);
182                          add_stat(FLOAT, &cpu_p->kernel,
183 <                                 "cpu", "kernel", NULL);
183 >                                 "cpu", "kernel", NULL);
184                          add_stat(FLOAT, &cpu_p->idle,
185 <                                 "cpu", "idle", NULL);
185 >                                 "cpu", "idle", NULL);
186                          add_stat(FLOAT, &cpu_p->iowait,
187 <                                 "cpu", "iowait", NULL);
187 >                                 "cpu", "iowait", NULL);
188                          add_stat(FLOAT, &cpu_p->swap,
189 <                                 "cpu", "swap", NULL);
189 >                                 "cpu", "swap", NULL);
190                          add_stat(FLOAT, &cpu_p->nice,
191 <                                 "cpu", "nice", NULL);
192 <                        add_stat(TIME_T, &cpu_s->systime,
193 <                                 "cpu", "time_taken", NULL);
191 >                                 "cpu", "nice", NULL);
192 >                        add_stat(TIME_T, &cpu_p->time_taken,
193 >                                 "cpu", "time_taken", NULL);
194                  }
195          } else {
196 <                cpu_s = use_diffs ? get_cpu_diff() : get_cpu_totals();
196 >                sg_cpu_stats *cpu_s;
197 >
198 >                cpu_s = use_diffs ? sg_get_cpu_stats_diff()
199 >                                  : sg_get_cpu_stats();
200                  if (cpu_s != NULL) {
201                          add_stat(LONG_LONG, &cpu_s->user,
202 <                                 "cpu", "user", NULL);
202 >                                 "cpu", "user", NULL);
203                          add_stat(LONG_LONG, &cpu_s->kernel,
204 <                                 "cpu", "kernel", NULL);
204 >                                 "cpu", "kernel", NULL);
205                          add_stat(LONG_LONG, &cpu_s->idle,
206 <                                 "cpu", "idle", NULL);
206 >                                 "cpu", "idle", NULL);
207                          add_stat(LONG_LONG, &cpu_s->iowait,
208 <                                 "cpu", "iowait", NULL);
208 >                                 "cpu", "iowait", NULL);
209                          add_stat(LONG_LONG, &cpu_s->swap,
210 <                                 "cpu", "swap", NULL);
210 >                                 "cpu", "swap", NULL);
211                          add_stat(LONG_LONG, &cpu_s->nice,
212 <                                 "cpu", "nice", NULL);
212 >                                 "cpu", "nice", NULL);
213                          add_stat(LONG_LONG, &cpu_s->total,
214 <                                 "cpu", "total", NULL);
214 >                                 "cpu", "total", NULL);
215                          add_stat(TIME_T, &cpu_s->systime,
216 <                                 "cpu", "systime", NULL);
216 >                                 "cpu", "systime", NULL);
217                  }
218          }
219 + }
220  
221 <        mem = get_memory_stats();
221 > void populate_mem() {
222 >        sg_mem_stats *mem = sg_get_mem_stats();
223 >
224          if (mem != NULL) {
225 <                add_stat(LONG_LONG, &mem->total, "mem", "total", NULL);
226 <                add_stat(LONG_LONG, &mem->free, "mem", "free", NULL);
227 <                add_stat(LONG_LONG, &mem->used, "mem", "used", NULL);
228 <                add_stat(LONG_LONG, &mem->cache, "mem", "cache", NULL);
225 >                add_stat(BYTES, &mem->total, "mem", "total", NULL);
226 >                add_stat(BYTES, &mem->free, "mem", "free", NULL);
227 >                add_stat(BYTES, &mem->used, "mem", "used", NULL);
228 >                add_stat(BYTES, &mem->cache, "mem", "cache", NULL);
229          }
230 + }
231  
232 <        load = get_load_stats();
232 > void populate_load() {
233 >        sg_load_stats *load = sg_get_load_stats();
234 >
235          if (load != NULL) {
236                  add_stat(DOUBLE, &load->min1, "load", "min1", NULL);
237                  add_stat(DOUBLE, &load->min5, "load", "min5", NULL);
238                  add_stat(DOUBLE, &load->min15, "load", "min15", NULL);
239          }
240 + }
241  
242 <        user = get_user_stats();
242 > void populate_user() {
243 >        sg_user_stats *user = sg_get_user_stats();
244 >
245          if (user != NULL) {
246                  add_stat(INT, &user->num_entries, "user", "num", NULL);
247                  add_stat(STRING, &user->name_list, "user", "names", NULL);
248          }
249 + }
250  
251 <        swap = get_swap_stats();
251 > void populate_swap() {
252 >        sg_swap_stats *swap = sg_get_swap_stats();
253 >
254          if (swap != NULL) {
255 <                add_stat(LONG_LONG, &swap->total, "swap", "total", NULL);
256 <                add_stat(LONG_LONG, &swap->used, "swap", "used", NULL);
257 <                add_stat(LONG_LONG, &swap->free, "swap", "free", NULL);
255 >                add_stat(BYTES, &swap->total, "swap", "total", NULL);
256 >                add_stat(BYTES, &swap->used, "swap", "used", NULL);
257 >                add_stat(BYTES, &swap->free, "swap", "free", NULL);
258          }
259 + }
260  
261 <        gen = get_general_stats();
262 <        if (gen != NULL) {
263 <                add_stat(STRING, &gen->os_name,
264 <                         "general", "os_name", NULL);
265 <                add_stat(STRING, &gen->os_release,
266 <                         "general", "os_release", NULL);
267 <                add_stat(STRING, &gen->os_version,
268 <                         "general", "os_version", NULL);
269 <                add_stat(STRING, &gen->platform, "general", "platform", NULL);
270 <                add_stat(STRING, &gen->hostname, "general", "hostname", NULL);
271 <                add_stat(TIME_T, &gen->uptime, "general", "uptime", NULL);
261 > void populate_general() {
262 >        /* FIXME this should be renamed to host. */
263 >        sg_host_info *host = sg_get_host_info();
264 >
265 >        if (host != NULL) {
266 >                add_stat(STRING, &host->os_name,
267 >                         "general", "os_name", NULL);
268 >                add_stat(STRING, &host->os_release,
269 >                         "general", "os_release", NULL);
270 >                add_stat(STRING, &host->os_version,
271 >                         "general", "os_version", NULL);
272 >                add_stat(STRING, &host->platform, "general", "platform", NULL);
273 >                add_stat(STRING, &host->hostname, "general", "hostname", NULL);
274 >                add_stat(TIME_T, &host->uptime, "general", "uptime", NULL);
275          }
276 + }
277  
278 <        disk = get_disk_stats(&n);
278 > void populate_fs() {
279 >        int n, i;
280 >        sg_fs_stats *disk = sg_get_fs_stats(&n);
281 >
282          if (disk != NULL) {
283                  for (i = 0; i < n; i++) {
284                          /* FIXME it'd be nicer if libstatgrab did this */
285 <                        const char *name = disk[i].device_name,
286 <                                   *p = strrchr(name, '/');
287 <                        if (p != NULL)
288 <                                name = p + 1;
289 <                        if (*name == '\0')
290 <                                name = "root";
291 <        
285 >                        char *buf, *name, *p;
286 >                        const char *device = disk[i].device_name;
287 >
288 >                        if (strcmp(device, "/") == 0)
289 >                                device = "root";
290 >
291 >                        buf = strdup(device);
292 >                        if (buf == NULL)
293 >                                die("out of memory");
294 >
295 >                        name = buf;
296 >                        if (strlen(name) == 2 && name[1] == ':')
297 >                                name[1] = '\0';
298 >                        if (strncmp(name, "/dev/", 5) == 0)
299 >                                name += 5;
300 >                        while ((p = strchr(name, '/')) != NULL)
301 >                                *p = '_';
302 >
303                          add_stat(STRING, &disk[i].device_name,
304 <                                 "fs", name, "device_name", NULL);
304 >                                 "fs", name, "device_name", NULL);
305                          add_stat(STRING, &disk[i].fs_type,
306 <                                 "fs", name, "fs_type", NULL);
306 >                                 "fs", name, "fs_type", NULL);
307                          add_stat(STRING, &disk[i].mnt_point,
308 <                                 "fs", name, "mnt_point", NULL);
309 <                        add_stat(LONG_LONG, &disk[i].size,
310 <                                 "fs", name, "size", NULL);
311 <                        add_stat(LONG_LONG, &disk[i].used,
312 <                                 "fs", name, "used", NULL);
313 <                        add_stat(LONG_LONG, &disk[i].avail,
314 <                                 "fs", name, "avail", NULL);
308 >                                 "fs", name, "mnt_point", NULL);
309 >                        add_stat(BYTES, &disk[i].size,
310 >                                 "fs", name, "size", NULL);
311 >                        add_stat(BYTES, &disk[i].used,
312 >                                 "fs", name, "used", NULL);
313 >                        add_stat(BYTES, &disk[i].avail,
314 >                                 "fs", name, "avail", NULL);
315                          add_stat(LONG_LONG, &disk[i].total_inodes,
316 <                                 "fs", name, "total_inodes", NULL);
316 >                                 "fs", name, "total_inodes", NULL);
317                          add_stat(LONG_LONG, &disk[i].used_inodes,
318 <                                 "fs", name, "used_inodes", NULL);
318 >                                 "fs", name, "used_inodes", NULL);
319                          add_stat(LONG_LONG, &disk[i].free_inodes,
320 <                                 "fs", name, "free_inodes", NULL);
320 >                                 "fs", name, "free_inodes", NULL);
321 >                        add_stat(LONG_LONG, &disk[i].avail_inodes,
322 >                                 "fs", name, "avail_inodes", NULL);
323 >                        add_stat(LONG_LONG, &disk[i].io_size,
324 >                                 "fs", name, "io_size", NULL);
325 >                        add_stat(LONG_LONG, &disk[i].block_size,
326 >                                 "fs", name, "block_size", NULL);
327 >                        add_stat(LONG_LONG, &disk[i].total_blocks,
328 >                                 "fs", name, "total_blocks", NULL);
329 >                        add_stat(LONG_LONG, &disk[i].free_blocks,
330 >                                 "fs", name, "free_blocks", NULL);
331 >                        add_stat(LONG_LONG, &disk[i].avail_blocks,
332 >                                 "fs", name, "avail_blocks", NULL);
333 >                        add_stat(LONG_LONG, &disk[i].used_blocks,
334 >                                 "fs", name, "used_blocks", NULL);
335 >
336 >                        free(buf);
337                  }
338          }
339 + }
340  
341 <        diskio = use_diffs ? get_diskio_stats_diff(&n) : get_diskio_stats(&n);
341 > void populate_disk() {
342 >        int n, i;
343 >        sg_disk_io_stats *diskio;
344 >
345 >        diskio = use_diffs ? sg_get_disk_io_stats_diff(&n)
346 >                           : sg_get_disk_io_stats(&n);
347          if (diskio != NULL) {
348                  for (i = 0; i < n; i++) {
349                          const char *name = diskio[i].disk_name;
350          
351                          add_stat(STRING, &diskio[i].disk_name,
352 <                                 "disk", name, "disk_name", NULL);
353 <                        add_stat(LONG_LONG, &diskio[i].read_bytes,
354 <                                 "disk", name, "read_bytes", NULL);
355 <                        add_stat(LONG_LONG, &diskio[i].write_bytes,
356 <                                 "disk", name, "write_bytes", NULL);
352 >                                 "disk", name, "disk_name", NULL);
353 >                        add_stat(BYTES, &diskio[i].read_bytes,
354 >                                 "disk", name, "read_bytes", NULL);
355 >                        add_stat(BYTES, &diskio[i].write_bytes,
356 >                                 "disk", name, "write_bytes", NULL);
357                          add_stat(TIME_T, &diskio[i].systime,
358 <                                 "disk", name, "systime", NULL);
358 >                                 "disk", name, "systime", NULL);
359                  }
360          }
361 + }
362  
363 <        proc = get_process_stats();
363 > void populate_proc() {
364 >        /* FIXME expose individual process info too */
365 >        sg_process_count *proc = sg_get_process_count();
366 >
367          if (proc != NULL) {
368                  add_stat(INT, &proc->total, "proc", "total", NULL);
369                  add_stat(INT, &proc->running, "proc", "running", NULL);
# Line 305 | Line 371 | void get_stats(int use_diffs) {
371                  add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
372                  add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
373          }
374 + }
375  
376 <        net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n);
377 <        if (net != NULL) {
378 <                for (i = 0; i < n; i++) {
379 <                        const char *name = net[i].interface_name;
376 > void populate_net() {
377 >        int num_io, num_iface, i;
378 >        sg_network_io_stats *io;
379 >        sg_network_iface_stats *iface;
380 >
381 >        io = use_diffs ? sg_get_network_io_stats_diff(&num_io)
382 >                       : sg_get_network_io_stats(&num_io);
383 >        if (io != NULL) {
384 >                for (i = 0; i < num_io; i++) {
385 >                        const char *name = io[i].interface_name;
386          
387 <                        add_stat(STRING, &net[i].interface_name,
388 <                                 "net", name, "interface_name", NULL);
389 <                        add_stat(LONG_LONG, &net[i].tx,
390 <                                 "net", name, "tx", NULL);
391 <                        add_stat(LONG_LONG, &net[i].rx,
392 <                                 "net", name, "rx", NULL);
393 <                        add_stat(TIME_T, &net[i].systime,
394 <                                 "net", name, "systime", NULL);
387 >                        add_stat(STRING, &io[i].interface_name,
388 >                                 "net", name, "interface_name", NULL);
389 >                        add_stat(BYTES, &io[i].tx,
390 >                                 "net", name, "tx", NULL);
391 >                        add_stat(BYTES, &io[i].rx,
392 >                                 "net", name, "rx", NULL);
393 >                        add_stat(LONG_LONG, &io[i].ipackets,
394 >                                 "net", name, "ipackets", NULL);
395 >                        add_stat(LONG_LONG, &io[i].opackets,
396 >                                 "net", name, "opackets", NULL);
397 >                        add_stat(LONG_LONG, &io[i].ierrors,
398 >                                 "net", name, "ierrors", NULL);
399 >                        add_stat(LONG_LONG, &io[i].oerrors,
400 >                                 "net", name, "oerrors", NULL);
401 >                        add_stat(LONG_LONG, &io[i].collisions,
402 >                                 "net", name, "collisions", NULL);
403 >                        add_stat(TIME_T, &io[i].systime,
404 >                                 "net", name, "systime", NULL);
405                  }
406          }
407  
408 <        page = use_diffs ? get_page_stats_diff() : get_page_stats();
408 >        iface = sg_get_network_iface_stats(&num_iface);
409 >        if (iface != NULL) {
410 >                for (i = 0; i < num_iface; i++) {
411 >                        const char *name = iface[i].interface_name;
412 >                        int had_io = 0, j;
413 >
414 >                        /* If there wasn't a corresponding io stat,
415 >                           add interface_name from here. */
416 >                        if (io != NULL) {
417 >                                for (j = 0; j < num_io; j++) {
418 >                                        if (strcmp(io[j].interface_name,
419 >                                                   name) == 0) {
420 >                                                had_io = 1;
421 >                                                break;
422 >                                        }
423 >                                }
424 >                        }
425 >                        if (!had_io) {
426 >                                add_stat(STRING, &iface[i].interface_name,
427 >                                        "net", name, "interface_name", NULL);
428 >                        }
429 >
430 >                        add_stat(INT, &iface[i].speed,
431 >                                 "net", name, "speed", NULL);
432 >                        add_stat(BOOL, &iface[i].up,
433 >                                 "net", name, "up", NULL);
434 >                        add_stat(DUPLEX, &iface[i].duplex,
435 >                                 "net", name, "duplex", NULL);
436 >                }
437 >        }
438 > }
439 >
440 > void populate_page() {
441 >        sg_page_stats *page;
442 >
443 >        page = use_diffs ? sg_get_page_stats_diff() : sg_get_page_stats();
444          if (page != NULL) {
445                  add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
446                  add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
447 <                add_stat(LONG_LONG, &page->systime, "page", "systime", NULL);
447 >                add_stat(TIME_T, &page->systime, "page", "systime", NULL);
448          }
449 + }
450  
451 <        qsort(stats, num_stats, sizeof *stats, stats_compare);
451 > typedef struct {
452 >        const char *name;
453 >        void (*populate)();
454 >        int interesting;
455 > } toplevel;
456 > toplevel toplevels[] = {
457 >        {"const.", populate_const, 0},
458 >        {"cpu.", populate_cpu, 0},
459 >        {"mem.", populate_mem, 0},
460 >        {"load.", populate_load, 0},
461 >        {"user.", populate_user, 0},
462 >        {"swap.", populate_swap, 0},
463 >        {"general.", populate_general, 0},
464 >        {"fs.", populate_fs, 0},
465 >        {"disk.", populate_disk, 0},
466 >        {"proc.", populate_proc, 0},
467 >        {"net.", populate_net, 0},
468 >        {"page.", populate_page, 0},
469 >        {NULL, NULL, 0}
470 > };
471 >
472 > /* Set the "interesting" flag on the sections that we actually need to
473 >   fetch. */
474 > void select_interesting(int argc, char **argv) {
475 >        toplevel *t;
476 >
477 >        if (argc == 0) {
478 >                for (t = &toplevels[0]; t->name != NULL; t++)
479 >                        t->interesting = 1;
480 >        } else {
481 >                int i;
482 >
483 >                for (i = 0; i < argc; i++) {
484 >                        for (t = &toplevels[0]; t->name != NULL; t++) {
485 >                                if (strncmp(argv[i], t->name,
486 >                                            strlen(t->name)) == 0) {
487 >                                        t->interesting = 1;
488 >                                        break;
489 >                                }
490 >                        }
491 >                }
492 >        }
493   }
494  
495 < /* Print the value of a stat. */
496 < void print_stat_value(const stat *s) {
495 > /* Clear and rebuild the stat_items array. */
496 > void get_stats() {
497 >        toplevel *t;
498 >
499 >        clear_stats();
500 >
501 >        for (t = &toplevels[0]; t->name != NULL; t++) {
502 >                if (t->interesting)
503 >                        t->populate();
504 >        }
505 >
506 >        if (stat_items != NULL)
507 >                qsort(stat_items, num_stats, sizeof *stat_items, stats_compare);
508 > }
509 >
510 > /* Print the value of a stat_item. */
511 > void print_stat_value(const stat_item *s) {
512          void *v = s->stat;
513 +        double fv;
514 +        long lv;
515 +        long long llv;
516  
517          switch (s->type) {
518          case LONG_LONG:
519 + #ifdef WIN32 /* Windows printf does not understand %lld, so use %I64d instead */
520 +                printf("%I64d", *(long long *)v);
521 + #else
522                  printf("%lld", *(long long *)v);
523 + #endif
524                  break;
525 +        case BYTES:
526 +                llv = *(long long *)v;
527 +                if (bytes_scale_factor != 0) {
528 +                        llv /= bytes_scale_factor;
529 +                }
530 + #ifdef WIN32
531 +                printf("%I64d", llv);
532 + #else
533 +                printf("%lld", llv);
534 + #endif
535 +                break;
536          case TIME_T:
537                  /* FIXME option for formatted time? */
538 <                printf("%ld", *(time_t *)v);
538 >                lv = *(time_t *)v;
539 >                printf("%ld", lv);
540                  break;
541          case FLOAT:
348                printf("%f", *(float *)v);
349                break;
542          case DOUBLE:
543 <                printf("%f", *(double *)v);
543 >                if (s->type == FLOAT) {
544 >                        fv = *(float *)v;
545 >                } else {
546 >                        fv = *(double *)v;
547 >                }
548 >                if (float_scale_factor != 0) {
549 >                        printf("%ld", (long)(float_scale_factor * fv));
550 >                } else {
551 >                        printf("%f", fv);
552 >                }
553                  break;
554          case STRING:
555                  /* FIXME escaping? */
# Line 357 | Line 558 | void print_stat_value(const stat *s) {
558          case INT:
559                  printf("%d", *(int *)v);
560                  break;
561 +        case BOOL:
562 +                printf("%s", *(int *)v ? "true" : "false");
563 +                break;
564 +        case DUPLEX:
565 +                switch (*(sg_iface_duplex *) v) {
566 +                case SG_IFACE_DUPLEX_FULL:
567 +                        printf("full");
568 +                        break;
569 +                case SG_IFACE_DUPLEX_HALF:
570 +                        printf("half");
571 +                        break;
572 +                default:
573 +                        printf("unknown");
574 +                        break;
575 +                }
576 +                break;
577          }
578   }
579  
580   /* Print the name and value of a stat. */
581 < void print_stat(const stat *s) {
581 > void print_stat(const stat_item *s) {
582          switch (display_mode) {
583          case DISPLAY_LINUX:
584                  printf("%s = ", s->name);
# Line 384 | Line 601 | void print_stats(int argc, char **argv) {
601          if (argc == optind) {
602                  /* Print all stats. */
603                  for (i = 0; i < num_stats; i++)
604 <                        print_stat(&stats[i]);
604 >                        print_stat(&stat_items[i]);
605          } else {
606                  /* Print selected stats. */
607                  for (i = optind; i < argc; i++) {
608 <                        stat key;
609 <                        const stat *s;
608 >                        char *name = argv[i];
609 >                        stat_item key;
610 >                        const stat_item *s, *end;
611 >                        int (*compare)(const void *, const void *);
612  
613 <                        key.name = argv[i];
614 <                        s = (const stat *)bsearch(&key, stats, num_stats,
615 <                                                  sizeof *stats,
616 <                                                  stats_compare);
617 <                        if (s != NULL) {
613 >                        key.name = name;
614 >                        if (name[strlen(name) - 1] == '.')
615 >                                compare = stats_compare_prefix;
616 >                        else
617 >                                compare = stats_compare;
618 >
619 >                        if (stat_items == NULL) {
620 >                                s = NULL;
621 >                        } else {
622 >                                s = (const stat_item *)bsearch(&key, stat_items,
623 >                                                          num_stats,
624 >                                                          sizeof *stat_items,
625 >                                                          compare);
626 >                        }
627 >
628 >                        if (s == NULL) {
629 >                                printf("Unknown stat %s\n", name);
630 >                                continue;
631 >                        }
632 >
633 >                        /* Find the range of stats the user wanted. */
634 >                        for (; s >= stat_items; s--) {
635 >                                if (compare(&key, s) != 0)
636 >                                        break;
637 >                        }
638 >                        s++;
639 >                        for (end = s; end < &stat_items[num_stats]; end++) {
640 >                                if (compare(&key, end) != 0)
641 >                                        break;
642 >                        }
643 >
644 >                        /* And print them. */
645 >                        for (; s < end; s++) {
646                                  print_stat(s);
647                          }
648                  }
# Line 404 | Line 651 | void print_stats(int argc, char **argv) {
651  
652   void usage() {
653          printf("Usage: statgrab [OPTION]... [STAT]...\n"
654 <               "Display system statistics (all statistics by default).\n"
654 >               "Display system statistics.\n"
655 >               "\n"
656 >               "If no STATs are given, all will be displayed. Specify 'STAT.' to display all\n"
657 >               "statistics starting with that prefix.\n"
658                 "\n");
659          printf("  -l         Linux sysctl-style output (default)\n"
660                 "  -b         BSD sysctl-style output\n"
# Line 414 | Line 664 | void usage() {
664                 "  -s         Display stat differences repeatedly\n"
665                 "  -o         Display stat differences once\n"
666                 "  -t DELAY   When repeating, wait DELAY seconds between updates (default 1)\n"
667 <               "  -p         Display CPU usage as percentages rather than absolute values\n"
667 >               "  -p         Display CPU usage differences as percentages rather than\n"
668 >               "             absolute values\n"
669 >               "  -f FACTOR  Display floating-point values as integers scaled by FACTOR\n"
670 >               "  -K         Display byte counts in kibibytes\n"
671 >               "  -M         Display byte counts in mebibytes\n"
672 >               "  -G         Display byte counts in gibibytes\n"
673                 "\n");
674          printf("Version %s - report bugs to <%s>.\n",
675 <                PACKAGE_VERSION, PACKAGE_BUGREPORT);
675 >               PACKAGE_VERSION, PACKAGE_BUGREPORT);
676          exit(1);
677   }
678  
679   int main(int argc, char **argv) {
680          opterr = 0;
681          while (1) {
682 <                int c = getopt(argc, argv, "lbmunsot:p");
682 >                int c = getopt(argc, argv, "lbmunsot:pf:KMG");
683                  if (c == -1)
684                          break;
685                  switch (c) {
# Line 455 | Line 710 | int main(int argc, char **argv) {
710                  case 'p':
711                          use_cpu_percent = 1;
712                          break;
713 +                case 'f':
714 +                        float_scale_factor = atol(optarg);
715 +                        break;
716 +                case 'K':
717 +                        bytes_scale_factor = 1024;
718 +                        break;
719 +                case 'M':
720 +                        bytes_scale_factor = 1024 * 1024;
721 +                        break;
722 +                case 'G':
723 +                        bytes_scale_factor = 1024 * 1024 * 1024;
724 +                        break;
725                  default:
726                          usage();
727                  }
# Line 463 | Line 730 | int main(int argc, char **argv) {
730          if (display_mode == DISPLAY_MRTG) {
731                  if ((argc - optind) != 2)
732                          die("mrtg mode: must specify exactly two stats");
733 <                if (repeat_mode != REPEAT_NONE)
733 >                if (repeat_mode == REPEAT_FOREVER)
734                          die("mrtg mode: cannot repeat display");
735          }
736  
737 +        if (use_cpu_percent && repeat_mode == REPEAT_NONE)
738 +                die("CPU percentage usage display requires stat differences");
739 +
740 +        if (repeat_mode == REPEAT_NONE)
741 +                use_diffs = 0;
742 +        else
743 +                use_diffs = 1;
744 +
745 +        select_interesting(argc - optind, &argv[optind]);
746 +
747 +        /* We don't care if sg_init fails, because we can just display
748 +           the statistics that can be read as non-root. */
749 +        sg_init();
750 +        sg_snapshot();
751 +        if (sg_drop_privileges() != 0)
752 +                die("Failed to drop setuid/setgid privileges");
753 +
754          switch (repeat_mode) {
755          case REPEAT_NONE:
756 <                get_stats(0);
756 >                get_stats();
757                  print_stats(argc, argv);
758                  break;
759          case REPEAT_ONCE:
760 <                get_stats(1);
760 >                get_stats();
761                  sleep(repeat_time);
762 <                get_stats(1);
762 >                sg_snapshot();
763 >                get_stats();
764                  print_stats(argc, argv);
765                  break;
766          case REPEAT_FOREVER:
767                  while (1) {
768 <                        get_stats(1);
768 >                        get_stats();
769                          print_stats(argc, argv);
770                          printf("\n");
771                          sleep(repeat_time);
772 +                        sg_snapshot();
773                  }
774          }
775  
# Line 491 | Line 777 | int main(int argc, char **argv) {
777                  printf("\n");
778                  printf("statgrab\n");
779          }
780 +
781 +        sg_shutdown();
782  
783          return 0;
784   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines