ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/statgrab/statgrab.c
Revision: 1.3
Committed: Wed Aug 27 14:04:17 2003 UTC (21 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.2: +4 -0 lines
Log Message:
Have to pull in the definitions from config.h.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2003 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
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 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <statgrab.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31
32 typedef enum {
33 LONG_LONG = 0,
34 TIME_T,
35 FLOAT,
36 DOUBLE,
37 STRING,
38 INT
39 } stat_type;
40
41 typedef enum {
42 DISPLAY_LINUX = 0,
43 DISPLAY_BSD,
44 DISPLAY_MRTG,
45 DISPLAY_PLAIN
46 } display_mode_type;
47
48 typedef enum {
49 REPEAT_NONE = 0,
50 REPEAT_ONCE,
51 REPEAT_FOREVER
52 } repeat_mode_type;
53
54 typedef struct {
55 char *name;
56 stat_type type;
57 void *stat;
58 } stat;
59
60 stat *stats = NULL;
61 int num_stats = 0;
62 int alloc_stats = 0;
63 #define INCREMENT_STATS 64
64
65 display_mode_type display_mode = DISPLAY_LINUX;
66 repeat_mode_type repeat_mode = REPEAT_NONE;
67 int repeat_time = 1;
68 int use_cpu_percent = 0;
69
70 /* Exit with an error message. */
71 void die(const char *s) {
72 fprintf(stderr, "fatal: %s\n", s);
73 exit(1);
74 }
75
76 /* Remove all the recorded stats. */
77 void clear_stats() {
78 int i;
79
80 for (i = 0; i < num_stats; i++)
81 free(stats[i].name);
82 free(stats);
83 stats = NULL;
84 num_stats = 0;
85 alloc_stats = 0;
86 }
87
88 /* Add a stat. The varargs make up the name, joined with dots; the name is
89 terminated with a NULL. */
90 void add_stat(stat_type type, void *stat, ...) {
91 va_list ap;
92 int len = 0;
93 char *name, *p;
94
95 /* Figure out how long the name will be, including dots and trailing
96 \0. */
97 va_start(ap, stat);
98 while (1) {
99 const char *part = va_arg(ap, const char *);
100 if (part == NULL)
101 break;
102 len += 1 + strlen(part);
103 }
104 va_end(ap);
105
106 /* Paste the name together. */
107 name = malloc(len);
108 if (name == NULL)
109 die("out of memory");
110 p = name;
111 va_start(ap, stat);
112 while (1) {
113 const char *part = va_arg(ap, const char *);
114 int partlen;
115 if (part == NULL)
116 break;
117 partlen = strlen(part);
118 memcpy(p, part, partlen);
119 p += partlen;
120 *p++ = '.';
121 }
122 va_end(ap);
123 *--p = '\0';
124
125 /* Replace spaces with underscores. */
126 for (p = name; *p != '\0'; p++) {
127 if (*p == ' ')
128 *p = '_';
129 }
130
131 /* Stretch the stats array if necessary. */
132 if (num_stats >= alloc_stats) {
133 alloc_stats += INCREMENT_STATS;
134 stats = realloc(stats, alloc_stats * sizeof *stats);
135 if (stats == NULL)
136 die("out of memory");
137 }
138
139 stats[num_stats].name = name;
140 stats[num_stats].type = type;
141 stats[num_stats].stat = stat;
142 ++num_stats;
143 }
144
145 /* Compare two stats by name, for sorting purposes. */
146 int stats_compare(const void *a, const void *b) {
147 return strcmp(((stat *)a)->name, ((stat *)b)->name);
148 }
149
150 /* Clear and rebuild the stats array. */
151 void get_stats(int use_diffs) {
152 cpu_states_t *cpu_s;
153 cpu_percent_t *cpu_p;
154 mem_stat_t *mem;
155 load_stat_t *load;
156 user_stat_t *user;
157 swap_stat_t *swap;
158 general_stat_t *gen;
159 disk_stat_t *disk;
160 diskio_stat_t *diskio;
161 process_stat_t *proc;
162 network_stat_t *net;
163 page_stat_t *page;
164 static int zero = 0;
165 int n, i;
166
167 clear_stats();
168
169 /* Constants, for use with MRTG mode. */
170 add_stat(INT, &zero, "const", "0", NULL);
171
172 /* FIXME when only fetching some stats, it'd be more efficient to only
173 do the libstatgrab calls needed, rather than fetching everything. */
174
175 if (use_cpu_percent) {
176 cpu_p = cpu_percent_usage();
177 if (cpu_p != NULL) {
178 add_stat(FLOAT, &cpu_p->user,
179 "cpu", "user", NULL);
180 add_stat(FLOAT, &cpu_p->kernel,
181 "cpu", "kernel", NULL);
182 add_stat(FLOAT, &cpu_p->idle,
183 "cpu", "idle", NULL);
184 add_stat(FLOAT, &cpu_p->iowait,
185 "cpu", "iowait", NULL);
186 add_stat(FLOAT, &cpu_p->swap,
187 "cpu", "swap", NULL);
188 add_stat(FLOAT, &cpu_p->nice,
189 "cpu", "nice", NULL);
190 add_stat(TIME_T, &cpu_s->systime,
191 "cpu", "time_taken", NULL);
192 }
193 } else {
194 cpu_s = use_diffs ? get_cpu_diff() : get_cpu_totals();
195 if (cpu_s != NULL) {
196 add_stat(LONG_LONG, &cpu_s->user,
197 "cpu", "user", NULL);
198 add_stat(LONG_LONG, &cpu_s->kernel,
199 "cpu", "kernel", NULL);
200 add_stat(LONG_LONG, &cpu_s->idle,
201 "cpu", "idle", NULL);
202 add_stat(LONG_LONG, &cpu_s->iowait,
203 "cpu", "iowait", NULL);
204 add_stat(LONG_LONG, &cpu_s->swap,
205 "cpu", "swap", NULL);
206 add_stat(LONG_LONG, &cpu_s->nice,
207 "cpu", "nice", NULL);
208 add_stat(LONG_LONG, &cpu_s->total,
209 "cpu", "total", NULL);
210 add_stat(TIME_T, &cpu_s->systime,
211 "cpu", "systime", NULL);
212 }
213 }
214
215 mem = get_memory_stats();
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
223 load = get_load_stats();
224 if (load != NULL) {
225 add_stat(DOUBLE, &load->min1, "load", "min1", NULL);
226 add_stat(DOUBLE, &load->min5, "load", "min5", NULL);
227 add_stat(DOUBLE, &load->min15, "load", "min15", NULL);
228 }
229
230 user = get_user_stats();
231 if (user != NULL) {
232 add_stat(INT, &user->num_entries, "user", "num", NULL);
233 add_stat(STRING, &user->name_list, "user", "names", NULL);
234 }
235
236 swap = get_swap_stats();
237 if (swap != NULL) {
238 add_stat(LONG_LONG, &swap->total, "swap", "total", NULL);
239 add_stat(LONG_LONG, &swap->used, "swap", "used", NULL);
240 add_stat(LONG_LONG, &swap->free, "swap", "free", NULL);
241 }
242
243 gen = get_general_stats();
244 if (gen != NULL) {
245 add_stat(STRING, &gen->os_name,
246 "general", "os_name", NULL);
247 add_stat(STRING, &gen->os_release,
248 "general", "os_release", NULL);
249 add_stat(STRING, &gen->os_version,
250 "general", "os_version", NULL);
251 add_stat(STRING, &gen->platform, "general", "platform", NULL);
252 add_stat(STRING, &gen->hostname, "general", "hostname", NULL);
253 add_stat(TIME_T, &gen->uptime, "general", "uptime", NULL);
254 }
255
256 disk = get_disk_stats(&n);
257 if (disk != NULL) {
258 for (i = 0; i < n; i++) {
259 /* FIXME it'd be nicer if libstatgrab did this */
260 const char *name = disk[i].device_name,
261 *p = strrchr(name, '/');
262 if (p != NULL)
263 name = p + 1;
264 if (*name == '\0')
265 name = "root";
266
267 add_stat(STRING, &disk[i].device_name,
268 "fs", name, "device_name", NULL);
269 add_stat(STRING, &disk[i].fs_type,
270 "fs", name, "fs_type", NULL);
271 add_stat(STRING, &disk[i].mnt_point,
272 "fs", name, "mnt_point", NULL);
273 add_stat(LONG_LONG, &disk[i].size,
274 "fs", name, "size", NULL);
275 add_stat(LONG_LONG, &disk[i].used,
276 "fs", name, "used", NULL);
277 add_stat(LONG_LONG, &disk[i].avail,
278 "fs", name, "avail", NULL);
279 add_stat(LONG_LONG, &disk[i].total_inodes,
280 "fs", name, "total_inodes", NULL);
281 add_stat(LONG_LONG, &disk[i].used_inodes,
282 "fs", name, "used_inodes", NULL);
283 add_stat(LONG_LONG, &disk[i].free_inodes,
284 "fs", name, "free_inodes", NULL);
285 }
286 }
287
288 diskio = use_diffs ? get_diskio_stats_diff(&n) : get_diskio_stats(&n);
289 if (diskio != NULL) {
290 for (i = 0; i < n; i++) {
291 const char *name = diskio[i].disk_name;
292
293 add_stat(STRING, &diskio[i].disk_name,
294 "disk", name, "disk_name", NULL);
295 add_stat(LONG_LONG, &diskio[i].read_bytes,
296 "disk", name, "read_bytes", NULL);
297 add_stat(LONG_LONG, &diskio[i].write_bytes,
298 "disk", name, "write_bytes", NULL);
299 add_stat(TIME_T, &diskio[i].systime,
300 "disk", name, "systime", NULL);
301 }
302 }
303
304 proc = get_process_stats();
305 if (proc != NULL) {
306 add_stat(INT, &proc->total, "proc", "total", NULL);
307 add_stat(INT, &proc->running, "proc", "running", NULL);
308 add_stat(INT, &proc->sleeping, "proc", "sleeping", NULL);
309 add_stat(INT, &proc->stopped, "proc", "stopped", NULL);
310 add_stat(INT, &proc->zombie, "proc", "zombie", NULL);
311 }
312
313 net = use_diffs ? get_network_stats_diff(&n) : get_network_stats(&n);
314 if (net != NULL) {
315 for (i = 0; i < n; i++) {
316 const char *name = net[i].interface_name;
317
318 add_stat(STRING, &net[i].interface_name,
319 "net", name, "interface_name", NULL);
320 add_stat(LONG_LONG, &net[i].tx,
321 "net", name, "tx", NULL);
322 add_stat(LONG_LONG, &net[i].rx,
323 "net", name, "rx", NULL);
324 add_stat(TIME_T, &net[i].systime,
325 "net", name, "systime", NULL);
326 }
327 }
328
329 page = use_diffs ? get_page_stats_diff() : get_page_stats();
330 if (page != NULL) {
331 add_stat(LONG_LONG, &page->pages_pagein, "page", "in", NULL);
332 add_stat(LONG_LONG, &page->pages_pageout, "page", "out", NULL);
333 add_stat(LONG_LONG, &page->systime, "page", "systime", NULL);
334 }
335
336 qsort(stats, num_stats, sizeof *stats, stats_compare);
337 }
338
339 /* Print the value of a stat. */
340 void print_stat_value(const stat *s) {
341 void *v = s->stat;
342
343 switch (s->type) {
344 case LONG_LONG:
345 printf("%lld", *(long long *)v);
346 break;
347 case TIME_T:
348 /* FIXME option for formatted time? */
349 printf("%ld", *(time_t *)v);
350 break;
351 case FLOAT:
352 printf("%f", *(float *)v);
353 break;
354 case DOUBLE:
355 printf("%f", *(double *)v);
356 break;
357 case STRING:
358 /* FIXME escaping? */
359 printf("%s", *(char **)v);
360 break;
361 case INT:
362 printf("%d", *(int *)v);
363 break;
364 }
365 }
366
367 /* Print the name and value of a stat. */
368 void print_stat(const stat *s) {
369 switch (display_mode) {
370 case DISPLAY_LINUX:
371 printf("%s = ", s->name);
372 break;
373 case DISPLAY_BSD:
374 printf("%s: ", s->name);
375 break;
376 case DISPLAY_MRTG:
377 case DISPLAY_PLAIN:
378 break;
379 }
380 print_stat_value(s);
381 printf("\n");
382 }
383
384 /* Print stats as specified on the provided command line. */
385 void print_stats(int argc, char **argv) {
386 int i;
387
388 if (argc == optind) {
389 /* Print all stats. */
390 for (i = 0; i < num_stats; i++)
391 print_stat(&stats[i]);
392 } else {
393 /* Print selected stats. */
394 for (i = optind; i < argc; i++) {
395 stat key;
396 const stat *s;
397
398 key.name = argv[i];
399 s = (const stat *)bsearch(&key, stats, num_stats,
400 sizeof *stats,
401 stats_compare);
402 if (s != NULL) {
403 print_stat(s);
404 }
405 }
406 }
407 }
408
409 void usage() {
410 printf("Usage: statgrab [OPTION]... [STAT]...\n"
411 "Display system statistics (all statistics by default).\n"
412 "\n");
413 printf(" -l Linux sysctl-style output (default)\n"
414 " -b BSD sysctl-style output\n"
415 " -m MRTG-compatible output\n"
416 " -u Plain output (only show values)\n"
417 " -n Display cumulative stats once (default)\n"
418 " -s Display stat differences repeatedly\n"
419 " -o Display stat differences once\n"
420 " -t DELAY When repeating, wait DELAY seconds between updates (default 1)\n"
421 " -p Display CPU usage as percentages rather than absolute values\n"
422 "\n");
423 printf("Version %s - report bugs to <%s>.\n",
424 PACKAGE_VERSION, PACKAGE_BUGREPORT);
425 exit(1);
426 }
427
428 int main(int argc, char **argv) {
429 opterr = 0;
430 while (1) {
431 int c = getopt(argc, argv, "lbmunsot:p");
432 if (c == -1)
433 break;
434 switch (c) {
435 case 'l':
436 display_mode = DISPLAY_LINUX;
437 break;
438 case 'b':
439 display_mode = DISPLAY_BSD;
440 break;
441 case 'm':
442 display_mode = DISPLAY_MRTG;
443 break;
444 case 'u':
445 display_mode = DISPLAY_PLAIN;
446 break;
447 case 'n':
448 repeat_mode = REPEAT_NONE;
449 break;
450 case 's':
451 repeat_mode = REPEAT_FOREVER;
452 break;
453 case 'o':
454 repeat_mode = REPEAT_ONCE;
455 break;
456 case 't':
457 repeat_time = atoi(optarg);
458 break;
459 case 'p':
460 use_cpu_percent = 1;
461 break;
462 default:
463 usage();
464 }
465 }
466
467 if (display_mode == DISPLAY_MRTG) {
468 if ((argc - optind) != 2)
469 die("mrtg mode: must specify exactly two stats");
470 if (repeat_mode != REPEAT_NONE)
471 die("mrtg mode: cannot repeat display");
472 }
473
474 switch (repeat_mode) {
475 case REPEAT_NONE:
476 get_stats(0);
477 print_stats(argc, argv);
478 break;
479 case REPEAT_ONCE:
480 get_stats(1);
481 sleep(repeat_time);
482 get_stats(1);
483 print_stats(argc, argv);
484 break;
485 case REPEAT_FOREVER:
486 while (1) {
487 get_stats(1);
488 print_stats(argc, argv);
489 printf("\n");
490 sleep(repeat_time);
491 }
492 }
493
494 if (display_mode == DISPLAY_MRTG) {
495 printf("\n");
496 printf("statgrab\n");
497 }
498
499 return 0;
500 }
501