1: /*
2: * src/bmon.c Bandwidth Monitor
3: *
4: * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5: * Copyright (c) 2013 Red Hat, Inc.
6: *
7: * Permission is hereby granted, free of charge, to any person obtaining a
8: * copy of this software and associated documentation files (the "Software"),
9: * to deal in the Software without restriction, including without limitation
10: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11: * and/or sell copies of the Software, and to permit persons to whom the
12: * Software is furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included
15: * in all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23: * DEALINGS IN THE SOFTWARE.
24: */
25:
26: #include <bmon/bmon.h>
27: #include <bmon/conf.h>
28: #include <bmon/attr.h>
29: #include <bmon/utils.h>
30: #include <bmon/input.h>
31: #include <bmon/output.h>
32: #include <bmon/module.h>
33: #include <bmon/group.h>
34:
35: int start_time;
36:
37: struct reader_timing rtiming;
38:
39: static char *usage_text =
40: "Usage: bmon [OPTION]...\n" \
41: "\n" \
42: "Options:\n" \
43: "Startup:\n" \
44: " -i, --input=MODPARM Input module(s)\n" \
45: " -o, --output=MODPARM Output module(s)\n" \
46: " -f, --configfile=PATH Alternative path to configuration file\n" \
47: " -h, --help Show this help text\n" \
48: " -V, --version Show version\n" \
49: "\n" \
50: "Input:\n" \
51: " -p, --policy=POLICY Element display policy (see below)\n" \
52: " -a, --show-all Show all elements (even disabled elements)\n" \
53: " -r, --read-interval=FLOAT Read interval in seconds (float)\n" \
54: " -R, --rate-interval=FLOAT Rate interval in seconds (float)\n" \
55: " -s, --sleep-interval=FLOAT Sleep time in seconds (float)\n" \
56: " -L, --lifetime=LIFETIME Lifetime of an element in seconds (float)\n" \
57: "\n" \
58: "Output:\n" \
59: " -U, --use-si Use SI units\n" \
60: " -b, --use-bit Display in bits instead of bytes\n" \
61: "\n" \
62: "Module configuration:\n" \
63: " modparm := MODULE:optlist,MODULE:optlist,...\n" \
64: " optlist := option;option;...\n" \
65: " option := TYPE[=VALUE]\n" \
66: "\n" \
67: " Examples:\n" \
68: " -o curses:ngraph=2\n" \
69: " -o list # Shows a list of available modules\n" \
70: " -o curses:help # Shows a help text for html module\n" \
71: "\n" \
72: "Interface selection:\n" \
73: " policy := [!]simple_regexp,[!]simple_regexp,...\n" \
74: "\n" \
75: " Example: -p 'eth*,lo*,!eth1'\n" \
76: "\n" \
77: "Please see the bmon(1) man pages for full documentation.\n";
78:
79: static void do_shutdown(void)
80: {
81: static int done;
82:
83: if (!done) {
84: done = 1;
85: module_shutdown();
86: }
87: }
88:
89: static void sig_exit(void)
90: {
91: do_shutdown();
92: }
93:
94: void quit(const char *fmt, ...)
95: {
96: static int done;
97: va_list args;
98:
99: va_start(args, fmt);
100: vfprintf(stderr, fmt, args);
101: va_end(args);
102:
103: if (!done) {
104: done = 1;
105: do_shutdown();
106: }
107:
108: exit(1);
109: }
110:
111: static inline void print_version(void)
112: {
113: printf("bmon %s\n", PACKAGE_VERSION);
114: printf("Copyright (C) 2001-2015 by Thomas Graf <tgraf@suug.ch>\n");
115: printf("Copyright (C) 2013 Red Hat, Inc.\n");
116: printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \
117: "software, and you\nare welcome to redistribute it under " \
118: "certain conditions. See the source\ncode for details.\n");
119: }
120:
121: static void parse_args_pre(int argc, char *argv[])
122: {
123: DBG("Parsing arguments pre state");
124:
125: for (;;)
126: {
127: char *gostr = "+:hvVf:";
128:
129: struct option long_opts[] = {
130: {"help", 0, NULL, 'h'},
131: {"version", 0, NULL, 'v'},
132: {"configfile", 1, NULL, 'f'},
133: {NULL, 0, NULL, 0},
134: };
135: int c = getopt_long(argc, argv, gostr, long_opts, NULL);
136: if (c == -1)
137: break;
138:
139: switch (c)
140: {
141: case 'f':
142: set_configfile(optarg);
143: break;
144:
145: case 'h':
146: print_version();
147: printf("\n%s", usage_text);
148: exit(1);
149: case 'V':
150: case 'v':
151: print_version();
152: exit(0);
153: }
154: }
155: }
156:
157: static int parse_args_post(int argc, char *argv[])
158: {
159: DBG("Parsing arguments post state");
160:
161: optind = 1;
162:
163: for (;;)
164: {
165: char *gostr = "i:o:p:r:R:s:aUb" \
166: "L:hvVf:";
167:
168: struct option long_opts[] = {
169: {"input", 1, NULL, 'i'},
170: {"output", 1, NULL, 'o'},
171: {"policy", 1, NULL, 'p'},
172: {"read-interval", 1, NULL, 'r'},
173: {"rate-interval", 1, NULL, 'R'},
174: {"sleep-interval", 1, NULL, 's'},
175: {"show-all", 0, NULL, 'a'},
176: {"use-si", 0, NULL, 'U'},
177: {"use-bit", 0, NULL, 'b'},
178: {"lifetime", 1, NULL, 'L'},
179: {NULL, 0, NULL, 0},
180: };
181: int c = getopt_long(argc, argv, gostr, long_opts, NULL);
182: if (c == -1)
183: break;
184:
185: switch (c)
186: {
187: case 'i':
188: if (input_set(optarg))
189: return 1;
190: break;
191:
192: case 'o':
193: if (output_set(optarg))
194: return 1;
195: break;
196:
197: case 'p':
198: cfg_setstr(cfg, "policy", optarg);
199: break;
200:
201: case 'r':
202: cfg_setfloat(cfg, "read_interval", strtod(optarg, NULL));
203: break;
204:
205: case 'R':
206: cfg_setfloat(cfg, "rate_interval", strtod(optarg, NULL));
207: break;
208:
209: case 's':
210: cfg_setint(cfg, "sleep_time", strtoul(optarg, NULL, 0));
211: break;
212:
213: case 'a':
214: cfg_setbool(cfg, "show_all", cfg_true);
215: break;
216:
217: case 'U':
218: cfg_setbool(cfg, "use_si", cfg_true);
219: break;
220:
221: case 'b':
222: cfg_setbool(cfg, "use_bit", cfg_true);
223: break;
224:
225: case 'L':
226: cfg_setint(cfg, "lifetime", strtoul(optarg, NULL, 0));
227: break;
228:
229: case 'f':
230: /* Already handled in pre getopt loop */
231: break;
232:
233: default:
234: quit("Aborting...\n");
235: break;
236:
237: }
238: }
239:
240: return 0;
241: }
242:
243: #if 0
244: static void calc_variance(timestamp_t *c, timestamp_t *ri)
245: {
246: float v = (ts_to_float(c) / ts_to_float(ri)) * 100.0f;
247:
248: rtiming.rt_variance.v_error = v;
249: rtiming.rt_variance.v_total += v;
250:
251: if (v > rtiming.rt_variance.v_max)
252: rtiming.rt_variance.v_max = v;
253:
254: if (v < rtiming.rt_variance.v_min)
255: rtiming.rt_variance.v_min = v;
256: }
257: #endif
258:
259: int main(int argc, char *argv[])
260: {
261: unsigned long sleep_time;
262: double read_interval;
263:
264: start_time = time(NULL);
265: memset(&rtiming, 0, sizeof(rtiming));
266: rtiming.rt_variance.v_min = FLT_MAX;
267:
268: /*
269: * Early initialization before reading config
270: */
271: conf_init_pre();
272: parse_args_pre(argc, argv);
273:
274: /*
275: * Reading the configuration file */
276: configfile_read();
277:
278: /*
279: * Late initialization after reading config
280: */
281: if (parse_args_post(argc, argv))
282: return 1;
283: conf_init_post();
284:
285: module_init();
286:
287: read_interval = cfg_read_interval;
288: sleep_time = cfg_getint(cfg, "sleep_time");
289:
290: if (((double) sleep_time / 1000000.0f) > read_interval)
291: sleep_time = (unsigned long) (read_interval * 1000000.0f);
292:
293: DBG("Entering mainloop...");
294:
295: do {
296: /*
297: * E := Elapsed time
298: * NR := Next Read
299: * LR := Last Read
300: * RI := Read Interval
301: * ST := Sleep Time
302: * C := Correction
303: */
304: timestamp_t e, ri, tmp;
305: unsigned long st;
306:
307: float_to_timestamp(&ri, read_interval);
308:
309: /*
310: * NR := NOW
311: */
312: update_timestamp(&rtiming.rt_next_read);
313:
314: for (;;) {
315: output_pre();
316:
317: /*
318: * E := NOW
319: */
320: update_timestamp(&e);
321:
322: /*
323: * IF NR <= E THEN
324: */
325: if (timestamp_le(&rtiming.rt_next_read, &e)) {
326: timestamp_t c;
327:
328: /*
329: * C := (NR - E)
330: */
331: timestamp_sub(&c, &rtiming.rt_next_read, &e);
332:
333: //calc_variance(&c, &ri);
334:
335: /*
336: * LR := E
337: */
338: copy_timestamp(&rtiming.rt_last_read, &e);
339:
340: /*
341: * NR := E + RI + C
342: */
343: timestamp_add(&rtiming.rt_next_read, &e, &ri);
344: timestamp_add(&rtiming.rt_next_read,
345: &rtiming.rt_next_read, &c);
346:
347:
348: reset_update_flags();
349: input_read();
350: free_unused_elements();
351: output_draw();
352: output_post();
353: }
354:
355: /*
356: * ST := Configured ST
357: */
358: st = sleep_time;
359:
360: /*
361: * IF (NR - E) < ST THEN
362: */
363: timestamp_sub(&tmp, &rtiming.rt_next_read, &e);
364:
365: if (tmp.tv_sec < 0)
366: continue;
367:
368: if (tmp.tv_sec == 0 && tmp.tv_usec < st) {
369: if (tmp.tv_usec < 0)
370: continue;
371: /*
372: * ST := (NR - E)
373: */
374: st = tmp.tv_usec;
375: }
376:
377: /*
378: * SLEEP(ST)
379: */
380: usleep(st);
381: }
382: } while (0);
383:
384: return 0; /* buddha says i'll never be reached */
385: }
386:
387: static void __init bmon_init(void)
388: {
389: atexit(&sig_exit);
390: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>