bmon/src/bmon.c
Thomas Graf 46ec101b00 Add -b / --use-bit option to display rates in bit/s instead of bytes/s
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-05-08 15:16:38 +02:00

404 lines
8.4 KiB
C

/*
* src/bmon.c Bandwidth Monitor
*
* Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2013 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <bmon/bmon.h>
#include <bmon/conf.h>
#include <bmon/attr.h>
#include <bmon/utils.h>
#include <bmon/input.h>
#include <bmon/output.h>
#include <bmon/module.h>
#include <bmon/group.h>
int start_time;
int do_quit = 0;
int is_daemon = 0;
struct reader_timing rtiming;
static char *usage_text =
"Usage: bmon [OPTION]...\n" \
"\n" \
"Options:\n" \
"Startup:\n" \
" -i, --input=MODPARM Input module(s)\n" \
" -o, --output=MODPARM Ouptut module(s)\n" \
" -f, --configfile=PATH Alternative path to configuration file\n" \
" -h, --help Show this help text\n" \
" -V, --version Show version\n" \
"\n" \
"Input:\n" \
" -p, --policy=POLICY Element display policy (see below)\n" \
" -a, --show-all Show all elements (even disabled elements)\n" \
" -r, --read-interval=FLOAT Read interval in seconds (float)\n" \
" -R, --rate-internval=FLOAT Rate interval in seconds (float)\n" \
" -s, --sleep-interval=FLOAT Sleep time in seconds (float)\n" \
" -L, --lifetime=LIFETIME Lifetime of an element in seconds (float)\n" \
"\n" \
"Output:\n" \
" -U, --use-si Use SI units\n" \
" -b, --use-bit Display in bits instead of btyes\n" \
"\n" \
"Module configuration:\n" \
" modparm := MODULE:optlist,MODULE:optlist,...\n" \
" optlist := option;option;...\n" \
" option := TYPE[=VALUE]\n" \
"\n" \
" Examples:\n" \
" -o curses:ngraph=2\n" \
" -o list # Shows a list of available modules\n" \
" -o curses:help # Shows a help text for html module\n" \
"\n" \
"Interface selection:\n" \
" policy := [!]simple_regexp,[!]simple_regexp,...\n" \
"\n" \
" Example: -p 'eth*,lo*,!eth1'\n" \
"\n" \
"Please see the bmon(1) man pages for full documentation.\n";
static void do_shutdown(void)
{
static int done;
if (!done) {
done = 1;
module_shutdown();
}
}
RETSIGTYPE sig_int(int unused)
{
if (do_quit)
exit(-1);
do_quit = 1;
}
void sig_exit(void)
{
do_shutdown();
}
void quit(const char *fmt, ...)
{
static int done;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (!done) {
done = 1;
do_shutdown();
}
exit(1);
}
static inline void print_version(void)
{
printf("bmon %s\n", PACKAGE_VERSION);
printf("Copyright (C) 2001-2013 by Thomas Graf <tgraf@suug.ch>\n");
printf("Copyright (C) 2013 Red Hat, Inc.\n");
printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \
"software, and you\nare welcome to redistribute it under " \
"certain conditions. See the source\ncode for details.\n");
}
static void parse_args_pre(int argc, char *argv[])
{
DBG("Parsing arguments pre state");
for (;;)
{
char *gostr = "+:hvVf:";
struct option long_opts[] = {
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
{"configfile", 1, 0, 'f'},
{0, 0, 0, 0},
};
int c = getopt_long(argc, argv, gostr, long_opts, NULL);
if (c == -1)
break;
switch (c)
{
case 'f':
set_configfile(optarg);
break;
case 'h':
print_version();
printf("\n%s", usage_text);
exit(1);
case 'V':
case 'v':
print_version();
exit(0);
}
}
}
static int parse_args_post(int argc, char *argv[])
{
DBG("Parsing arguments post state");
optind = 1;
for (;;)
{
char *gostr = "i:o:p:r:R:s:aUb" \
"L:hvVf:";
struct option long_opts[] = {
{"input", 1, 0, 'i'},
{"output", 1, 0, 'o'},
{"policy", 1, 0, 'p'},
{"read-interval", 1, 0, 'r'},
{"rate-interval", 1, 0, 'R'},
{"sleep-interval", 1, 0, 's'},
{"show-all", 0, 0, 'a'},
{"use-si", 0, 0, 'U'},
{"use-bit", 0, 0, 'b'},
{"lifetime", 1, 0, 'L'},
{0, 0, 0, 0},
};
int c = getopt_long(argc, argv, gostr, long_opts, NULL);
if (c == -1)
break;
switch (c)
{
case 'i':
if (input_set(optarg))
return 1;
break;
case 'o':
if (output_set(optarg))
return 1;
break;
case 'p':
cfg_setstr(cfg, "policy", optarg);
break;
case 'r':
cfg_setfloat(cfg, "read_interval", strtod(optarg, NULL));
break;
case 'R':
cfg_setfloat(cfg, "rate_interval", strtod(optarg, NULL));
break;
case 's':
cfg_setint(cfg, "sleep_time", strtoul(optarg, NULL, 0));
break;
case 'a':
cfg_setint(cfg, "show_all", 1);
break;
case 'U':
cfg_setbool(cfg, "use_si", cfg_true);
break;
case 'b':
cfg_setbool(cfg, "use_bit", cfg_true);
break;
case 'L':
cfg_setint(cfg, "lifetime", strtoul(optarg, NULL, 0));
break;
case 'f':
/* Already handled in pre getopt loop */
break;
default:
quit("Aborting...\n");
break;
}
}
return 0;
}
#if 0
static void calc_variance(timestamp_t *c, timestamp_t *ri)
{
float v = (ts_to_float(c) / ts_to_float(ri)) * 100.0f;
rtiming.rt_variance.v_error = v;
rtiming.rt_variance.v_total += v;
if (v > rtiming.rt_variance.v_max)
rtiming.rt_variance.v_max = v;
if (v < rtiming.rt_variance.v_min)
rtiming.rt_variance.v_min = v;
}
#endif
int main(int argc, char *argv[])
{
unsigned long sleep_time;
double read_interval;
start_time = time(0);
memset(&rtiming, 0, sizeof(rtiming));
rtiming.rt_variance.v_min = FLT_MAX;
/*
* Early initialization before reading config
*/
conf_init_pre();
parse_args_pre(argc, argv);
/*
* Reading the configuration file */
configfile_read();
/*
* Late initialization after reading config
*/
if (parse_args_post(argc, argv))
return 1;
conf_init_post();
module_init();
read_interval = cfg_read_interval;
sleep_time = cfg_getint(cfg, "sleep_time");
if (((double) sleep_time / 1000000.0f) > read_interval)
sleep_time = (unsigned long) (read_interval * 1000000.0f);
DBG("Entering mainloop...");
do {
/*
* E := Elapsed time
* NR := Next Read
* LR := Last Read
* RI := Read Interval
* ST := Sleep Time
* C := Correction
*/
timestamp_t e, ri, tmp;
unsigned long st;
float_to_timestamp(&ri, read_interval);
/*
* NR := NOW
*/
update_timestamp(&rtiming.rt_next_read);
for (;;) {
output_pre();
/*
* E := NOW
*/
update_timestamp(&e);
/*
* IF NR <= E THEN
*/
if (timestamp_le(&rtiming.rt_next_read, &e)) {
timestamp_t c;
/*
* C := (NR - E)
*/
timestamp_sub(&c, &rtiming.rt_next_read, &e);
//calc_variance(&c, &ri);
/*
* LR := E
*/
copy_timestamp(&rtiming.rt_last_read, &e);
/*
* NR := E + RI + C
*/
timestamp_add(&rtiming.rt_next_read, &e, &ri);
timestamp_add(&rtiming.rt_next_read,
&rtiming.rt_next_read, &c);
reset_update_flags();
input_read();
free_unused_elements();
output_draw();
output_post();
}
if (do_quit)
exit(0);
/*
* ST := Configured ST
*/
st = sleep_time;
/*
* IF (NR - E) < ST THEN
*/
timestamp_sub(&tmp, &rtiming.rt_next_read, &e);
if (tmp.tv_sec < 0)
continue;
if (tmp.tv_sec == 0 && tmp.tv_usec < st) {
if (tmp.tv_usec < 0)
continue;
/*
* ST := (NR - E)
*/
st = tmp.tv_usec;
}
/*
* SLEEP(ST)
*/
usleep(st);
}
} while (0);
return 0; /* buddha says i'll never be reached */
}
static void __init bmon_init(void)
{
atexit(&sig_exit);
//signal(SIGINT, &sig_int);
}