Initial import
This commit is contained in:
parent
924d1e1fb4
commit
3be703f67d
21
.gitignore
vendored
21
.gitignore
vendored
@ -1,17 +1,12 @@
|
||||
# Object files
|
||||
*.o
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.swp
|
||||
.deps
|
||||
Makefile.in
|
||||
Makefile
|
||||
/build-aux/
|
||||
/aclocal.m4
|
||||
/configure
|
||||
/config.*
|
||||
|
11
Makefile.am
Normal file
11
Makefile.am
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src man
|
||||
|
||||
pkgsysconfdir = $(sysconfdir)
|
||||
pkgsysconf_DATA = etc/bmon.conf
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(pkgsysconf_DATA)
|
@ -2,3 +2,8 @@ bmon
|
||||
====
|
||||
|
||||
bandwidth monitor and rate estimator
|
||||
|
||||
bmon is a monitoring and debugging tool to capture networking related
|
||||
statistics and prepare them visually in a human friendly way. It
|
||||
features various output methods including an interactive curses user
|
||||
interface and a programmable text output for scripting.
|
||||
|
4
autogen.sh
Executable file
4
autogen.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
autoreconf -fi;
|
||||
rm -Rf autom4te.cache;
|
191
configure.ac
Normal file
191
configure.ac
Normal file
@ -0,0 +1,191 @@
|
||||
#
|
||||
# configure.in Configure Script
|
||||
#
|
||||
# Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
|
||||
#
|
||||
# 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.
|
||||
|
||||
AC_INIT(bmon, 3.0-git, [], [], [http://www.infradead.org/~tgr/bmon/])
|
||||
AC_CONFIG_HEADERS(include/bmon/defs.h)
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)], [])
|
||||
|
||||
AC_ISC_POSIX
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_STDC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
|
||||
AC_HEADER_TIME
|
||||
AC_HEADER_DIRENT
|
||||
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_PID_T
|
||||
|
||||
AC_FUNC_FORK
|
||||
|
||||
AC_CHECK_HEADERS(getopt.h ncurses/ncurses.h ncurses.h curses.h)
|
||||
AC_CHECK_HEADERS(dirent.h sys/utsname.h sys/sockio.h netinet6/in6.h)
|
||||
AC_CHECK_HEADERS(fcntl.h netdb.h netinet/in.h sysctl/ioctl.h)
|
||||
AC_CHECK_HEADERS(sys/param.h sys/socket.h)
|
||||
|
||||
AC_CHECK_TYPES(suseconds_t)
|
||||
|
||||
AC_CHECK_FUNCS(atexit gettimeofday memset pow socket strcasecmp)
|
||||
AC_CHECK_FUNCS(strchr strdup strerror strncasecmp strstr strtol)
|
||||
AC_CHECK_FUNCS(uname getdate)
|
||||
|
||||
AX_WITH_CURSES
|
||||
if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then
|
||||
AC_MSG_ERROR([requires an X/Open-compatible Curses library with color])
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES([CONFUSE], [libconfuse], [], AC_MSG_ERROR([requires libconfuse]))
|
||||
|
||||
PKG_CHECK_MODULES([LIBNL], [libnl-3.0], [], AC_MSG_ERROR([requires libnl]))
|
||||
PKG_CHECK_MODULES([LIBNL_ROUTE], [libnl-route-3.0], [], AC_MSG_ERROR([requires libnl3-route]))
|
||||
|
||||
AC_CHECK_LIB(m, pow, [], AC_MSG_ERROR([requires libm]))
|
||||
|
||||
BMON_LIB=""
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## libcurses check
|
||||
##
|
||||
#####################################################################
|
||||
CURSES="No "
|
||||
AC_CHECK_LIB(ncurses, initscr, [
|
||||
AC_DEFINE_UNQUOTED(HAVE_NCURSES, "1", [have ncurses])
|
||||
LCURSES="ncurses"
|
||||
CURSES="Yes"
|
||||
],[
|
||||
AC_CHECK_LIB(curses,initscr, [
|
||||
AC_DEFINE_UNQUOTED(HAVE_CURSES, "1", [have curses])
|
||||
LCURSES="curses"
|
||||
CURSES="Yes"
|
||||
],[
|
||||
echo
|
||||
echo "*** Warning: Building bmon w/o curses support ***"
|
||||
echo
|
||||
])
|
||||
])
|
||||
|
||||
LIBCURSES="-l$LCURSES"
|
||||
|
||||
AC_CHECK_LIB($LCURSES, redrawwin, [
|
||||
AC_DEFINE_UNQUOTED(HAVE_REDRAWWIN, "1", [have redrawwin])
|
||||
])
|
||||
|
||||
AC_CHECK_LIB($LCURSES, use_default_colors, [
|
||||
AC_DEFINE_UNQUOTED(HAVE_USE_DEFAULT_COLORS, "1", [have udc])
|
||||
])
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## interface counter overflow workaround
|
||||
##
|
||||
#####################################################################
|
||||
AC_ARG_ENABLE(cnt-workaround,
|
||||
[ --disable-cnt-workaround Disables interface counter overflow workaround],[
|
||||
if test x$enableval = xno; then
|
||||
AC_DEFINE_UNQUOTED(DISABLE_OVERFLOW_WORKAROUND,"1",[no overflow workaround])
|
||||
fi
|
||||
])
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## curses
|
||||
##
|
||||
#####################################################################
|
||||
AC_ARG_ENABLE(curses,
|
||||
[ --disable-curses Disables curses output],[
|
||||
if test x$enableval = xno; then
|
||||
CURSES="No "
|
||||
fi
|
||||
])
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## debug check
|
||||
##
|
||||
#####################################################################
|
||||
DEBUG=0
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug Enable debug mode (default disabled)],[
|
||||
if test x$enableval = xyes; then
|
||||
AC_DEFINE_UNQUOTED(DEBUG, "1", [enable debugging])
|
||||
DEBUG=1;
|
||||
fi
|
||||
])
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## target os eval
|
||||
##
|
||||
#####################################################################
|
||||
case ${target_os} in
|
||||
linux*)
|
||||
AC_DEFINE_UNQUOTED(SYS_LINUX, "1", [operating system])
|
||||
;;
|
||||
|
||||
*solaris*)
|
||||
AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system])
|
||||
;;
|
||||
|
||||
*bsd*)
|
||||
AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system])
|
||||
;;
|
||||
|
||||
*darwin*)
|
||||
AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system])
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_DEFINE_UNQUOTED(SYS_OTHER, "1", [operating system])
|
||||
;;
|
||||
esac
|
||||
|
||||
#####################################################################
|
||||
##
|
||||
## export variables
|
||||
##
|
||||
#####################################################################
|
||||
AC_SUBST(DEBUG)
|
||||
AC_SUBST(STATIC)
|
||||
AC_SUBST(SYS)
|
||||
AC_SUBST(ARCH)
|
||||
|
||||
AC_SUBST(CURSES)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
man/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
81
etc/bmon.conf
Normal file
81
etc/bmon.conf
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* read_interval = 1.0
|
||||
* rate_interval = 1.0
|
||||
* variance = 0.1
|
||||
* history_variance = 0.1
|
||||
* sleep_time = 20000
|
||||
* lifetime = 30.0
|
||||
* show_all = true
|
||||
* policy = ""
|
||||
*/
|
||||
|
||||
/*
|
||||
* element eth0 {
|
||||
* description = { "My description" }
|
||||
* rxmax = { 10000 }
|
||||
* txmax = { 10000 }
|
||||
* max = { 12500000 }
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* Default configuration
|
||||
*
|
||||
* The following definitions is what is compiled into bmon and used
|
||||
* by default.
|
||||
*
|
||||
* unit byte {
|
||||
* variant default {
|
||||
* div = { 1, 1024, 1048576, 1073741824, 1099511627776}
|
||||
* txt = { "B", "KiB", "MiB", "GiB", "TiB" }
|
||||
* }
|
||||
* variant si {
|
||||
* div = { 1, 1000, 1000000, 1000000000, 1000000000000 }
|
||||
* txt = { "B", "KB", "MB", "GB", "TB" }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* unit bit {
|
||||
* variant default {
|
||||
* div = { 1, 1024, 1048576, 1073741824, 1099511627776}
|
||||
* txt = { "b", "Kib", "Mib", "Gib", "TiB" }
|
||||
* }
|
||||
* variant si {
|
||||
* div = { 1, 1000, 1000000, 1000000000, 1000000000000 }
|
||||
* txt = { "b", "Kb", "Mb", "Gb", "Tb" }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* unit number {
|
||||
* variant default {
|
||||
* div = { 1, 1000, 1000000, 1000000000, 1000000000000 }
|
||||
* txt = { "", "K", "M", "G", "T" }
|
||||
* }
|
||||
* }
|
||||
* unit percent {
|
||||
* variant default {
|
||||
* div = { 1. }
|
||||
* txt = { "%" }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* history second {
|
||||
* interval = { 1. }
|
||||
* size = { 60 }
|
||||
* }
|
||||
*
|
||||
* history minute {
|
||||
* interval = { 60. }
|
||||
* size = { 60 }
|
||||
* }
|
||||
*
|
||||
* history hour {
|
||||
* interval = { 3600. }
|
||||
* size = { 60 }
|
||||
* }
|
||||
*
|
||||
* history day {
|
||||
* interval = { 86400. }
|
||||
* size = { 60 }
|
||||
* }
|
||||
*/
|
2
include/bmon/.gitignore
vendored
Normal file
2
include/bmon/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
defs.h*
|
||||
stamp-h1
|
138
include/bmon/attr.h
Normal file
138
include/bmon/attr.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* bmon/attr.h Attributes
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_ATTR_H_
|
||||
#define __BMON_ATTR_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/unit.h>
|
||||
|
||||
struct element;
|
||||
|
||||
struct rate
|
||||
{
|
||||
/* Total value of attribute with eventual overflows accumulated. */
|
||||
uint64_t r_total;
|
||||
|
||||
/* Current value of counter */
|
||||
uint64_t r_current;
|
||||
|
||||
/* Value of r_current at last read */
|
||||
uint64_t r_prev;
|
||||
|
||||
/* Rate per second calculated every `rate_interval' */
|
||||
float r_rate;
|
||||
|
||||
/* Time of last calculation */
|
||||
timestamp_t r_last_calc;
|
||||
};
|
||||
|
||||
enum {
|
||||
ATTR_TYPE_UNSPEC,
|
||||
ATTR_TYPE_COUNTER,
|
||||
ATTR_TYPE_RATE,
|
||||
ATTR_TYPE_PERCENT,
|
||||
};
|
||||
|
||||
struct attr_def {
|
||||
int ad_id;
|
||||
char * ad_name;
|
||||
char * ad_description;
|
||||
int ad_type;
|
||||
int ad_flags;
|
||||
struct unit * ad_unit;
|
||||
|
||||
struct list_head ad_list;
|
||||
};
|
||||
|
||||
struct attr_map {
|
||||
const char * name;
|
||||
const char * description;
|
||||
const char * unit;
|
||||
int attrid,
|
||||
type,
|
||||
rxid,
|
||||
txid,
|
||||
flags;
|
||||
};
|
||||
|
||||
extern int attr_def_add(const char *, const char *,
|
||||
struct unit *, int, int);
|
||||
extern struct attr_def * attr_def_lookup(const char *);
|
||||
extern struct attr_def * attr_def_lookup_id(int);
|
||||
|
||||
extern int attr_map_load(struct attr_map *map, size_t size);
|
||||
|
||||
#define ATTR_FORCE_HISTORY 0x01 /* collect history */
|
||||
#define ATTR_IGNORE_OVERFLOWS 0x02
|
||||
#define ATTR_TRUE_64BIT 0x04
|
||||
#define ATTR_RX_ENABLED 0x08 /* has RX counter */
|
||||
#define ATTR_TX_ENABLED 0x10 /* has TX counter */
|
||||
#define ATTR_DOING_HISTORY 0x20 /* history collected */
|
||||
|
||||
struct attr
|
||||
{
|
||||
struct rate a_rx_rate,
|
||||
a_tx_rate;
|
||||
|
||||
uint8_t a_flags;
|
||||
struct attr_def * a_def;
|
||||
timestamp_t a_last_update;
|
||||
|
||||
struct list_head a_history_list;
|
||||
|
||||
struct list_head a_list;
|
||||
struct list_head a_sort_list;
|
||||
};
|
||||
|
||||
extern struct attr * attr_lookup(const struct element *, int);
|
||||
extern void attr_update(struct element *, int,
|
||||
uint64_t, uint64_t , int );
|
||||
extern void attr_notify_update(struct attr *,
|
||||
timestamp_t *);
|
||||
extern void attr_free(struct attr *);
|
||||
|
||||
extern void attr_rate2float(struct attr *,
|
||||
double *, char **, int *,
|
||||
double *, char **, int *);
|
||||
|
||||
extern void attr_calc_usage(struct attr *, float *, float *,
|
||||
uint64_t, uint64_t);
|
||||
|
||||
#define ATTR_HASH_SIZE 32
|
||||
|
||||
#define UPDATE_FLAG_RX 0x01
|
||||
#define UPDATE_FLAG_TX 0x02
|
||||
#define UPDATE_FLAG_64BIT 0x04
|
||||
|
||||
extern struct attr * attr_select_first(void);
|
||||
extern struct attr * attr_select_last(void);
|
||||
extern struct attr * attr_select_next(void);
|
||||
extern struct attr * attr_select_prev(void);
|
||||
extern struct attr * attr_current(void);
|
||||
|
||||
extern void attr_start_collecting_history(struct attr *);
|
||||
|
||||
#endif
|
82
include/bmon/bmon.h
Normal file
82
include/bmon/bmon.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* bmon.h All-include Header
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_BMON_H_
|
||||
#define __BMON_BMON_H_
|
||||
|
||||
#include <bmon/config.h>
|
||||
#include <bmon/list.h>
|
||||
|
||||
extern int start_time;
|
||||
|
||||
typedef struct timestamp_s
|
||||
{
|
||||
int64_t tv_sec;
|
||||
int64_t tv_usec;
|
||||
} timestamp_t;
|
||||
|
||||
typedef struct xdate_s
|
||||
{
|
||||
struct tm d_tm;
|
||||
unsigned int d_usec;
|
||||
} xdate_t;
|
||||
|
||||
enum {
|
||||
EMPTY_LIST = 1,
|
||||
END_OF_LIST = 2
|
||||
};
|
||||
|
||||
#define BUG() \
|
||||
do { \
|
||||
fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__); \
|
||||
assert(0); \
|
||||
exit(EINVAL); \
|
||||
} while (0);
|
||||
|
||||
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||
|
||||
#if defined __GNUC__
|
||||
#define __init __attribute__ ((constructor))
|
||||
#define __exit __attribute__ ((destructor))
|
||||
#else
|
||||
#define __init
|
||||
#define __exit
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(FMT, ARG...) \
|
||||
do { \
|
||||
fprintf(stderr, \
|
||||
"[DBG] %20s:%-4u %s: " FMT "\n", \
|
||||
__FILE__, __LINE__, \
|
||||
__PRETTY_FUNCTION__, ##ARG); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DBG(FMT, ARG...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
35
include/bmon/compile-fixes.h
Normal file
35
include/bmon/compile-fixes.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* compile_fixes.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_COMPILE_FIXES_H_
|
||||
#define __BMON_COMPILE_FIXES_H_
|
||||
|
||||
#include <bmon/defs.h>
|
||||
|
||||
#ifndef HAVE_SUSECONDS_T
|
||||
typedef long suseconds_t;
|
||||
#endif
|
||||
|
||||
#endif
|
91
include/bmon/conf.h
Normal file
91
include/bmon/conf.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* conf.h Config Crap
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_CONF_H_
|
||||
#define __BMON_CONF_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
|
||||
extern cfg_t *cfg;
|
||||
|
||||
extern float cfg_read_interval;
|
||||
extern float cfg_rate_interval;
|
||||
extern float cfg_rate_variance;
|
||||
extern float cfg_history_variance;
|
||||
extern int cfg_show_all;
|
||||
extern int cfg_unit_exp;
|
||||
|
||||
extern void conf_init_pre(void);
|
||||
extern void conf_init_post(void);
|
||||
extern void configfile_read(void);
|
||||
extern void set_configfile(const char *);
|
||||
|
||||
extern unsigned int get_lifecycles(void);
|
||||
|
||||
extern void conf_set_float(const char *, double);
|
||||
extern double conf_get_float(const char *);
|
||||
extern void conf_set_int(const char *, long);
|
||||
extern long conf_get_int(const char *);
|
||||
extern void conf_set_string(const char *, const char *);
|
||||
extern const char * conf_get_string(const char *);
|
||||
|
||||
typedef struct tv_s
|
||||
{
|
||||
char * tv_type;
|
||||
char * tv_value;
|
||||
struct list_head tv_list;
|
||||
} tv_t;
|
||||
|
||||
typedef struct module_conf_s
|
||||
{
|
||||
char * m_name;
|
||||
struct list_head m_attrs;
|
||||
struct list_head m_list;
|
||||
} module_conf_t;
|
||||
|
||||
extern int parse_module_param(const char *, struct list_head *);
|
||||
|
||||
enum {
|
||||
LAYOUT_UNSPEC,
|
||||
LAYOUT_DEFAULT,
|
||||
LAYOUT_STATUSBAR,
|
||||
LAYOUT_HEADER,
|
||||
LAYOUT_LIST,
|
||||
LAYOUT_SELECTED,
|
||||
__LAYOUT_MAX
|
||||
};
|
||||
|
||||
#define LAYOUT_MAX (__LAYOUT_MAX - 1)
|
||||
|
||||
struct layout
|
||||
{
|
||||
int l_fg,
|
||||
l_bg,
|
||||
l_attr;
|
||||
};
|
||||
|
||||
extern struct layout cfg_layout[];
|
||||
|
||||
#endif
|
158
include/bmon/config.h
Normal file
158
include/bmon/config.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* config.h Global Config
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_CONFIG_H_
|
||||
#define __BMON_CONFIG_H_
|
||||
|
||||
#include <bmon/defs.h>
|
||||
#include <bmon/compile-fixes.h>
|
||||
|
||||
#if STDC_HEADERS != 1
|
||||
#error "*** ERROR: ANSI C headers required for compilation ***"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/file.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <dirent.h>
|
||||
#include <values.h>
|
||||
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VFORK_H
|
||||
#include <vfork.h>
|
||||
#endif
|
||||
|
||||
#if !HAVE_WORKING_VFORK
|
||||
#define vfork fork
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#elif defined HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#else
|
||||
#error "*** ERROR: No string header file found ***"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INITTYPES_H
|
||||
#include <inittypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined HAVE_SYS_UTSNAME_H
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_NCURSESW_CURSES_H
|
||||
# include <ncursesw/curses.h>
|
||||
#elif defined HAVE_NCURSESW_H
|
||||
# include <ncursesw.h>
|
||||
#elif defined HAVE_NCURSES_CURSES_H
|
||||
# include <ncurses/curses.h>
|
||||
#elif defined HAVE_NCURSES_H
|
||||
# include <ncurses.h>
|
||||
#elif defined HAVE_CURSES_H
|
||||
# include <curses.h>
|
||||
#else
|
||||
# error "SysV or X/Open-compatible Curses header file required"
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined HAVE_NETINET6_IN6_H
|
||||
#include <netinet6/in6.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <confuse.h>
|
||||
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
|
||||
#ifndef SCNu64
|
||||
#define SCNu64 "llu"
|
||||
#endif
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
#ifndef PRId64
|
||||
#define PRId64 "lld"
|
||||
#endif
|
||||
|
||||
#ifndef PRIX64
|
||||
#define PRIX64 "X"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_GROUP "intf"
|
||||
|
||||
#endif
|
246
include/bmon/defs.h.in
Normal file
246
include/bmon/defs.h.in
Normal file
@ -0,0 +1,246 @@
|
||||
/* include/bmon/defs.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* enable debugging */
|
||||
#undef DEBUG
|
||||
|
||||
/* no overflow workaround */
|
||||
#undef DISABLE_OVERFLOW_WORKAROUND
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
|
||||
/* have curses */
|
||||
#undef HAVE_CURSES
|
||||
|
||||
/* Define to 1 if library supports color (enhanced functions) */
|
||||
#undef HAVE_CURSES_COLOR
|
||||
|
||||
/* Define to 1 if library supports X/Open Enhanced functions */
|
||||
#undef HAVE_CURSES_ENHANCED
|
||||
|
||||
/* Define to 1 if <curses.h> is present */
|
||||
#undef HAVE_CURSES_H
|
||||
|
||||
/* Define to 1 if library supports certain obsolete features */
|
||||
#undef HAVE_CURSES_OBSOLETE
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `getdate' function. */
|
||||
#undef HAVE_GETDATE
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* have ncurses */
|
||||
#undef HAVE_NCURSES
|
||||
|
||||
/* Define to 1 if the NcursesW library is present */
|
||||
#undef HAVE_NCURSESW
|
||||
|
||||
/* Define to 1 if <ncursesw/curses.h> is present */
|
||||
#undef HAVE_NCURSESW_CURSES_H
|
||||
|
||||
/* Define to 1 if <ncursesw.h> is present */
|
||||
#undef HAVE_NCURSESW_H
|
||||
|
||||
/* Define to 1 if <ncurses/curses.h> is present */
|
||||
#undef HAVE_NCURSES_CURSES_H
|
||||
|
||||
/* Define to 1 if <ncurses.h> is present */
|
||||
#undef HAVE_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
|
||||
#undef HAVE_NCURSES_NCURSES_H
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet6/in6.h> header file. */
|
||||
#undef HAVE_NETINET6_IN6_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the `pow' function. */
|
||||
#undef HAVE_POW
|
||||
|
||||
/* have redrawwin */
|
||||
#undef HAVE_REDRAWWIN
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#undef HAVE_STRNCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#undef HAVE_STRTOL
|
||||
|
||||
/* Define to 1 if the system has the type `suseconds_t'. */
|
||||
#undef HAVE_SUSECONDS_T
|
||||
|
||||
/* Define to 1 if you have the <sysctl/ioctl.h> header file. */
|
||||
#undef HAVE_SYSCTL_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#undef HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the `uname' function. */
|
||||
#undef HAVE_UNAME
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* have udc */
|
||||
#undef HAVE_USE_DEFAULT_COLORS
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* operating system */
|
||||
#undef SYS_BSD
|
||||
|
||||
/* operating system */
|
||||
#undef SYS_LINUX
|
||||
|
||||
/* operating system */
|
||||
#undef SYS_OTHER
|
||||
|
||||
/* operating system */
|
||||
#undef SYS_SUNOS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
130
include/bmon/element.h
Normal file
130
include/bmon/element.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* bmon/element.h Elements
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_ELEMENT_H_
|
||||
#define __BMON_ELEMENT_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/attr.h>
|
||||
|
||||
#define MAX_GRAPHS 32
|
||||
#define IFNAME_MAX 32
|
||||
|
||||
struct policy
|
||||
{
|
||||
char * p_rule;
|
||||
struct list_head p_list;
|
||||
};
|
||||
|
||||
struct element_cfg;
|
||||
|
||||
struct info
|
||||
{
|
||||
char * i_name;
|
||||
char * i_value;
|
||||
struct list_head i_list;
|
||||
};
|
||||
|
||||
struct element
|
||||
{
|
||||
char * e_name;
|
||||
char * e_description;
|
||||
uint32_t e_id;
|
||||
uint32_t e_flags;
|
||||
unsigned int e_lifecycles;
|
||||
unsigned int e_level; /* recursion level */
|
||||
|
||||
struct element * e_parent;
|
||||
struct element_group * e_group;
|
||||
|
||||
struct list_head e_list;
|
||||
struct list_head e_childs;
|
||||
|
||||
unsigned int e_nattrs;
|
||||
struct list_head e_attrhash[ATTR_HASH_SIZE];
|
||||
struct list_head e_attr_sorted;
|
||||
|
||||
unsigned int e_ninfo;
|
||||
struct list_head e_info_list;
|
||||
|
||||
struct attr_def * e_key_attr[__GT_MAX];
|
||||
struct attr_def * e_usage_attr;
|
||||
|
||||
float e_rx_usage,
|
||||
e_tx_usage;
|
||||
|
||||
struct element_cfg * e_cfg;
|
||||
|
||||
struct attr * e_current_attr;
|
||||
};
|
||||
|
||||
#define ELEMENT_CREAT (1 << 0)
|
||||
|
||||
extern struct element * element_lookup(struct element_group *,
|
||||
const char *, uint32_t,
|
||||
struct element *, int);
|
||||
|
||||
extern void element_free(struct element *);
|
||||
|
||||
extern void element_reset_update_flag(struct element_group *,
|
||||
struct element *,
|
||||
void *);
|
||||
extern void element_notify_update(struct element *,
|
||||
timestamp_t *);
|
||||
extern void element_lifesign(struct element *, int);
|
||||
extern void element_check_if_dead(struct element_group *,
|
||||
struct element *, void *);
|
||||
|
||||
extern int element_set_key_attr(struct element *, const char *, const char *);
|
||||
extern int element_set_usage_attr(struct element *, const char *);
|
||||
|
||||
#define ELEMENT_FLAG_FOLDED (1 << 0)
|
||||
#define ELEMENT_FLAG_UPDATED (1 << 1)
|
||||
#define ELEMENT_FLAG_EXCLUDE (1 << 2)
|
||||
#define ELEMENT_FLAG_CREATED (1 << 3)
|
||||
|
||||
extern void element_foreach_attr(struct element *,
|
||||
void (*cb)(struct element *,
|
||||
struct attr *, void *),
|
||||
void *);
|
||||
|
||||
extern struct element * element_current(void);
|
||||
extern struct element * element_select_first(void);
|
||||
extern struct element * element_select_last(void);
|
||||
extern struct element * element_select_next(void);
|
||||
extern struct element * element_select_prev(void);
|
||||
|
||||
extern int element_allowed(const char *, struct element_cfg *);
|
||||
extern void element_parse_policy(const char *);
|
||||
|
||||
extern void element_update_info(struct element *,
|
||||
const char *,
|
||||
const char *);
|
||||
|
||||
extern void element_set_txmax(struct element *, uint64_t);
|
||||
extern void element_set_rxmax(struct element *, uint64_t);
|
||||
|
||||
#endif
|
53
include/bmon/element_cfg.h
Normal file
53
include/bmon/element_cfg.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* element_cfg.h Element Configuration
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_ELEMENT_CFG_H_
|
||||
#define __BMON_ELEMENT_CFG_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/conf.h>
|
||||
|
||||
#define ELEMENT_CFG_SHOW (1 << 0)
|
||||
#define ELEMENT_CFG_HIDE (1 << 1)
|
||||
|
||||
struct element_cfg
|
||||
{
|
||||
char * ec_name; /* Name of element config */
|
||||
char * ec_parent; /* Name of parent */
|
||||
char * ec_description; /* Human readable description */
|
||||
uint64_t ec_rxmax; /* Maximum RX value expected */
|
||||
uint64_t ec_txmax; /* Minimum TX value expected */
|
||||
unsigned int ec_flags; /* Flags */
|
||||
|
||||
struct list_head ec_list; /* Internal, do not modify */
|
||||
int ec_refcnt; /* Internal, do not modify */
|
||||
};
|
||||
|
||||
extern struct element_cfg * element_cfg_alloc(const char *);
|
||||
extern struct element_cfg * element_cfg_create(const char *);
|
||||
extern void element_cfg_free(struct element_cfg *);
|
||||
extern struct element_cfg * element_cfg_lookup(const char *);
|
||||
|
||||
#endif
|
72
include/bmon/graph.h
Normal file
72
include/bmon/graph.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* bmon/graph.h Graph creation utility
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_GRAPH_H_
|
||||
#define __BMON_GRAPH_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/unit.h>
|
||||
|
||||
struct history;
|
||||
|
||||
struct graph_cfg {
|
||||
int gc_height,
|
||||
gc_width,
|
||||
gc_flags;
|
||||
|
||||
char gc_background,
|
||||
gc_foreground,
|
||||
gc_noise,
|
||||
gc_unknown;
|
||||
|
||||
struct unit * gc_unit;
|
||||
};
|
||||
|
||||
struct graph_table {
|
||||
char * gt_table;
|
||||
char * gt_y_unit;
|
||||
float * gt_scale;
|
||||
};
|
||||
|
||||
struct graph {
|
||||
struct graph_cfg g_cfg;
|
||||
struct graph_table g_rx,
|
||||
g_tx;
|
||||
|
||||
struct list_head g_list;
|
||||
};
|
||||
|
||||
extern void graph_free(struct graph *);
|
||||
extern struct graph * graph_alloc(struct history *, struct graph_cfg *);
|
||||
extern void graph_refill(struct graph *, struct history *);
|
||||
|
||||
extern size_t graph_row_size(struct graph_cfg *);
|
||||
|
||||
extern void new_graph(void);
|
||||
extern void del_graph(void);
|
||||
extern int next_graph(void);
|
||||
extern int prev_graph(void);
|
||||
|
||||
#endif
|
100
include/bmon/group.h
Normal file
100
include/bmon/group.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* bmon/group.h Group Management
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_GROUP_H_
|
||||
#define __BMON_GROUP_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
|
||||
struct element;
|
||||
|
||||
enum {
|
||||
GT_MAJOR,
|
||||
GT_MINOR,
|
||||
__GT_MAX,
|
||||
};
|
||||
|
||||
#define GT_MAX (__GT_MAX - 1)
|
||||
|
||||
#define GROUP_COL_MAX (__GT_MAX * 2)
|
||||
|
||||
struct group_hdr
|
||||
{
|
||||
char * gh_name;
|
||||
char * gh_title;
|
||||
char * gh_column[GROUP_COL_MAX];
|
||||
struct list_head gh_list;
|
||||
};
|
||||
|
||||
extern struct group_hdr * group_lookup_hdr(const char *);
|
||||
extern int group_new_hdr(const char *, const char *,
|
||||
const char *, const char *,
|
||||
const char *, const char *);
|
||||
extern int group_new_derived_hdr(const char *,
|
||||
const char *,
|
||||
const char *);
|
||||
|
||||
struct element_group
|
||||
{
|
||||
char * g_name;
|
||||
struct group_hdr * g_hdr;
|
||||
|
||||
struct list_head g_elements;
|
||||
unsigned int g_nelements;
|
||||
|
||||
/* Currently selected element in this group */
|
||||
struct element * g_current;
|
||||
|
||||
struct list_head g_list;
|
||||
};
|
||||
|
||||
#define GROUP_CREATE 1
|
||||
|
||||
extern struct element_group * group_lookup(const char *, int);
|
||||
extern void reset_update_flags(void);
|
||||
extern void free_unused_elements(void);
|
||||
extern void calc_rates(void);
|
||||
|
||||
extern void group_foreach(
|
||||
void (*cb)(struct element_group *,
|
||||
void *),
|
||||
void *);
|
||||
extern void group_foreach_recursive(
|
||||
void (*cb)(struct element_group *,
|
||||
struct element *, void *),
|
||||
void *);
|
||||
|
||||
extern void group_foreach_element(struct element_group *,
|
||||
void (*cb)(struct element_group *,
|
||||
struct element *, void *),
|
||||
void *);
|
||||
|
||||
extern struct element_group * group_current(void);
|
||||
extern struct element_group * group_select_first(void);
|
||||
extern struct element_group * group_select_last(void);
|
||||
extern struct element_group * group_select_next(void);
|
||||
extern struct element_group * group_select_prev(void);
|
||||
|
||||
#endif
|
93
include/bmon/history.h
Normal file
93
include/bmon/history.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* bmon/history.h History Management
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_HISTORY_H_
|
||||
#define __BMON_HISTORY_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/attr.h>
|
||||
|
||||
#define HISTORY_UNKNOWN ((uint64_t) -1)
|
||||
#define HBEAT_TRIGGER 60.0f
|
||||
|
||||
enum {
|
||||
HISTORY_TYPE_8 = 1,
|
||||
HISTORY_TYPE_16 = 2,
|
||||
HISTORY_TYPE_32 = 4,
|
||||
HISTORY_TYPE_64 = 8,
|
||||
};
|
||||
|
||||
struct history_def
|
||||
{
|
||||
char * hd_name;
|
||||
int hd_size,
|
||||
hd_type;
|
||||
float hd_interval;
|
||||
|
||||
struct list_head hd_list;
|
||||
};
|
||||
|
||||
struct history_store
|
||||
{
|
||||
/* TODO? store error ratio? */
|
||||
void * hs_data;
|
||||
uint64_t hs_prev_total;
|
||||
};
|
||||
|
||||
struct history
|
||||
{
|
||||
/* index to current entry in data array */
|
||||
int h_index;
|
||||
struct history_def * h_definition;
|
||||
/* time of last history update */
|
||||
timestamp_t h_last_update;
|
||||
struct list_head h_list;
|
||||
|
||||
float h_min_interval,
|
||||
h_max_interval;
|
||||
|
||||
struct history_store h_rx,
|
||||
h_tx;
|
||||
|
||||
};
|
||||
|
||||
extern struct history_def * history_def_lookup(const char *);
|
||||
extern struct history_def * history_def_alloc(const char *);
|
||||
|
||||
extern uint64_t history_data(struct history *,
|
||||
struct history_store *, int);
|
||||
extern void history_update(struct attr *,
|
||||
struct history *, timestamp_t *);
|
||||
extern struct history * history_alloc(struct history_def *);
|
||||
extern void history_free(struct history *);
|
||||
extern void history_attach(struct attr *);
|
||||
|
||||
extern struct history_def * history_select_first(void);
|
||||
extern struct history_def * history_select_last(void);
|
||||
extern struct history_def * history_select_next(void);
|
||||
extern struct history_def * history_select_prev(void);
|
||||
extern struct history_def * history_current(void);
|
||||
|
||||
#endif
|
42
include/bmon/info.h
Normal file
42
include/bmon/info.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* bmon/info.h Info Attributes
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_INFO_H_
|
||||
#define __BMON_INFO_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/unit.h>
|
||||
|
||||
struct element;
|
||||
|
||||
struct info
|
||||
{
|
||||
char * i_name;
|
||||
char * i_value;
|
||||
|
||||
struct list_head i_list;
|
||||
};
|
||||
|
||||
#endif
|
52
include/bmon/input.h
Normal file
52
include/bmon/input.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* input.h Input API
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_INPUT_H_
|
||||
#define __BMON_INPUT_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/module.h>
|
||||
|
||||
extern int input_set(const char *);
|
||||
extern void input_register(struct bmon_module *);
|
||||
extern void input_read(void);
|
||||
|
||||
struct reader_timing
|
||||
{
|
||||
timestamp_t rt_last_read; /* timestamp taken before read */
|
||||
timestamp_t rt_next_read; /* estimated next read */
|
||||
|
||||
struct {
|
||||
float v_error;
|
||||
float v_max;
|
||||
float v_min;
|
||||
float v_total;
|
||||
} rt_variance;
|
||||
};
|
||||
|
||||
extern struct reader_timing rtiming;
|
||||
|
||||
#endif
|
93
include/bmon/list.h
Normal file
93
include/bmon/list.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* bmon/list.h Kernel List Implementation
|
||||
*
|
||||
* Copied and adapted from the kernel sources
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BMON_LIST_H_
|
||||
#define BMON_LIST_H_
|
||||
|
||||
struct list_head
|
||||
{
|
||||
struct list_head * next;
|
||||
struct list_head * prev;
|
||||
};
|
||||
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
static inline void __list_add(struct list_head *obj, struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
prev->next = obj;
|
||||
obj->prev = prev;
|
||||
next->prev = obj;
|
||||
obj->next = next;
|
||||
}
|
||||
|
||||
static inline void list_add_tail(struct list_head *obj, struct list_head *head)
|
||||
{
|
||||
__list_add(obj, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void list_add_head(struct list_head *obj, struct list_head *head)
|
||||
{
|
||||
__list_add(obj, head, head->next);
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *obj)
|
||||
{
|
||||
obj->next->prev = obj->prev;
|
||||
obj->prev->next = obj->next;
|
||||
}
|
||||
|
||||
static inline int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
|
||||
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
#define list_at_tail(pos, head, member) \
|
||||
((pos)->member.next == (head))
|
||||
|
||||
#define list_at_head(pos, head, member) \
|
||||
((pos)->member.prev == (head))
|
||||
|
||||
#define LIST_SELF(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = { &(name), &(name) }
|
||||
|
||||
#define list_first_entry(head, type, member) \
|
||||
list_entry((head)->next, type, member)
|
||||
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
&(pos)->member != (head); \
|
||||
(pos) = list_entry((pos)->member.next, typeof(*(pos)), member))
|
||||
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&(pos)->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
#define init_list_head(head) \
|
||||
do { (head)->next = (head); (head)->prev = (head); } while (0)
|
||||
|
||||
#endif
|
75
include/bmon/module.h
Normal file
75
include/bmon/module.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* module.h Module API
|
||||
*
|
||||
* Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_MODULE_H_
|
||||
#define __BMON_MODULE_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/conf.h>
|
||||
|
||||
#define BMON_MODULE_ENABLED 1
|
||||
#define BMON_MODULE_DEFAULT 2
|
||||
|
||||
struct bmon_module
|
||||
{
|
||||
char * m_name;
|
||||
|
||||
int (*m_init)(void);
|
||||
int (*m_probe)(void);
|
||||
void (*m_shutdown)(void);
|
||||
|
||||
void (*m_parse_opt)(const char *, const char *);
|
||||
|
||||
void (*m_pre)(void);
|
||||
void (*m_do)(void);
|
||||
void (*m_post)(void);
|
||||
|
||||
int m_flags;
|
||||
struct list_head m_list;
|
||||
};
|
||||
|
||||
struct bmon_subsys
|
||||
{
|
||||
char * s_name;
|
||||
int s_nmod;
|
||||
struct list_head s_mod_list;
|
||||
|
||||
void (*s_activate_default)(void);
|
||||
|
||||
struct list_head s_list;
|
||||
};
|
||||
|
||||
extern void module_foreach_run_enabled_pre(struct bmon_subsys *);
|
||||
extern void module_foreach_run_enabled(struct bmon_subsys *);
|
||||
extern void module_foreach_run_enabled_post(struct bmon_subsys *);
|
||||
|
||||
extern void module_register(struct bmon_subsys *, struct bmon_module *);
|
||||
extern int module_set(struct bmon_subsys *, const char *);
|
||||
|
||||
extern void module_init(void);
|
||||
extern void module_shutdown(void);
|
||||
extern void module_register_subsys(struct bmon_subsys *);
|
||||
|
||||
#endif
|
39
include/bmon/output.h
Normal file
39
include/bmon/output.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* output.h Output API
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_OUTPUT_H_
|
||||
#define __BMON_OUTPUT_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/module.h>
|
||||
|
||||
extern void output_register(struct bmon_module *);
|
||||
extern int output_set(const char *);
|
||||
extern void output_pre(void);
|
||||
extern void output_draw(void);
|
||||
extern void output_post(void);
|
||||
|
||||
#endif
|
68
include/bmon/unit.h
Normal file
68
include/bmon/unit.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* bmon/unit.h Units
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_UNIT_H_
|
||||
#define __BMON_UNIT_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
|
||||
#define DYNAMIC_EXP (-1)
|
||||
|
||||
enum {
|
||||
UNIT_DEFAULT,
|
||||
UNIT_SI,
|
||||
__UNIT_MAX,
|
||||
};
|
||||
|
||||
#define UNIT_MAX (__UNIT_MAX - 1)
|
||||
|
||||
#define UNIT_BYTE "byte"
|
||||
#define UNIT_NUMBER "number"
|
||||
|
||||
struct fraction {
|
||||
uint64_t f_divisor;
|
||||
char * f_name;
|
||||
|
||||
struct list_head f_list;
|
||||
};
|
||||
|
||||
struct unit {
|
||||
char * u_name;
|
||||
struct list_head u_div[__UNIT_MAX];
|
||||
|
||||
struct list_head u_list;
|
||||
};
|
||||
|
||||
extern struct unit * unit_lookup(const char *);
|
||||
extern struct unit * unit_add(const char *name);
|
||||
extern void unit_add_div(struct unit *, int, const char *, float);
|
||||
extern uint64_t unit_divisor(uint64_t, struct unit *, char **, int *);
|
||||
extern double unit_value2str(uint64_t, struct unit *, char **, int *);
|
||||
extern void fraction_free(struct fraction *);
|
||||
|
||||
extern char * unit_bytes2str(uint64_t, char *, size_t);
|
||||
extern char * unit_bit2str(uint64_t, char *, size_t);
|
||||
|
||||
#endif
|
102
include/bmon/utils.h
Normal file
102
include/bmon/utils.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* utils.h General purpose utilities
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BMON_UTILS_H_
|
||||
#define __BMON_UTILS_H_
|
||||
|
||||
#include <bmon/bmon.h>
|
||||
|
||||
extern void * xcalloc(size_t, size_t);
|
||||
extern void * xrealloc(void *, size_t);
|
||||
extern void xfree(void *);
|
||||
extern void quit (const char *, ...);
|
||||
|
||||
extern float timestamp_to_float(timestamp_t *);
|
||||
extern int64_t timestamp_to_int(timestamp_t *);
|
||||
|
||||
extern void float_to_timestamp(timestamp_t *, float);
|
||||
extern void int_to_timestamp(timestamp_t *, int);
|
||||
|
||||
extern void timestamp_add(timestamp_t *, timestamp_t *, timestamp_t *);
|
||||
extern void timestamp_sub(timestamp_t *, timestamp_t *, timestamp_t *);
|
||||
|
||||
extern int timestamp_le(timestamp_t *, timestamp_t *);
|
||||
extern int timestamp_is_negative(timestamp_t *ts);
|
||||
|
||||
extern void update_timestamp(timestamp_t *);
|
||||
extern void copy_timestamp(timestamp_t *, timestamp_t *);
|
||||
|
||||
extern float timestamp_diff(timestamp_t *, timestamp_t *);
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define xntohll(N) (N)
|
||||
#define xhtonll(N) (N)
|
||||
#else
|
||||
#define xntohll(N) ((((uint64_t) ntohl(N)) << 32) + ntohl((N) >> 32))
|
||||
#define xhtonll(N) ((((uint64_t) htonl(N)) << 32) + htonl((N) >> 32))
|
||||
#endif
|
||||
|
||||
enum {
|
||||
U_NUMBER,
|
||||
U_BYTES,
|
||||
U_BITS
|
||||
};
|
||||
|
||||
extern float read_delta;
|
||||
|
||||
|
||||
const char * xinet_ntop(struct sockaddr *, char *, socklen_t);
|
||||
|
||||
|
||||
extern float time_diff(timestamp_t *, timestamp_t *);
|
||||
extern float diff_now(timestamp_t *);
|
||||
|
||||
extern uint64_t parse_size(const char *);
|
||||
|
||||
extern int parse_date(const char *str, xdate_t *dst);
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
extern char *strdup(const char *);
|
||||
#endif
|
||||
|
||||
extern char * timestamp2str(timestamp_t *ts, char *buf, size_t len);
|
||||
|
||||
static inline char *xstrncat(char *dest, const char *src, size_t n)
|
||||
{
|
||||
return strncat(dest, src, n - strlen(dest) - 1);
|
||||
}
|
||||
|
||||
static inline void xdate_to_ts(timestamp_t *dst, xdate_t *src)
|
||||
{
|
||||
dst->tv_sec = mktime(&src->d_tm);
|
||||
dst->tv_usec = src->d_usec;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
518
m4/ax_with_curses.m4
Normal file
518
m4/ax_with_curses.m4
Normal file
@ -0,0 +1,518 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_with_curses.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro checks whether a SysV or X/Open-compatible Curses library is
|
||||
# present, along with the associated header file. The NcursesW
|
||||
# (wide-character) library is searched for first, followed by Ncurses,
|
||||
# then the system-default plain Curses. The first library found is the
|
||||
# one returned.
|
||||
#
|
||||
# The following options are understood: --with-ncursesw, --with-ncurses,
|
||||
# --without-ncursesw, --without-ncurses. The "--with" options force the
|
||||
# macro to use that particular library, terminating with an error if not
|
||||
# found. The "--without" options simply skip the check for that library.
|
||||
# The effect on the search pattern is:
|
||||
#
|
||||
# (no options) - NcursesW, Ncurses, Curses
|
||||
# --with-ncurses --with-ncursesw - NcursesW only [*]
|
||||
# --without-ncurses --with-ncursesw - NcursesW only [*]
|
||||
# --with-ncursesw - NcursesW only [*]
|
||||
# --with-ncurses --without-ncursesw - Ncurses only [*]
|
||||
# --with-ncurses - NcursesW, Ncurses [**]
|
||||
# --without-ncurses --without-ncursesw - Curses only
|
||||
# --without-ncursesw - Ncurses, Curses
|
||||
# --without-ncurses - NcursesW, Curses
|
||||
#
|
||||
# [*] If the library is not found, abort the configure script.
|
||||
#
|
||||
# [**] If the second library (Ncurses) is not found, abort configure.
|
||||
#
|
||||
# The following preprocessor symbols may be defined by this macro if the
|
||||
# appropriate conditions are met:
|
||||
#
|
||||
# HAVE_CURSES - if any SysV or X/Open Curses library found
|
||||
# HAVE_CURSES_ENHANCED - if library supports X/Open Enhanced functions
|
||||
# HAVE_CURSES_COLOR - if library supports color (enhanced functions)
|
||||
# HAVE_CURSES_OBSOLETE - if library supports certain obsolete features
|
||||
# HAVE_NCURSESW - if NcursesW (wide char) library is to be used
|
||||
# HAVE_NCURSES - if the Ncurses library is to be used
|
||||
#
|
||||
# HAVE_CURSES_H - if <curses.h> is present and should be used
|
||||
# HAVE_NCURSESW_H - if <ncursesw.h> should be used
|
||||
# HAVE_NCURSES_H - if <ncurses.h> should be used
|
||||
# HAVE_NCURSESW_CURSES_H - if <ncursesw/curses.h> should be used
|
||||
# HAVE_NCURSES_CURSES_H - if <ncurses/curses.h> should be used
|
||||
#
|
||||
# (These preprocessor symbols are discussed later in this document.)
|
||||
#
|
||||
# The following output variable is defined by this macro; it is precious
|
||||
# and may be overridden on the ./configure command line:
|
||||
#
|
||||
# CURSES_LIB - library to add to xxx_LDADD
|
||||
#
|
||||
# The library listed in CURSES_LIB is NOT added to LIBS by default. You
|
||||
# need to add CURSES_LIB to the appropriate xxx_LDADD line in your
|
||||
# Makefile.am. For example:
|
||||
#
|
||||
# prog_LDADD = @CURSES_LIB@
|
||||
#
|
||||
# If CURSES_LIB is set on the configure command line (such as by running
|
||||
# "./configure CURSES_LIB=-lmycurses"), then the only header searched for
|
||||
# is <curses.h>. The user may use the CPPFLAGS precious variable to
|
||||
# override the standard #include search path. If the user needs to
|
||||
# specify an alternative path for a library (such as for a non-standard
|
||||
# NcurseW), the user should use the LDFLAGS variable.
|
||||
#
|
||||
# The following shell variables may be defined by this macro:
|
||||
#
|
||||
# ax_cv_curses - set to "yes" if any Curses library found
|
||||
# ax_cv_curses_enhanced - set to "yes" if Enhanced functions present
|
||||
# ax_cv_curses_color - set to "yes" if color functions present
|
||||
# ax_cv_curses_obsolete - set to "yes" if obsolete features present
|
||||
#
|
||||
# ax_cv_ncursesw - set to "yes" if NcursesW library found
|
||||
# ax_cv_ncurses - set to "yes" if Ncurses library found
|
||||
# ax_cv_plaincurses - set to "yes" if plain Curses library found
|
||||
# ax_cv_curses_which - set to "ncursesw", "ncurses", "plaincurses" or "no"
|
||||
#
|
||||
# These variables can be used in your configure.ac to determine the level
|
||||
# of support you need from the Curses library. For example, if you must
|
||||
# have either Ncurses or NcursesW, you could include:
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
# if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
|
||||
# AX_MSG_ERROR([requires either NcursesW or Ncurses library])
|
||||
# fi
|
||||
#
|
||||
# If any Curses library will do (but one must be present and must support
|
||||
# color), you could use:
|
||||
#
|
||||
# AX_WITH_CURSES
|
||||
# if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then
|
||||
# AC_MSG_ERROR([requires an X/Open-compatible Curses library with color])
|
||||
# fi
|
||||
#
|
||||
# Certain preprocessor symbols and shell variables defined by this macro
|
||||
# can be used to determine various features of the Curses library. In
|
||||
# particular, HAVE_CURSES and ax_cv_curses are defined if the Curses
|
||||
# library found conforms to the traditional SysV and/or X/Open Base Curses
|
||||
# definition. Any working Curses library conforms to this level.
|
||||
#
|
||||
# HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the
|
||||
# library supports the X/Open Enhanced Curses definition. In particular,
|
||||
# the wide-character types attr_t, cchar_t and wint_t, the functions
|
||||
# wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES
|
||||
# are checked. The Ncurses library does NOT conform to this definition,
|
||||
# although NcursesW does.
|
||||
#
|
||||
# HAVE_CURSES_COLOR and ax_cv_curses_color are defined if the library
|
||||
# supports color functions and macros such as COLOR_PAIR, A_COLOR,
|
||||
# COLOR_WHITE, COLOR_RED and init_pair(). These are NOT part of the
|
||||
# X/Open Base Curses definition, but are part of the Enhanced set of
|
||||
# functions. The Ncurses library DOES support these functions, as does
|
||||
# NcursesW.
|
||||
#
|
||||
# HAVE_CURSES_OBSOLETE and ax_cv_curses_obsolete are defined if the
|
||||
# library supports certain features present in SysV and BSD Curses but not
|
||||
# defined in the X/Open definition. In particular, the functions
|
||||
# getattrs(), getcurx() and getmaxx() are checked.
|
||||
#
|
||||
# To use the HAVE_xxx_H preprocessor symbols, insert the following into
|
||||
# your system.h (or equivalent) header file:
|
||||
#
|
||||
# #if defined HAVE_NCURSESW_CURSES_H
|
||||
# # include <ncursesw/curses.h>
|
||||
# #elif defined HAVE_NCURSESW_H
|
||||
# # include <ncursesw.h>
|
||||
# #elif defined HAVE_NCURSES_CURSES_H
|
||||
# # include <ncurses/curses.h>
|
||||
# #elif defined HAVE_NCURSES_H
|
||||
# # include <ncurses.h>
|
||||
# #elif defined HAVE_CURSES_H
|
||||
# # include <curses.h>
|
||||
# #else
|
||||
# # error "SysV or X/Open-compatible Curses header file required"
|
||||
# #endif
|
||||
#
|
||||
# For previous users of this macro: you should not need to change anything
|
||||
# in your configure.ac or Makefile.am, as the previous (serial 10)
|
||||
# semantics are still valid. However, you should update your system.h (or
|
||||
# equivalent) header file to the fragment shown above. You are encouraged
|
||||
# also to make use of the extended functionality provided by this version
|
||||
# of AX_WITH_CURSES, as well as in the additional macros
|
||||
# AX_WITH_CURSES_PANEL, AX_WITH_CURSES_MENU and AX_WITH_CURSES_FORM.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Mark Pulford <mark@kyne.com.au>
|
||||
# Copyright (c) 2009 Damian Pietras <daper@daper.net>
|
||||
# Copyright (c) 2012 Reuben Thomas <rrt@sc3d.org>
|
||||
# Copyright (c) 2011 John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 13
|
||||
|
||||
AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES])
|
||||
AC_DEFUN([AX_WITH_CURSES], [
|
||||
AC_ARG_VAR([CURSES_LIB], [linker library for Curses, e.g. -lcurses])
|
||||
AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses],
|
||||
[force the use of Ncurses or NcursesW])],
|
||||
[], [with_ncurses=check])
|
||||
AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw],
|
||||
[do not use NcursesW (wide character support)])],
|
||||
[], [with_ncursesw=check])
|
||||
|
||||
ax_saved_LIBS=$LIBS
|
||||
AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes],
|
||||
[ax_with_plaincurses=no], [ax_with_plaincurses=check])
|
||||
|
||||
ax_cv_curses_which=no
|
||||
|
||||
# Test for NcursesW
|
||||
|
||||
AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncursesw" != xno], [
|
||||
LIBS="$ax_saved_LIBS -lncursesw"
|
||||
|
||||
AC_CACHE_CHECK([for NcursesW wide-character library], [ax_cv_ncursesw], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_ncursesw=yes], [ax_cv_ncursesw=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncursesw" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncursesw
|
||||
CURSES_LIB="-lncursesw"
|
||||
AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
AC_CACHE_CHECK([for working ncursesw/curses.h], [ax_cv_header_ncursesw_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncursesw/curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncursesw_curses_h=yes],
|
||||
[ax_cv_header_ncursesw_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSESW_CURSES_H], [1], [Define to 1 if <ncursesw/curses.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncursesw.h], [ax_cv_header_ncursesw_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncursesw.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncursesw_h=yes],
|
||||
[ax_cv_header_ncursesw_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_h" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSESW_H], [1], [Define to 1 if <ncursesw.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h_with_ncursesw], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <ncurses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_h_with_ncursesw=yes],
|
||||
[ax_cv_header_ncurses_h_with_ncursesw=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_h_with_ncursesw" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if <ncurses.h> is present])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [
|
||||
AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
# Test for Ncurses
|
||||
|
||||
AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
LIBS="$ax_saved_LIBS -lncurses"
|
||||
|
||||
AC_CACHE_CHECK([for Ncurses library], [ax_cv_ncurses], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_ncurses=yes], [ax_cv_ncurses=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [
|
||||
AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_ncurses" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=ncurses
|
||||
CURSES_LIB="-lncurses"
|
||||
AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses/curses.h], [ax_cv_header_ncurses_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <ncurses/curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_curses_h=yes],
|
||||
[ax_cv_header_ncurses_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_CURSES_H], [1], [Define to 1 if <ncurses/curses.h> is present])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <ncurses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_header_ncurses_h=yes],
|
||||
[ax_cv_header_ncurses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_ncurses_h" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if <ncurses.h> is present])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xno && test "x$ax_cv_header_ncurses_h" = xno], [
|
||||
AC_MSG_WARN([could not find a working ncurses/curses.h or ncurses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
# Test for plain Curses (or if CURSES_LIB was set by user)
|
||||
|
||||
AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [
|
||||
AS_IF([test "x$CURSES_LIB" != x], [
|
||||
LIBS="$ax_saved_LIBS $CURSES_LIB"
|
||||
], [
|
||||
LIBS="$ax_saved_LIBS -lcurses"
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for Curses library], [ax_cv_plaincurses], [
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])],
|
||||
[ax_cv_plaincurses=yes], [ax_cv_plaincurses=no])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_plaincurses" = xyes], [
|
||||
ax_cv_curses=yes
|
||||
ax_cv_curses_which=plaincurses
|
||||
AS_IF([test "x$CURSES_LIB" = x], [
|
||||
CURSES_LIB="-lcurses"
|
||||
])
|
||||
AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present])
|
||||
|
||||
# Check for base conformance (and header file)
|
||||
|
||||
AC_CACHE_CHECK([for working curses.h], [ax_cv_header_curses_h], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
initscr();
|
||||
]])],
|
||||
[ax_cv_header_curses_h=yes],
|
||||
[ax_cv_header_curses_h=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_header_curses_h" = xyes], [
|
||||
AC_DEFINE([HAVE_CURSES_H], [1], [Define to 1 if <curses.h> is present])
|
||||
|
||||
# Check for X/Open Enhanced conformance
|
||||
|
||||
AC_CACHE_CHECK([for X/Open Enhanced Curses conformance], [ax_cv_plaincurses_enhanced], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <curses.h>
|
||||
@%:@ifndef _XOPEN_CURSES
|
||||
@%:@error "this Curses library is not enhanced"
|
||||
"this Curses library is not enhanced"
|
||||
@%:@endif
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
attr_t d = WA_NORMAL;
|
||||
cchar_t e;
|
||||
wint_t f;
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
wattr_set(stdscr, d, 0, NULL);
|
||||
wget_wch(stdscr, &f);
|
||||
]])],
|
||||
[ax_cv_plaincurses_enhanced=yes],
|
||||
[ax_cv_plaincurses_enhanced=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_enhanced" = xyes], [
|
||||
ax_cv_curses_enhanced=yes
|
||||
ax_cv_curses_color=yes
|
||||
AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions])
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
])
|
||||
|
||||
# Check for color functions
|
||||
|
||||
AC_CACHE_CHECK([for Curses color functions], [ax_cv_plaincurses_color], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@define _XOPEN_SOURCE_EXTENDED 1
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
chtype c = COLOR_PAIR(1) & A_COLOR;
|
||||
initscr();
|
||||
init_pair(1, COLOR_WHITE, COLOR_RED);
|
||||
]])],
|
||||
[ax_cv_plaincurses_color=yes],
|
||||
[ax_cv_plaincurses_color=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_color" = xyes], [
|
||||
ax_cv_curses_color=yes
|
||||
AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)])
|
||||
])
|
||||
|
||||
# Check for obsolete functions
|
||||
|
||||
AC_CACHE_CHECK([for obsolete Curses functions], [ax_cv_plaincurses_obsolete], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
@%:@include <curses.h>
|
||||
]], [[
|
||||
chtype a = A_BOLD;
|
||||
int b = KEY_LEFT;
|
||||
int g = getattrs(stdscr);
|
||||
int h = getcurx(stdscr) + getmaxx(stdscr);
|
||||
initscr();
|
||||
]])],
|
||||
[ax_cv_plaincurses_obsolete=yes],
|
||||
[ax_cv_plaincurses_obsolete=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_plaincurses_obsolete" = xyes], [
|
||||
ax_cv_curses_obsolete=yes
|
||||
AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features])
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_header_curses_h" = xno], [
|
||||
AC_MSG_WARN([could not find a working curses.h])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$ax_cv_curses" != xyes], [ax_cv_curses=no])
|
||||
AS_IF([test "x$ax_cv_curses_enhanced" != xyes], [ax_cv_curses_enhanced=no])
|
||||
AS_IF([test "x$ax_cv_curses_color" != xyes], [ax_cv_curses_color=no])
|
||||
AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no])
|
||||
|
||||
LIBS=$ax_saved_LIBS
|
||||
])dnl
|
3
man/Makefile.am
Normal file
3
man/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
dist_man8_MANS = bmon.8
|
235
man/bmon.8
Normal file
235
man/bmon.8
Normal file
@ -0,0 +1,235 @@
|
||||
.TH "bmon" "8" "" "Bandwidth Monitor" "bmon"
|
||||
.SH "NAME"
|
||||
bmon \- bandwidth monitor and rate estimator
|
||||
.SH "SYNOPSIS"
|
||||
.B bmon
|
||||
[\fB\-\-show\-all\fR]
|
||||
[\fB\-\-use\-si\fR]
|
||||
[\fB\-\-input\fR=\fIMODULE\fR]
|
||||
[\fB\-\-output\fR=\fIMODULE\fR]
|
||||
[OPTIONS...]
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
bmon is a monitoring and debugging tool to capture networking related
|
||||
statistics and prepare them visually in a human friendly way. It
|
||||
features various output methods including an interactive curses user
|
||||
interface and a programmable text output for scripting.
|
||||
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\fB -h\fR, \fB\-\-help\fR
|
||||
.RS 4
|
||||
Prints a short help text and exits\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB -V\fR, \fB\-\-version\fR
|
||||
.RS 4
|
||||
Prints the versioning identifier and exits\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB -i\fR, \fB\-\-input=\fRMODULE[:OPTIONS][,MODULE...]
|
||||
.RS 4
|
||||
Set list of input modules to load and use. Multiple modules can be used
|
||||
in parallel. bmon automatically loads a useful and working input module
|
||||
by default. See INPUT MODULES for more details.
|
||||
.RE
|
||||
.PP
|
||||
\fB -o\fR, \fB\-\-ouptut\fRMODULE[:OPTIONS][,MODULE...]
|
||||
.RS 4
|
||||
Set list of output modules to load and use. Multiple modules can be used
|
||||
in parallel. By default, bmon will use the curses output mode, if that is
|
||||
not available due to an incompatible console it will fall back to a simple
|
||||
text mode. See OUTPUT MODULES for more details.
|
||||
.RE
|
||||
.PP
|
||||
\fB -U\fR, \fB\-\-use\-si\fR
|
||||
.RS 4
|
||||
Use SI unit system instead of 1KB = 1'024 bytes.
|
||||
.RE
|
||||
.PP
|
||||
\fB -f\fR, \fB\-\-configfile=\fRFILE
|
||||
.RS 4
|
||||
Set alternative path to configuration file.
|
||||
.RE
|
||||
.PP
|
||||
\fB -p\fR, \fB\-\-policy=\fRPOLICY
|
||||
.RS 4
|
||||
Set policy defining which network interfaces to display. See
|
||||
INTERFACE SELECTION for more details.
|
||||
.RE
|
||||
.PP
|
||||
\fB -a\fR, \fB\-\-show\-all=\fR
|
||||
.RS 4
|
||||
Display all interfaces, even interface that are administratively down.
|
||||
.RE
|
||||
.PP
|
||||
\fB -r\fR, \fB\-\-read\-interval=\fRFLOAT
|
||||
.RS 4
|
||||
Set interval in seconds in which input modules read statistics from their
|
||||
source. The default is 1.0 seconds.
|
||||
.RE
|
||||
.PP
|
||||
\fB -R\fR, \fB\-\-rate\-interval=\fRFLOAT
|
||||
.RS 4
|
||||
Set interval in seconds in which the rate per counter is calculated.
|
||||
The default is 1.0 seconds.
|
||||
.RE
|
||||
.PP
|
||||
\fB -L\fR, \fB\-\-lifetime=\fRFLOAT
|
||||
.RS 4
|
||||
Set lifetime of an element in seconds before it is no longer displayed
|
||||
without receiving any statistical updates. The default is 30 seconds.
|
||||
.RE
|
||||
|
||||
.SH "INPUT MODULES"
|
||||
.PP
|
||||
Input modules provide statistical data about elements. Each element consists
|
||||
of attributes which represents a counter, a rate, or a percentage. Elements
|
||||
may carry additional child elements to represent a hierarchy. Each element is
|
||||
assigned to a group defined by the input module. Input modules are polled in
|
||||
the frequence of the configured read interval.
|
||||
.PP
|
||||
The following input modules are available:
|
||||
.TP
|
||||
\fBnetlink\fR
|
||||
Uses the Netlink protocol to collect interface and traffic control statistics
|
||||
from the kernel. This is the default input module.
|
||||
|
||||
.TP
|
||||
\fBproc\fR
|
||||
Reads interface statistics from the /proc/net/dev file. This is considered a
|
||||
legacy interface and provided for backwards compatibily reasons. This is a
|
||||
fallback module if the Netlink interface is not available.
|
||||
|
||||
.TP
|
||||
\fBdummy\fR
|
||||
Programmable input module for debugging and testing purposes.
|
||||
|
||||
.TP
|
||||
\fBnull\fR
|
||||
No data collected.
|
||||
|
||||
.PP
|
||||
To receive additional information about a module, run the module with the
|
||||
"help" option set like this:
|
||||
|
||||
.PP
|
||||
.RS 4
|
||||
bmon \-i netlink:help
|
||||
.RE
|
||||
|
||||
See MODULE CONFIGURATION for more details.
|
||||
|
||||
.SH "OUTPUT MODULES"
|
||||
.PP
|
||||
Output modules display or export the statistical data collected by input
|
||||
modules. Multiple output modules can be run at the same time. bmon will
|
||||
not prevent possible conflicts such as multiple output modules writing to
|
||||
the console.
|
||||
.PP
|
||||
The following output modules exist:
|
||||
|
||||
.TP
|
||||
\fBcurses\fR
|
||||
Interactive curses based text user interface providing real time rate
|
||||
estimations and a graphical representatio nof each attribute. Press '?'
|
||||
to display the quick reference guide. This is the default output mode.
|
||||
|
||||
.TP
|
||||
\fBascii\fR
|
||||
Simple programmable text output intended for human consumption. Capable
|
||||
of printing list of interfaces, detailed counters and graphs to the
|
||||
console. This is the default fallback output mode if curses is not
|
||||
available.
|
||||
|
||||
.TP
|
||||
\fBformat\fR
|
||||
Fully scriptable output mode inteded for consumption by other programs.
|
||||
See the module help text for additional information.
|
||||
|
||||
.TP
|
||||
\fBnull\fR
|
||||
Disable output.
|
||||
|
||||
.PP
|
||||
To receive additional information about a module, run the module with the
|
||||
"help" option set like this:
|
||||
|
||||
.PP
|
||||
.RS 4
|
||||
bmon \-o curses:help
|
||||
.RE
|
||||
|
||||
See MODULE CONFIGURATION for more details.
|
||||
|
||||
.SH "MODULE CONFIGURATION"
|
||||
.PP
|
||||
The syntax to configure modules is as follows:
|
||||
.PP
|
||||
.RS 4
|
||||
ARGUMENT ::= mod1[:OPTS][,mod2[:OPTS]...]
|
||||
.br
|
||||
OPTS ::= OPTION[;OPTION...]
|
||||
.br
|
||||
OPTION ::= option[=value]
|
||||
.RE
|
||||
|
||||
.PP
|
||||
Run the module with option "help" to receive the list of options for each
|
||||
module:
|
||||
|
||||
.PP
|
||||
.RS 4
|
||||
bmon -i module:help
|
||||
.RE
|
||||
|
||||
.SH "INTERFACE SELECTION"
|
||||
.PP
|
||||
The following syntax is used to define the interface selection policy:
|
||||
.PP
|
||||
.RS 4
|
||||
SELECTION ::= NAME[,NAME[,...]]
|
||||
.br
|
||||
NAME ::= [!]interface
|
||||
.RE
|
||||
|
||||
.PP
|
||||
The interface name may contain the character '*' which will act as a wildcard
|
||||
and represents any number of any character type, e.g. eth*, h*0, ...
|
||||
|
||||
.TP
|
||||
Examples:
|
||||
.RS
|
||||
.NF
|
||||
lo,eth0,eth1
|
||||
.FI
|
||||
.RE
|
||||
.RS
|
||||
.NF
|
||||
eth*,!eth0
|
||||
.FI
|
||||
.RE
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
To run bmon in curses mode monitoring the interfaces eth0
|
||||
and eth1:
|
||||
.PP
|
||||
.RS 4
|
||||
\fBbmon \-p eth0,eth1 \-o curses\fP
|
||||
.RE
|
||||
|
||||
.SH "FILES"
|
||||
/etc/bmon.conf
|
||||
.br
|
||||
$HOME/.bmonrc
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBip\fR(8),
|
||||
\fBnetstat\fR(8),
|
||||
\fBifconfig\fR(8),
|
||||
\fBnetlink\fR(7),
|
||||
|
||||
.SH "AUTHOR"
|
||||
Thomas Graf <tgraf@suug.ch>
|
2
src/.gitignore
vendored
Normal file
2
src/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.o
|
||||
bmon
|
42
src/Makefile.am
Normal file
42
src/Makefile.am
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
bin_PROGRAMS = bmon
|
||||
|
||||
bmon_CFLAGS = \
|
||||
-I${top_srcdir}/include \
|
||||
-I${top_builddir}/include \
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\" \
|
||||
-D_GNU_SOURCE \
|
||||
$(CURSES_CFLAGS) \
|
||||
$(CONFUSE_CFLAGS) \
|
||||
$(LIBNL_CFLAGS) \
|
||||
$(LIBNL_ROUTE_CFLAGS)
|
||||
|
||||
bmon_LDADD = \
|
||||
$(CURSES_LIB) \
|
||||
$(CONFUSE_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(LIBNL_ROUTE_LIBS)
|
||||
|
||||
bmon_SOURCES = \
|
||||
utils.c \
|
||||
unit.c \
|
||||
conf.c \
|
||||
input.c \
|
||||
output.c \
|
||||
group.c \
|
||||
element.c \
|
||||
attr.c \
|
||||
element_cfg.c \
|
||||
history.c \
|
||||
graph.c \
|
||||
bmon.c \
|
||||
module.c \
|
||||
in_netlink.c \
|
||||
in_null.c \
|
||||
in_dummy.c \
|
||||
in_proc.c \
|
||||
out_null.c \
|
||||
out_format.c \
|
||||
out_ascii.c \
|
||||
out_curses.c
|
635
src/attr.c
Normal file
635
src/attr.c
Normal file
@ -0,0 +1,635 @@
|
||||
/*
|
||||
* attr.c Attributes
|
||||
*
|
||||
* 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/history.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/unit.h>
|
||||
#include <bmon/input.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
#if 0
|
||||
|
||||
#define MAX_POLICY 255
|
||||
|
||||
static char * allowed_attrs[MAX_POLICY];
|
||||
static char * denied_attrs[MAX_POLICY];
|
||||
static int allow_all_attrs;
|
||||
|
||||
#endif
|
||||
|
||||
static LIST_HEAD(attr_def_list);
|
||||
static int attr_id_gen = 1;
|
||||
|
||||
struct attr_def *attr_def_lookup(const char *name)
|
||||
{
|
||||
struct attr_def *def;
|
||||
|
||||
list_for_each_entry(def, &attr_def_list, ad_list)
|
||||
if (!strcmp(name, def->ad_name))
|
||||
return def;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct attr_def *attr_def_lookup_id(int id)
|
||||
{
|
||||
struct attr_def *def;
|
||||
|
||||
list_for_each_entry(def, &attr_def_list, ad_list)
|
||||
if (def->ad_id == id)
|
||||
return def;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
for (i = 0; i < NAME_HASHSIZ; i++) {
|
||||
struct attr_type *t;
|
||||
for (t = attr_ht_name[i]; t; t = t->at_next_name) {
|
||||
err = cb(t, arg);
|
||||
if (err < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
int attr_def_add(const char *name, const char *desc, struct unit *unit,
|
||||
int type, int flags)
|
||||
{
|
||||
struct attr_def *def;
|
||||
|
||||
if ((def = attr_def_lookup(name)))
|
||||
return def->ad_id;
|
||||
|
||||
def = xcalloc(1, sizeof(*def));
|
||||
|
||||
def->ad_id = attr_id_gen++;
|
||||
def->ad_name = strdup(name);
|
||||
|
||||
def->ad_description = strdup(desc ? : "");
|
||||
def->ad_type = type;
|
||||
def->ad_unit = unit;
|
||||
def->ad_flags = flags;
|
||||
|
||||
list_add_tail(&def->ad_list, &attr_def_list);
|
||||
|
||||
DBG("New attribute %s desc=\"%s\" unit=%s type=%d",
|
||||
def->ad_name, def->ad_description, def->ad_unit->u_name, type);
|
||||
|
||||
return def->ad_id;
|
||||
}
|
||||
|
||||
void attr_def_free(struct attr_def *def)
|
||||
{
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
xfree(def->ad_name);
|
||||
xfree(def->ad_description);
|
||||
xfree(def);
|
||||
}
|
||||
|
||||
int attr_map_load(struct attr_map *map, size_t size)
|
||||
{
|
||||
int i, nfailed = 0;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
struct attr_map *m = &map[i];
|
||||
struct unit *u;
|
||||
|
||||
if (!(u = unit_lookup(m->unit))) {
|
||||
nfailed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
m->attrid = attr_def_add(m->name, m->description, u,
|
||||
m->type, m->flags);
|
||||
}
|
||||
|
||||
return nfailed;
|
||||
}
|
||||
|
||||
static inline unsigned int attr_hash(int id)
|
||||
{
|
||||
return id % ATTR_HASH_SIZE;
|
||||
}
|
||||
|
||||
struct attr *attr_lookup(const struct element *e, int id)
|
||||
{
|
||||
unsigned int hash = attr_hash(id);
|
||||
struct attr *attr;
|
||||
|
||||
list_for_each_entry(attr, &e->e_attrhash[hash], a_list)
|
||||
if (attr->a_def->ad_id == id)
|
||||
return attr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int collect_history(struct element *e, struct attr_def *def)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (def->ad_flags & ATTR_FORCE_HISTORY)
|
||||
return 1;
|
||||
|
||||
for (n = 0; n <= GT_MAX; n++)
|
||||
if (e->e_key_attr[n] == def)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
#if 0
|
||||
if (!allowed_attrs[0] && !denied_attrs[0]) {
|
||||
if (!strcmp(ad->ad_name, "bytes") ||
|
||||
!strcmp(ad->ad_name, "packets"))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!allowed_attrs[0]) {
|
||||
for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
|
||||
if (!strcasecmp(denied_attrs[n], ad->ad_name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
|
||||
if (!strcasecmp(denied_attrs[n], ad->ad_name))
|
||||
return 0;
|
||||
|
||||
for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
|
||||
if (!strcasecmp(allowed_attrs[n], ad->ad_name))
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
void attr_parse_policy(const char *policy)
|
||||
{
|
||||
static int set = 0;
|
||||
int i, a = 0, d = 0, f = 0;
|
||||
char *p, *s;
|
||||
|
||||
if (set)
|
||||
return;
|
||||
set = 1;
|
||||
|
||||
if (!strcasecmp(policy, "all")) {
|
||||
allow_all_attrs = 1;
|
||||
return ;
|
||||
}
|
||||
|
||||
s = strdup(policy);
|
||||
|
||||
for (i = 0, p = s; ; i++) {
|
||||
if (s[i] == ',' || s[i] == '\0') {
|
||||
|
||||
f = s[i] == '\0' ? 1 : 0;
|
||||
s[i] = '\0';
|
||||
|
||||
if ('!' == *p) {
|
||||
if (d > (MAX_POLICY - 1))
|
||||
break;
|
||||
denied_attrs[d++] = strdup(++p);
|
||||
} else {
|
||||
if(a > (MAX_POLICY - 1))
|
||||
break;
|
||||
allowed_attrs[a++] = strdup(p);
|
||||
}
|
||||
|
||||
if (f)
|
||||
break;
|
||||
|
||||
p = &s[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
xfree(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void attr_start_collecting_history(struct attr *attr)
|
||||
{
|
||||
if (attr->a_flags & ATTR_DOING_HISTORY)
|
||||
return;
|
||||
|
||||
DBG("Starting to collect history for attribute %s",
|
||||
attr->a_def->ad_name);
|
||||
|
||||
history_attach(attr);
|
||||
attr->a_flags |= ATTR_DOING_HISTORY;
|
||||
}
|
||||
|
||||
static int attrcmp(struct element *e, struct attr *a, struct attr *b)
|
||||
{
|
||||
/* major key attribute is always first */
|
||||
if (e->e_key_attr[GT_MAJOR] == b->a_def)
|
||||
return 1;
|
||||
|
||||
/* minor key attribte is always second */
|
||||
if (e->e_key_attr[GT_MINOR] == b->a_def)
|
||||
return (e->e_key_attr[GT_MAJOR] == a->a_def) ? -1 : 1;
|
||||
|
||||
/* otherwise sort by alphabet */
|
||||
return strcasecmp(a->a_def->ad_description, b->a_def->ad_description);
|
||||
}
|
||||
|
||||
void attr_update(struct element *e, int id, uint64_t rx, uint64_t tx, int flags)
|
||||
{
|
||||
struct attr *attr, *n;
|
||||
int update_ts = 0;
|
||||
|
||||
if (!(attr = attr_lookup(e, id))) {
|
||||
unsigned int hash = attr_hash(id);
|
||||
struct attr_def *def;
|
||||
|
||||
if (!(def = attr_def_lookup_id(id)))
|
||||
return;
|
||||
|
||||
DBG("Tracking new attribute %d (\"%s\") of element %s",
|
||||
def->ad_id, def->ad_name, e->e_name);
|
||||
|
||||
attr = xcalloc(1, sizeof(*attr));
|
||||
attr->a_def = def;
|
||||
attr->a_flags = def->ad_flags;
|
||||
|
||||
init_list_head(&attr->a_history_list);
|
||||
|
||||
if (collect_history(e, def))
|
||||
attr_start_collecting_history(attr);
|
||||
|
||||
list_add_tail(&attr->a_list, &e->e_attrhash[hash]);
|
||||
e->e_nattrs++;
|
||||
|
||||
list_for_each_entry(n, &e->e_attr_sorted, a_sort_list) {
|
||||
if (attrcmp(e, attr, n) < 0) {
|
||||
list_add_tail(&attr->a_sort_list,
|
||||
&n->a_sort_list);
|
||||
goto inserted;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&attr->a_sort_list, &e->e_attr_sorted);
|
||||
}
|
||||
|
||||
inserted:
|
||||
if (flags & UPDATE_FLAG_RX) {
|
||||
attr->a_rx_rate.r_current = rx;
|
||||
attr->a_flags |= ATTR_RX_ENABLED;
|
||||
update_ts = 1;
|
||||
}
|
||||
|
||||
if (flags & UPDATE_FLAG_TX) {
|
||||
attr->a_tx_rate.r_current = tx;
|
||||
attr->a_flags |= ATTR_TX_ENABLED;
|
||||
update_ts = 1;
|
||||
}
|
||||
|
||||
if (update_ts)
|
||||
update_timestamp(&attr->a_last_update);
|
||||
|
||||
DBG("Updated attribute %d (\"%s\") of element %s", id, attr->a_def->ad_name, e->e_name);
|
||||
}
|
||||
|
||||
void attr_free(struct attr *a)
|
||||
{
|
||||
struct history *h, *n;
|
||||
|
||||
list_for_each_entry_safe(h, n, &a->a_history_list, h_list)
|
||||
history_free(h);
|
||||
|
||||
list_del(&a->a_list);
|
||||
|
||||
xfree(a);
|
||||
}
|
||||
|
||||
void attr_rate2float(struct attr *a, double *rx, char **rxu, int *rxprec,
|
||||
double *tx, char **txu, int *txprec)
|
||||
{
|
||||
struct unit *u = a->a_def->ad_unit;
|
||||
|
||||
*rx = unit_value2str(a->a_rx_rate.r_rate, u, rxu, rxprec);
|
||||
*tx = unit_value2str(a->a_tx_rate.r_rate, u, txu, txprec);
|
||||
}
|
||||
|
||||
struct attr *attr_select_first(void)
|
||||
{
|
||||
struct element *e;
|
||||
|
||||
if (!(e = element_current()))
|
||||
return NULL;
|
||||
|
||||
if (list_empty(&e->e_attr_sorted))
|
||||
e->e_current_attr = NULL;
|
||||
else
|
||||
e->e_current_attr = list_first_entry(&e->e_attr_sorted,
|
||||
struct attr, a_sort_list);
|
||||
|
||||
return e->e_current_attr;
|
||||
}
|
||||
|
||||
struct attr *attr_select_last(void)
|
||||
{
|
||||
struct element *e;
|
||||
|
||||
if (!(e = element_current()))
|
||||
return NULL;
|
||||
|
||||
if (list_empty(&e->e_attr_sorted))
|
||||
e->e_current_attr = NULL;
|
||||
else
|
||||
e->e_current_attr = list_entry(&e->e_attr_sorted,
|
||||
struct attr, a_sort_list);
|
||||
|
||||
return e->e_current_attr;
|
||||
}
|
||||
|
||||
struct attr *attr_select_next(void)
|
||||
{
|
||||
struct element *e;
|
||||
struct attr *a;
|
||||
|
||||
if (!(e = element_current()))
|
||||
return NULL;
|
||||
|
||||
if (!(a = e->e_current_attr))
|
||||
return attr_select_first();
|
||||
|
||||
if (a->a_sort_list.next != &e->e_attr_sorted)
|
||||
e->e_current_attr = list_entry(a->a_sort_list.next,
|
||||
struct attr, a_sort_list);
|
||||
else
|
||||
return attr_select_first();
|
||||
|
||||
return e->e_current_attr;
|
||||
}
|
||||
|
||||
struct attr *attr_select_prev(void)
|
||||
{
|
||||
struct element *e;
|
||||
struct attr *a;
|
||||
|
||||
if (!(e = element_current()))
|
||||
return NULL;
|
||||
|
||||
if (!(a = e->e_current_attr))
|
||||
return attr_select_last();
|
||||
|
||||
if (a->a_sort_list.prev != &e->e_attr_sorted)
|
||||
e->e_current_attr = list_entry(a->a_sort_list.prev,
|
||||
struct attr, a_sort_list);
|
||||
else
|
||||
return attr_select_last();
|
||||
|
||||
return e->e_current_attr;
|
||||
|
||||
}
|
||||
|
||||
struct attr *attr_current(void)
|
||||
{
|
||||
struct element *e;
|
||||
|
||||
if (!(e = element_current()))
|
||||
return NULL;
|
||||
|
||||
if (!e->e_current_attr)
|
||||
return attr_select_first();
|
||||
|
||||
return e->e_current_attr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int __first_attr(struct item *item, int graph)
|
||||
{
|
||||
int i;
|
||||
struct attr *a;
|
||||
|
||||
for (i = 0; i < ATTR_HASH_MAX; i++) {
|
||||
for (a = item->i_attrs[i]; a; a = a->a_next) {
|
||||
if (a->a_flags & ATTR_FLAG_HISTORY) {
|
||||
item->i_attr_sel[graph] = a;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
int __next_attr(struct item *item, int graph)
|
||||
{
|
||||
int hash;
|
||||
struct attr *attr, *next;
|
||||
|
||||
if (item->i_attr_sel[graph] == NULL)
|
||||
return __first_attr(item, graph);
|
||||
|
||||
attr = item->i_attr_sel[graph];
|
||||
hash = attr_hash(attr->a_def->ad_id);
|
||||
next = attr->a_next;
|
||||
|
||||
if (next == NULL)
|
||||
hash++;
|
||||
|
||||
for (; hash < ATTR_HASH_MAX; hash++) {
|
||||
if (next) {
|
||||
attr = next;
|
||||
next = NULL;
|
||||
} else
|
||||
attr = item->i_attrs[hash];
|
||||
|
||||
for (; attr; attr = attr->a_next) {
|
||||
if (!(attr->a_flags & ATTR_FLAG_HISTORY))
|
||||
continue;
|
||||
item->i_attr_sel[graph] = attr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return __first_attr(item, graph);
|
||||
}
|
||||
|
||||
struct attr *attr_current(struct item *item, int graph)
|
||||
{
|
||||
if (item->i_attr_sel[graph] == NULL)
|
||||
__first_attr(item, graph);
|
||||
|
||||
return item->i_attr_sel[graph];
|
||||
}
|
||||
|
||||
int attr_first(void)
|
||||
{
|
||||
struct item *item = item_current();
|
||||
|
||||
if (item == NULL)
|
||||
return EMPTY_LIST;
|
||||
|
||||
return __first_attr(item, item->i_graph_sel);
|
||||
}
|
||||
|
||||
int attr_next(void)
|
||||
{
|
||||
struct item *item = item_current();
|
||||
|
||||
if (item == NULL)
|
||||
return EMPTY_LIST;
|
||||
|
||||
return __next_attr(item, item->i_graph_sel);
|
||||
}
|
||||
#endif
|
||||
|
||||
static float __calc_usage(double rate, uint64_t max)
|
||||
{
|
||||
if (!max)
|
||||
return FLT_MAX;
|
||||
|
||||
if (!rate)
|
||||
return 0.0f;
|
||||
|
||||
return 100.0f / ((double) max / (rate * cfg_rate_interval));
|
||||
}
|
||||
|
||||
void attr_calc_usage(struct attr *a, float *rx, float *tx,
|
||||
uint64_t rxmax, uint64_t txmax)
|
||||
{
|
||||
if (a->a_def->ad_type == ATTR_TYPE_PERCENT) {
|
||||
*rx = a->a_rx_rate.r_total;
|
||||
*tx = a->a_tx_rate.r_total;
|
||||
} else {
|
||||
*rx = __calc_usage(a->a_rx_rate.r_rate, rxmax);
|
||||
*tx = __calc_usage(a->a_tx_rate.r_rate, txmax);
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_counter_rate(struct attr *a, struct rate *rate,
|
||||
timestamp_t *ts)
|
||||
{
|
||||
uint64_t delta, prev_total;
|
||||
float diff, old_rate;
|
||||
|
||||
if (rate->r_current < rate->r_prev) {
|
||||
/* Overflow detected */
|
||||
if (a->a_flags & ATTR_IGNORE_OVERFLOWS)
|
||||
delta = rate->r_current;
|
||||
else {
|
||||
if (a->a_flags & ATTR_TRUE_64BIT)
|
||||
delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev;
|
||||
else
|
||||
delta = 0xFFFFFFFFULL - rate->r_prev;
|
||||
|
||||
delta += rate->r_current + 1;
|
||||
}
|
||||
} else
|
||||
delta = rate->r_current - rate->r_prev;
|
||||
|
||||
prev_total = rate->r_total;
|
||||
rate->r_total += delta;
|
||||
rate->r_prev = rate->r_current;
|
||||
|
||||
if (!prev_total) {
|
||||
/*
|
||||
* No previous records exists, reset time to now to
|
||||
* avoid doing unnecessary calculation, this behaviour
|
||||
* continues as long as the counter stays 0.
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
diff = timestamp_diff(&rate->r_last_calc, ts);
|
||||
if (diff < (cfg_rate_interval - cfg_rate_variance))
|
||||
return;
|
||||
|
||||
old_rate = rate->r_rate;
|
||||
|
||||
if (rate->r_total < prev_total) {
|
||||
/* overflow */
|
||||
delta = 0xFFFFFFFFFFFFFFFFULL - prev_total;
|
||||
delta += rate->r_total + 1;
|
||||
} else
|
||||
delta = rate->r_total - prev_total;
|
||||
|
||||
rate->r_rate = delta / diff;
|
||||
|
||||
if (old_rate)
|
||||
rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f;
|
||||
|
||||
out:
|
||||
copy_timestamp(&rate->r_last_calc, ts);
|
||||
}
|
||||
|
||||
static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts)
|
||||
{
|
||||
rate->r_prev = rate->r_rate = rate->r_total = rate->r_current;
|
||||
copy_timestamp(&rate->r_last_calc, ts);
|
||||
}
|
||||
|
||||
void attr_notify_update(struct attr *a, timestamp_t *ts)
|
||||
{
|
||||
switch (a->a_def->ad_type) {
|
||||
case ATTR_TYPE_RATE:
|
||||
case ATTR_TYPE_PERCENT:
|
||||
calc_rate_total(a, &a->a_rx_rate, ts);
|
||||
calc_rate_total(a, &a->a_tx_rate, ts);
|
||||
break;
|
||||
|
||||
case ATTR_TYPE_COUNTER:
|
||||
calc_counter_rate(a, &a->a_rx_rate, ts);
|
||||
calc_counter_rate(a, &a->a_tx_rate, ts);
|
||||
break;
|
||||
default:
|
||||
DBG("Attribute update of unknown type");
|
||||
break;
|
||||
}
|
||||
|
||||
if (a->a_flags & ATTR_DOING_HISTORY) {
|
||||
struct history *h;
|
||||
|
||||
DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name);
|
||||
|
||||
list_for_each_entry(h, &a->a_history_list, h_list)
|
||||
history_update(a, h, ts);
|
||||
}
|
||||
}
|
||||
|
||||
static void __exit attr_exit(void)
|
||||
{
|
||||
struct attr_def *ad, *n;
|
||||
|
||||
list_for_each_entry_safe(ad, n, &attr_def_list, ad_list)
|
||||
attr_def_free(ad);
|
||||
}
|
397
src/bmon.c
Normal file
397
src/bmon.c
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
* 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" \
|
||||
"\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:aU" \
|
||||
"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'},
|
||||
{"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 '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);
|
||||
}
|
596
src/conf.c
Normal file
596
src/conf.c
Normal file
@ -0,0 +1,596 @@
|
||||
/*
|
||||
* conf.c Config Crap
|
||||
*
|
||||
* 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/unit.h>
|
||||
#include <bmon/attr.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/element_cfg.h>
|
||||
#include <bmon/history.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
cfg_t *cfg;
|
||||
|
||||
static cfg_opt_t element_opts[] = {
|
||||
CFG_STR("description", NULL, CFGF_NONE),
|
||||
CFG_BOOL("show", cfg_true, CFGF_NONE),
|
||||
CFG_INT("rxmax", 0, CFGF_NONE),
|
||||
CFG_INT("txmax", 0, CFGF_NONE),
|
||||
CFG_INT("max", 0, CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t history_opts[] = {
|
||||
CFG_FLOAT("interval", 1.0f, CFGF_NONE),
|
||||
CFG_INT("size", 60, CFGF_NONE),
|
||||
CFG_STR("type", "64bit", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t attr_opts[] = {
|
||||
CFG_STR("description", "", CFGF_NONE),
|
||||
CFG_STR("unit", "", CFGF_NONE),
|
||||
CFG_STR("type", "counter", CFGF_NONE),
|
||||
CFG_BOOL("history", cfg_false, CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t variant_opts[] = {
|
||||
CFG_FLOAT_LIST("div", "{}", CFGF_NONE),
|
||||
CFG_STR_LIST("txt", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t unit_opts[] = {
|
||||
CFG_SEC("variant", variant_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t global_opts[] = {
|
||||
CFG_FLOAT("read_interval", 1.0f, CFGF_NONE),
|
||||
CFG_FLOAT("rate_interval", 1.0f, CFGF_NONE),
|
||||
CFG_FLOAT("lifetime", 30.0f, CFGF_NONE),
|
||||
CFG_FLOAT("history_variance", 0.1f, CFGF_NONE),
|
||||
CFG_FLOAT("variance", 0.1f, CFGF_NONE),
|
||||
CFG_BOOL("show_all", cfg_false, CFGF_NONE),
|
||||
CFG_INT("unit_exp", -1, CFGF_NONE),
|
||||
CFG_INT("sleep_time", 20000UL, CFGF_NONE),
|
||||
CFG_BOOL("use_si", 0, CFGF_NONE),
|
||||
CFG_STR("uid", NULL, CFGF_NONE),
|
||||
CFG_STR("gid", NULL, CFGF_NONE),
|
||||
CFG_STR("policy", "", CFGF_NONE),
|
||||
CFG_SEC("unit", unit_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_SEC("attr", attr_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_SEC("history", history_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_SEC("element", element_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
};
|
||||
|
||||
float cfg_read_interval;
|
||||
float cfg_rate_interval;
|
||||
float cfg_rate_variance;
|
||||
float cfg_history_variance;
|
||||
int cfg_show_all;
|
||||
int cfg_unit_exp = DYNAMIC_EXP;
|
||||
|
||||
static char * configfile = NULL;
|
||||
|
||||
#if defined HAVE_CURSES
|
||||
#if defined HAVE_USE_DEFAULT_COLORS
|
||||
struct layout cfg_layout[] =
|
||||
{
|
||||
{-1, -1, 0}, /* dummy, not used */
|
||||
{-1, -1, 0}, /* default */
|
||||
{-1, -1, A_REVERSE}, /* statusbar */
|
||||
{-1, -1, 0}, /* header */
|
||||
{-1, -1, 0}, /* list */
|
||||
{-1, -1, A_REVERSE}, /* selected */
|
||||
};
|
||||
#else
|
||||
struct layout cfg_layout[] =
|
||||
{
|
||||
{0, 0, 0}, /* dummy, not used */
|
||||
{COLOR_BLACK, COLOR_WHITE, 0}, /* default */
|
||||
{COLOR_BLACK, COLOR_WHITE, A_REVERSE}, /* statusbar */
|
||||
{COLOR_BLACK, COLOR_WHITE, 0}, /* header */
|
||||
{COLOR_BLACK, COLOR_WHITE, 0}, /* list */
|
||||
{COLOR_BLACK, COLOR_WHITE, A_REVERSE}, /* selected */
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
tv_t * parse_tv(char *data)
|
||||
{
|
||||
char *value;
|
||||
tv_t *tv = xcalloc(1, sizeof(tv_t));
|
||||
|
||||
init_list_head(&tv->tv_list);
|
||||
|
||||
value = strchr(data, '=');
|
||||
|
||||
if (value) {
|
||||
*value = '\0';
|
||||
++value;
|
||||
tv->tv_value = strdup(value);
|
||||
}
|
||||
|
||||
tv->tv_type = strdup(data);
|
||||
return tv;
|
||||
}
|
||||
|
||||
module_conf_t * parse_module(char *data)
|
||||
{
|
||||
char *name = data, *opts = data, *next;
|
||||
module_conf_t *m;
|
||||
|
||||
if (!*name)
|
||||
quit("No module name given");
|
||||
|
||||
m = xcalloc(1, sizeof(module_conf_t));
|
||||
|
||||
init_list_head(&m->m_attrs);
|
||||
|
||||
opts = strchr(data, ':');
|
||||
|
||||
if (opts) {
|
||||
*opts = '\0';
|
||||
opts++;
|
||||
|
||||
do {
|
||||
tv_t *tv;
|
||||
next = strchr(opts, ';');
|
||||
|
||||
if (next) {
|
||||
*next = '\0';
|
||||
++next;
|
||||
}
|
||||
|
||||
tv = parse_tv(opts);
|
||||
list_add_tail(&tv->tv_list, &m->m_attrs);
|
||||
|
||||
opts = next;
|
||||
} while(next);
|
||||
}
|
||||
|
||||
m->m_name = strdup(name);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
int parse_module_param(const char *data, struct list_head *list)
|
||||
{
|
||||
char *buf = strdup(data);
|
||||
char *next;
|
||||
char *current = buf;
|
||||
module_conf_t *m;
|
||||
int n = 0;
|
||||
|
||||
do {
|
||||
next = strchr(current, ',');
|
||||
|
||||
if (next) {
|
||||
*next = '\0';
|
||||
++next;
|
||||
}
|
||||
|
||||
m = parse_module(current);
|
||||
if (m) {
|
||||
list_add_tail(&m->m_list, list);
|
||||
n++;
|
||||
}
|
||||
|
||||
current = next;
|
||||
} while (next);
|
||||
|
||||
free(buf);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void configfile_read_history(void)
|
||||
{
|
||||
int i, nhistory;
|
||||
|
||||
nhistory = cfg_size(cfg, "history");
|
||||
|
||||
for (i = 0; i < nhistory; i++) {
|
||||
struct history_def *def;
|
||||
cfg_t *history;
|
||||
const char *name, *type;
|
||||
float interval;
|
||||
int size;
|
||||
|
||||
if (!(history = cfg_getnsec(cfg, "history", i)))
|
||||
BUG();
|
||||
|
||||
if (!(name = cfg_title(history)))
|
||||
BUG();
|
||||
|
||||
interval = cfg_getfloat(history, "interval");
|
||||
size = cfg_getint(history, "size");
|
||||
type = cfg_getstr(history, "type");
|
||||
|
||||
if (interval == 0.0f)
|
||||
interval = cfg_getfloat(cfg, "read_interval");
|
||||
|
||||
def = history_def_alloc(name);
|
||||
def->hd_interval = interval;
|
||||
def->hd_size = size;
|
||||
|
||||
if (!strcasecmp(type, "8bit"))
|
||||
def->hd_type = HISTORY_TYPE_8;
|
||||
else if (!strcasecmp(type, "16bit"))
|
||||
def->hd_type = HISTORY_TYPE_16;
|
||||
else if (!strcasecmp(type, "32bit"))
|
||||
def->hd_type = HISTORY_TYPE_32;
|
||||
else if (!strcasecmp(type, "64bit"))
|
||||
def->hd_type = HISTORY_TYPE_64;
|
||||
else
|
||||
quit("Invalid type \'%s\', must be \"(8|16|32|64)bit\""
|
||||
" in history definition #%d\n", type, i+1);
|
||||
}
|
||||
}
|
||||
|
||||
static void configfile_read_element_cfg(void)
|
||||
{
|
||||
int i, nelement;
|
||||
|
||||
nelement = cfg_size(cfg, "element");
|
||||
|
||||
for (i = 0; i < nelement; i++) {
|
||||
struct element_cfg *ec;
|
||||
cfg_t *element;
|
||||
const char *name, *description;
|
||||
long max;
|
||||
|
||||
if (!(element = cfg_getnsec(cfg, "element", i)))
|
||||
BUG();
|
||||
|
||||
if (!(name = cfg_title(element)))
|
||||
BUG();
|
||||
|
||||
ec = element_cfg_alloc(name);
|
||||
|
||||
if ((description = cfg_getstr(element, "description")))
|
||||
ec->ec_description = strdup(description);
|
||||
|
||||
if ((max = cfg_getint(element, "max")))
|
||||
ec->ec_rxmax = ec->ec_txmax = max;
|
||||
|
||||
if ((max = cfg_getint(element, "rxmax")))
|
||||
ec->ec_rxmax = max;
|
||||
|
||||
if ((max = cfg_getint(element, "txmax")))
|
||||
ec->ec_txmax = max;
|
||||
|
||||
if (cfg_getbool(element, "show"))
|
||||
ec->ec_flags |= ELEMENT_CFG_SHOW;
|
||||
else
|
||||
ec->ec_flags |= ELEMENT_CFG_HIDE;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_div(struct unit *unit, int type, cfg_t *variant)
|
||||
{
|
||||
int ndiv, n, ntxt;
|
||||
|
||||
if (!(ndiv = cfg_size(variant, "div")))
|
||||
return;
|
||||
|
||||
ntxt = cfg_size(variant, "txt");
|
||||
if (ntxt != ndiv)
|
||||
quit("Number of elements for div and txt not equal\n");
|
||||
|
||||
if (!list_empty(&unit->u_div[type])) {
|
||||
struct fraction *f, *n;
|
||||
|
||||
list_for_each_entry_safe(f, n, &unit->u_div[type], f_list)
|
||||
fraction_free(f);
|
||||
}
|
||||
|
||||
for (n = 0; n < ndiv; n++) {
|
||||
char *txt;
|
||||
float div;
|
||||
|
||||
div = cfg_getnfloat(variant, "div", n);
|
||||
txt = cfg_getnstr(variant, "txt", n);
|
||||
|
||||
unit_add_div(unit, type, txt, div);
|
||||
}
|
||||
}
|
||||
|
||||
static void configfile_read_units(void)
|
||||
{
|
||||
int i, nunits;
|
||||
struct unit *u;
|
||||
|
||||
nunits = cfg_size(cfg, "unit");
|
||||
|
||||
for (i = 0; i < nunits; i++) {
|
||||
int nvariants, n;
|
||||
cfg_t *unit;
|
||||
const char *name;
|
||||
|
||||
if (!(unit = cfg_getnsec(cfg, "unit", i)))
|
||||
BUG();
|
||||
|
||||
if (!(name = cfg_title(unit)))
|
||||
BUG();
|
||||
|
||||
if (!(nvariants = cfg_size(unit, "variant")))
|
||||
continue;
|
||||
|
||||
if (!(u = unit_add(name)))
|
||||
continue;
|
||||
|
||||
for (n = 0; n < nvariants; n++) {
|
||||
cfg_t *variant;
|
||||
const char *vtitle;
|
||||
|
||||
if (!(variant = cfg_getnsec(unit, "variant", n)))
|
||||
BUG();
|
||||
|
||||
if (!(vtitle = cfg_title(variant)))
|
||||
BUG();
|
||||
|
||||
if (!strcasecmp(vtitle, "default"))
|
||||
add_div(u, UNIT_DEFAULT, variant);
|
||||
else if (!strcasecmp(vtitle, "si"))
|
||||
add_div(u, UNIT_SI, variant);
|
||||
else
|
||||
quit("Unknown unit variant \'%s\'\n", vtitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void configfile_read_attrs(void)
|
||||
{
|
||||
int i, nattrs, t;
|
||||
|
||||
nattrs = cfg_size(cfg, "attr");
|
||||
|
||||
for (i = 0; i < nattrs; i++) {
|
||||
struct unit *u;
|
||||
cfg_t *attr;
|
||||
const char *name, *description, *unit, *type;
|
||||
int flags = 0;
|
||||
|
||||
if (!(attr = cfg_getnsec(cfg, "attr", i)))
|
||||
BUG();
|
||||
|
||||
if (!(name = cfg_title(attr)))
|
||||
BUG();
|
||||
|
||||
description = cfg_getstr(attr, "description");
|
||||
unit = cfg_getstr(attr, "unit");
|
||||
type = cfg_getstr(attr, "type");
|
||||
|
||||
if (!unit)
|
||||
quit("Attribute '%s' is missing unit specification\n",
|
||||
name);
|
||||
|
||||
if (!type)
|
||||
quit("Attribute '%s' is missing type specification\n",
|
||||
name);
|
||||
|
||||
if (!(u = unit_lookup(unit)))
|
||||
quit("Unknown unit \'%s\' attribute '%s'\n",
|
||||
unit, name);
|
||||
|
||||
if (!strcasecmp(type, "counter"))
|
||||
t = ATTR_TYPE_COUNTER;
|
||||
else if (!strcasecmp(type, "rate"))
|
||||
t = ATTR_TYPE_RATE;
|
||||
else if (!strcasecmp(type, "percent"))
|
||||
t = ATTR_TYPE_PERCENT;
|
||||
else
|
||||
quit("Unknown type \'%s\' in attribute '%s'\n",
|
||||
type, name);
|
||||
|
||||
if (cfg_getbool(attr, "history"))
|
||||
flags |= ATTR_FORCE_HISTORY;
|
||||
|
||||
if (cfg_getbool(attr, "ignore_overflows"))
|
||||
flags |= ATTR_IGNORE_OVERFLOWS;
|
||||
|
||||
attr_def_add(name, description, u, t, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_read(const char *path, int must)
|
||||
{
|
||||
int err;
|
||||
|
||||
DBG("Reading configfile %s...", path);
|
||||
|
||||
if (access(path, R_OK) != 0) {
|
||||
if (must)
|
||||
quit("Error: Unable to read configfile \"%s\": %s\n",
|
||||
path, strerror(errno));
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
err = cfg_parse(cfg, path);
|
||||
if (err == CFG_FILE_ERROR) {
|
||||
quit("Error while reading configfile \"%s\": %s\n",
|
||||
path, strerror(errno));
|
||||
} else if (err == CFG_PARSE_ERROR) {
|
||||
quit("Error while reading configfile \"%s\": parse error\n",
|
||||
path);
|
||||
}
|
||||
|
||||
configfile_read_units();
|
||||
configfile_read_history();
|
||||
configfile_read_attrs();
|
||||
configfile_read_element_cfg();
|
||||
}
|
||||
|
||||
static const char default_config[] = \
|
||||
"unit byte {" \
|
||||
" variant default {" \
|
||||
" div = { 1, 1024, 1048576, 1073741824, 1099511627776}" \
|
||||
" txt = { \"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\" }" \
|
||||
" }" \
|
||||
" variant si {" \
|
||||
" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \
|
||||
" txt = { \"B\", \"KB\", \"MB\", \"GB\", \"TB\" }" \
|
||||
" }" \
|
||||
" }" \
|
||||
"unit bit {" \
|
||||
" variant default {" \
|
||||
" div = { 1, 1024, 1048576, 1073741824, 1099511627776}" \
|
||||
" txt = { \"b\", \"Kib\", \"Mib\", \"Gib\", \"TiB\" }" \
|
||||
" }" \
|
||||
" variant si {" \
|
||||
" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \
|
||||
" txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \
|
||||
" }" \
|
||||
"}" \
|
||||
"unit number {" \
|
||||
" variant default {" \
|
||||
" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \
|
||||
" txt = { \"\", \"K\", \"M\", \"G\", \"T\" }" \
|
||||
" }" \
|
||||
"}" \
|
||||
"unit percent {" \
|
||||
" variant default {" \
|
||||
" div = { 1. }" \
|
||||
" txt = { \"%\" }" \
|
||||
" }" \
|
||||
"}" \
|
||||
"history second {" \
|
||||
" interval = 1.0" \
|
||||
" size = 60" \
|
||||
"}" \
|
||||
"history minute {" \
|
||||
" interval = 60.0" \
|
||||
" size = 60" \
|
||||
"}" \
|
||||
"history hour {" \
|
||||
" interval = 3600.0" \
|
||||
" size = 60" \
|
||||
"}" \
|
||||
"history day {" \
|
||||
" interval = 86400.0" \
|
||||
" size = 60" \
|
||||
"}";
|
||||
|
||||
static void conf_read_default(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
DBG("Reading default config");
|
||||
|
||||
err = cfg_parse_buf(cfg, default_config);
|
||||
if (err)
|
||||
quit("Error while parsing default config\n");
|
||||
|
||||
configfile_read_units();
|
||||
configfile_read_history();
|
||||
configfile_read_attrs();
|
||||
configfile_read_element_cfg();
|
||||
}
|
||||
|
||||
void configfile_read(void)
|
||||
{
|
||||
if (configfile)
|
||||
conf_read(configfile, 1);
|
||||
else {
|
||||
conf_read(SYSCONFDIR "/bmonrc", 0);
|
||||
|
||||
if (getenv("HOME")) {
|
||||
char path[FILENAME_MAX+1];
|
||||
snprintf(path, sizeof(path), "%s/.bmonrc",
|
||||
getenv("HOME"));
|
||||
conf_read(path, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void conf_init_pre(void)
|
||||
{
|
||||
conf_read_default();
|
||||
}
|
||||
|
||||
void conf_init_post(void)
|
||||
{
|
||||
cfg_read_interval = cfg_getfloat(cfg, "read_interval");
|
||||
cfg_rate_interval = cfg_getfloat(cfg, "rate_interval");
|
||||
cfg_rate_variance = cfg_getfloat(cfg, "variance") * cfg_rate_interval;
|
||||
cfg_history_variance = cfg_getfloat(cfg, "history_variance");
|
||||
cfg_show_all = cfg_getbool(cfg, "show_all");
|
||||
cfg_unit_exp = cfg_getint(cfg, "unit_exp");
|
||||
|
||||
element_parse_policy(cfg_getstr(cfg, "policy"));
|
||||
}
|
||||
|
||||
void set_configfile(const char *file)
|
||||
{
|
||||
static int set = 0;
|
||||
if (!set) {
|
||||
configfile = strdup(file);
|
||||
set = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void set_unit_exp(const char *name)
|
||||
{
|
||||
if (tolower(*name) == 'b')
|
||||
cfg_setint(cfg, "unit_exp", 0);
|
||||
else if (tolower(*name) == 'k')
|
||||
cfg_setint(cfg, "unit_exp", 1);
|
||||
else if (tolower(*name) == 'm')
|
||||
cfg_setint(cfg, "unit_exp", 2);
|
||||
else if (tolower(*name) == 'g')
|
||||
cfg_setint(cfg, "unit_exp", 3);
|
||||
else if (tolower(*name) == 't')
|
||||
cfg_setint(cfg, "unit_exp", 4);
|
||||
else if (tolower(*name) == 'd')
|
||||
cfg_setint(cfg, "unit_exp", DYNAMIC_EXP);
|
||||
else
|
||||
quit("Unknown unit exponent '%s'\n", name);
|
||||
}
|
||||
|
||||
unsigned int get_lifecycles(void)
|
||||
{
|
||||
return (unsigned int)
|
||||
(cfg_getfloat(cfg, "lifetime") / cfg_getfloat(cfg, "read_interval"));
|
||||
}
|
||||
|
||||
static void __exit conf_shutdown(void)
|
||||
{
|
||||
cfg_free(cfg);
|
||||
}
|
||||
|
||||
static void __init __conf_init(void)
|
||||
{
|
||||
DBG("init");
|
||||
|
||||
cfg = cfg_init(global_opts, CFGF_NOCASE);
|
||||
|
||||
/* FIXME: Add validation functions */
|
||||
//cfg_set_validate_func(cfg, "bookmark", &cb_validate_bookmark);
|
||||
}
|
537
src/element.c
Normal file
537
src/element.c
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* src/element.c Elements
|
||||
*
|
||||
* 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/element.h>
|
||||
#include <bmon/element_cfg.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/input.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static LIST_HEAD(allowed);
|
||||
static LIST_HEAD(denied);
|
||||
|
||||
static int match_mask(const struct policy *p, const char *str)
|
||||
{
|
||||
int i, n;
|
||||
char c;
|
||||
|
||||
if (!p || !str)
|
||||
return 0;
|
||||
|
||||
for (i = 0, n = 0; p->p_rule[i] != '\0'; i++) {
|
||||
if (p->p_rule[i] == '*') {
|
||||
c = tolower(p->p_rule[i + 1]);
|
||||
|
||||
if (c == '\0')
|
||||
return 1;
|
||||
|
||||
while (tolower(str[n]) != c)
|
||||
if (str[n++] == '\0')
|
||||
return 0;
|
||||
} else if (tolower(p->p_rule[i]) != tolower(str[n++]))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str[n] == '\0' ? 1 : 0;
|
||||
}
|
||||
|
||||
int element_allowed(const char *name, struct element_cfg *cfg)
|
||||
{
|
||||
struct policy *p;
|
||||
|
||||
if (cfg) {
|
||||
if (cfg->ec_flags & ELEMENT_CFG_HIDE)
|
||||
return 0;
|
||||
else if (cfg->ec_flags & ELEMENT_CFG_SHOW)
|
||||
return 1;
|
||||
}
|
||||
|
||||
list_for_each_entry(p, &denied, p_list)
|
||||
if (match_mask(p, name))
|
||||
return 0;
|
||||
|
||||
if (!list_empty(&allowed)) {
|
||||
list_for_each_entry(p, &allowed, p_list)
|
||||
if (match_mask(p, name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void element_parse_policy(const char *policy)
|
||||
{
|
||||
char *start, *copy, *save = NULL, *tok;
|
||||
struct policy *p;
|
||||
|
||||
if (!policy)
|
||||
return;
|
||||
|
||||
copy = strdup(policy);
|
||||
start = copy;
|
||||
|
||||
while ((tok = strtok_r(start, ",", &save)) != NULL) {
|
||||
start = NULL;
|
||||
|
||||
p = xcalloc(1, sizeof(*p));
|
||||
|
||||
if (*tok == '!') {
|
||||
p->p_rule = strdup(++tok);
|
||||
list_add_tail(&p->p_list, &denied);
|
||||
} else {
|
||||
p->p_rule = strdup(tok);
|
||||
list_add_tail(&p->p_list, &allowed);
|
||||
}
|
||||
}
|
||||
|
||||
xfree(copy);
|
||||
}
|
||||
|
||||
struct element *__lookup_element(struct element_group *group, const char *name,
|
||||
uint32_t id, struct element *parent)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct element *e;
|
||||
|
||||
if (parent)
|
||||
list = &parent->e_childs;
|
||||
else
|
||||
list = &group->g_elements;
|
||||
|
||||
list_for_each_entry(e, list, e_list)
|
||||
if (!strcmp(name, e->e_name) && e->e_id == id)
|
||||
return e;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct element *element_lookup(struct element_group *group, const char *name,
|
||||
uint32_t id, struct element *parent, int flags)
|
||||
{
|
||||
struct element_cfg *cfg;
|
||||
struct element *e;
|
||||
int i;
|
||||
|
||||
if (!group)
|
||||
BUG();
|
||||
|
||||
if ((e = __lookup_element(group, name, id, parent)))
|
||||
return e;
|
||||
|
||||
if (!(flags & ELEMENT_CREAT))
|
||||
return NULL;
|
||||
|
||||
cfg = element_cfg_lookup(name);
|
||||
if (!element_allowed(name, cfg))
|
||||
return NULL;
|
||||
|
||||
DBG("Creating element %d \"%s\"", id, name);
|
||||
|
||||
e = xcalloc(1, sizeof(*e));
|
||||
|
||||
init_list_head(&e->e_list);
|
||||
init_list_head(&e->e_childs);
|
||||
init_list_head(&e->e_info_list);
|
||||
init_list_head(&e->e_attr_sorted);
|
||||
|
||||
for (i = 0; i < ATTR_HASH_SIZE; i++)
|
||||
init_list_head(&e->e_attrhash[i]);
|
||||
|
||||
e->e_name = strdup(name);
|
||||
e->e_id = id;
|
||||
e->e_parent = parent;
|
||||
e->e_group = group;
|
||||
e->e_lifecycles = get_lifecycles();
|
||||
e->e_flags = ELEMENT_FLAG_CREATED;
|
||||
e->e_cfg = cfg;
|
||||
|
||||
if (e->e_cfg) {
|
||||
if (e->e_cfg->ec_description)
|
||||
element_update_info(e, "Description",
|
||||
e->e_cfg->ec_description);
|
||||
|
||||
element_set_rxmax(e, e->e_cfg->ec_rxmax);
|
||||
element_set_txmax(e, e->e_cfg->ec_txmax);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
DBG("Attached to parent %d \"%s\"", parent->e_id, parent->e_name);
|
||||
list_add_tail(&e->e_list, &parent->e_childs);
|
||||
} else {
|
||||
DBG("Attached to group %s", group->g_name);
|
||||
list_add_tail(&e->e_list, &group->g_elements);
|
||||
}
|
||||
|
||||
group->g_nelements++;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void element_free(struct element *e)
|
||||
{
|
||||
struct info *info, *ninfo;
|
||||
struct element *c, *cnext;
|
||||
struct attr *a, *an;
|
||||
int i;
|
||||
|
||||
if (e->e_group->g_current == e) {
|
||||
element_select_prev();
|
||||
if (e->e_group->g_current == e)
|
||||
e->e_group->g_current = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(c, cnext, &e->e_childs, e_list)
|
||||
element_free(c);
|
||||
|
||||
list_for_each_entry_safe(info, ninfo, &e->e_info_list, i_list) {
|
||||
xfree(info->i_name);
|
||||
xfree(info->i_value);
|
||||
list_del(&info->i_list);
|
||||
xfree(info);
|
||||
}
|
||||
|
||||
for (i = 0; i < ATTR_HASH_SIZE; i++)
|
||||
list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list)
|
||||
attr_free(a);
|
||||
|
||||
if (e->e_group) {
|
||||
list_del(&e->e_list);
|
||||
e->e_group->g_nelements--;
|
||||
}
|
||||
|
||||
xfree(e->e_name);
|
||||
xfree(e);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (item->i_group->g_selected == item) {
|
||||
if (item_select_prev() == END_OF_LIST) {
|
||||
if (group_select_prev() == END_OF_LIST) {
|
||||
if (node_select_prev() != END_OF_LIST)
|
||||
item_select_last();
|
||||
} else
|
||||
item_select_last();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
void item_delete(struct item *item)
|
||||
{
|
||||
int m;
|
||||
struct item *child;
|
||||
|
||||
for (m = 0; m < ATTR_HASH_MAX; m++) {
|
||||
struct attr *a, *next;
|
||||
for (a = item->i_attrs[m]; a; a = next) {
|
||||
next = a->a_next;
|
||||
xfree(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (item->i_group->g_selected == item) {
|
||||
if (item_select_prev() == END_OF_LIST) {
|
||||
if (group_select_prev() == END_OF_LIST) {
|
||||
if (node_select_prev() != END_OF_LIST)
|
||||
item_select_last();
|
||||
} else
|
||||
item_select_last();
|
||||
}
|
||||
}
|
||||
|
||||
unlink_item(item);
|
||||
item->i_group->g_nitems--;
|
||||
|
||||
for (child = item->i_childs; child; child = child->i_next)
|
||||
item_delete(child);
|
||||
|
||||
if (item->i_path)
|
||||
xfree(item->i_path);
|
||||
|
||||
xfree(item);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void element_reset_update_flag(struct element_group *g,
|
||||
struct element *e, void *arg)
|
||||
{
|
||||
DBG("Reseting update flag of %s", e->e_name);
|
||||
e->e_flags &= ~ELEMENT_FLAG_UPDATED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Needs to be called after updating all attributes of an element
|
||||
*/
|
||||
void element_notify_update(struct element *e, timestamp_t *ts)
|
||||
{
|
||||
struct attr *a;
|
||||
int i;
|
||||
|
||||
e->e_flags |= ELEMENT_FLAG_UPDATED;
|
||||
|
||||
if (ts == NULL)
|
||||
ts = &rtiming.rt_last_read;
|
||||
|
||||
for (i = 0; i < ATTR_HASH_SIZE; i++)
|
||||
list_for_each_entry(a, &e->e_attrhash[i], a_list)
|
||||
attr_notify_update(a, ts);
|
||||
|
||||
if (e->e_usage_attr && e->e_cfg &&
|
||||
(a = attr_lookup(e, e->e_usage_attr->ad_id))) {
|
||||
attr_calc_usage(a, &e->e_rx_usage, &e->e_tx_usage,
|
||||
e->e_cfg->ec_rxmax, e->e_cfg->ec_txmax);
|
||||
} else {
|
||||
e->e_rx_usage = FLT_MAX;
|
||||
e->e_tx_usage = FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void element_lifesign(struct element *e, int n)
|
||||
{
|
||||
e->e_lifecycles = n * get_lifecycles();
|
||||
}
|
||||
|
||||
void element_check_if_dead(struct element_group *g,
|
||||
struct element *e, void *arg)
|
||||
{
|
||||
if (--(e->e_lifecycles) <= 0) {
|
||||
element_free(e);
|
||||
DBG("Deleting dead element %s", e->e_name);
|
||||
}
|
||||
}
|
||||
|
||||
void element_foreach_attr(struct element *e,
|
||||
void (*cb)(struct element *e,
|
||||
struct attr *, void *),
|
||||
void *arg)
|
||||
{
|
||||
struct attr *a;
|
||||
|
||||
list_for_each_entry(a, &e->e_attr_sorted, a_sort_list)
|
||||
cb(e, a, arg);
|
||||
}
|
||||
|
||||
int element_set_key_attr(struct element *e, const char *major,
|
||||
const char * minor)
|
||||
{
|
||||
if (!(e->e_key_attr[GT_MAJOR] = attr_def_lookup(major)))
|
||||
return -ENOENT;
|
||||
|
||||
if (!(e->e_key_attr[GT_MINOR] = attr_def_lookup(minor)))
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int element_set_usage_attr(struct element *e, const char *usage)
|
||||
{
|
||||
if (!(e->e_usage_attr = attr_def_lookup(usage)))
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct element *element_current(void)
|
||||
{
|
||||
struct element_group *g;
|
||||
|
||||
if (!(g = group_current()))
|
||||
return NULL;
|
||||
|
||||
if (!g->g_current)
|
||||
element_select_first();
|
||||
|
||||
return g->g_current;
|
||||
}
|
||||
|
||||
struct element *element_select_first(void)
|
||||
{
|
||||
struct element_group *g;
|
||||
|
||||
if (!(g = group_current()))
|
||||
return NULL;
|
||||
|
||||
if (list_empty(&g->g_elements))
|
||||
g->g_current = NULL;
|
||||
else
|
||||
g->g_current = list_first_entry(&g->g_elements,
|
||||
struct element, e_list);
|
||||
|
||||
return g->g_current;
|
||||
}
|
||||
|
||||
struct element *element_select_last(void)
|
||||
{
|
||||
struct element_group *g;
|
||||
|
||||
if (!(g = group_current()))
|
||||
return NULL;
|
||||
|
||||
if (list_empty(&g->g_elements))
|
||||
g->g_current = NULL;
|
||||
else {
|
||||
struct element *e;
|
||||
|
||||
e = list_entry(g->g_elements.prev, struct element, e_list);
|
||||
|
||||
while (!list_empty(&e->e_childs))
|
||||
e = list_entry(e->e_childs.prev, struct element,
|
||||
e_list);
|
||||
|
||||
g->g_current = e;
|
||||
}
|
||||
|
||||
return g->g_current;
|
||||
}
|
||||
|
||||
struct element *element_select_next(void)
|
||||
{
|
||||
struct element_group *g;
|
||||
struct element *e;
|
||||
|
||||
if (!(g = group_current()))
|
||||
return NULL;
|
||||
|
||||
if (!(e = g->g_current))
|
||||
return element_select_first();
|
||||
|
||||
if (!list_empty(&e->e_childs))
|
||||
e = list_first_entry(&e->e_childs, struct element, e_list);
|
||||
else {
|
||||
/*
|
||||
* move upwards until we have no parent or there is a next
|
||||
* entry in the list
|
||||
*/
|
||||
while (e->e_parent && e->e_list.next == &e->e_parent->e_childs)
|
||||
e = e->e_parent;
|
||||
|
||||
if (!e->e_parent && e->e_list.next == &g->g_elements) {
|
||||
group_select_next();
|
||||
return element_select_first();
|
||||
} else
|
||||
e = list_entry(e->e_list.next, struct element, e_list);
|
||||
}
|
||||
|
||||
g->g_current = e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
struct element *element_select_prev(void)
|
||||
{
|
||||
struct element_group *g;
|
||||
struct element *e;
|
||||
|
||||
if (!(g = group_current()))
|
||||
return NULL;
|
||||
|
||||
if (!(e = g->g_current))
|
||||
return element_select_last();
|
||||
|
||||
if (!e->e_parent && e->e_list.prev == &g->g_elements) {
|
||||
group_select_prev();
|
||||
return element_select_last();
|
||||
}
|
||||
|
||||
if (e->e_parent && e->e_list.prev == &e->e_parent->e_childs)
|
||||
e = e->e_parent;
|
||||
else {
|
||||
e = list_entry(e->e_list.prev, struct element, e_list);
|
||||
|
||||
while (!list_empty(&e->e_childs))
|
||||
e = list_entry(e->e_childs.prev, struct element,
|
||||
e_list);
|
||||
}
|
||||
|
||||
g->g_current = e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static struct info *element_info_lookup(struct element *e, const char *name)
|
||||
{
|
||||
struct info *i;
|
||||
|
||||
list_for_each_entry(i, &e->e_info_list, i_list)
|
||||
if (!strcmp(i->i_name, name))
|
||||
return i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void element_update_info(struct element *e, const char *name, const char *value)
|
||||
{
|
||||
struct info *i;
|
||||
|
||||
if ((i = element_info_lookup(e, name))) {
|
||||
xfree(i->i_value);
|
||||
i->i_value = strdup(value);
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("Created element info %s (\"%s\")", name, value);
|
||||
|
||||
i = xcalloc(1, sizeof(*i));
|
||||
i->i_name = strdup(name);
|
||||
i->i_value = strdup(value);
|
||||
|
||||
e->e_ninfo++;
|
||||
|
||||
list_add_tail(&i->i_list, &e->e_info_list);
|
||||
}
|
||||
|
||||
void element_set_txmax(struct element *e, uint64_t max)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
if (!e->e_cfg)
|
||||
e->e_cfg = element_cfg_create(e->e_name);
|
||||
|
||||
if (e->e_cfg->ec_txmax != max)
|
||||
e->e_cfg->ec_txmax = max;
|
||||
|
||||
unit_bit2str(e->e_cfg->ec_txmax * 8, buf, sizeof(buf));
|
||||
element_update_info(e, "TxMax", buf);
|
||||
}
|
||||
|
||||
void element_set_rxmax(struct element *e, uint64_t max)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
if (!e->e_cfg)
|
||||
e->e_cfg = element_cfg_create(e->e_name);
|
||||
|
||||
if (e->e_cfg->ec_rxmax != max)
|
||||
e->e_cfg->ec_rxmax = max;
|
||||
|
||||
unit_bit2str(e->e_cfg->ec_rxmax * 8, buf, sizeof(buf));
|
||||
element_update_info(e, "RxMax", buf);
|
||||
}
|
96
src/element_cfg.c
Normal file
96
src/element_cfg.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* element_cfg.c Element Configuration
|
||||
*
|
||||
* 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/element.h>
|
||||
#include <bmon/element_cfg.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static LIST_HEAD(cfg_list);
|
||||
|
||||
struct element_cfg *element_cfg_alloc(const char *name)
|
||||
{
|
||||
struct element_cfg *ec;
|
||||
|
||||
if ((ec = element_cfg_lookup(name))) {
|
||||
ec->ec_refcnt++;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = xcalloc(1, sizeof(*ec));
|
||||
ec->ec_name = strdup(name);
|
||||
ec->ec_refcnt = 1;
|
||||
|
||||
list_add_tail(&ec->ec_list, &cfg_list);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
struct element_cfg *element_cfg_create(const char *name)
|
||||
{
|
||||
struct element_cfg *cfg;
|
||||
|
||||
if (!(cfg = element_cfg_lookup(name)))
|
||||
cfg = element_cfg_alloc(name);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void __element_cfg_free(struct element_cfg *ec)
|
||||
{
|
||||
list_del(&ec->ec_list);
|
||||
|
||||
xfree(ec->ec_name);
|
||||
xfree(ec->ec_description);
|
||||
xfree(ec);
|
||||
}
|
||||
|
||||
void element_cfg_free(struct element_cfg *ec)
|
||||
{
|
||||
if (!ec || --ec->ec_refcnt)
|
||||
return;
|
||||
|
||||
__element_cfg_free(ec);
|
||||
}
|
||||
|
||||
struct element_cfg *element_cfg_lookup(const char *name)
|
||||
{
|
||||
struct element_cfg *ec;
|
||||
|
||||
list_for_each_entry(ec, &cfg_list, ec_list)
|
||||
if (!strcmp(name, ec->ec_name))
|
||||
return ec;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __exit __element_cfg_exit(void)
|
||||
{
|
||||
struct element_cfg *ec, *n;
|
||||
|
||||
list_for_each_entry_safe(ec, n, &cfg_list, ec_list)
|
||||
__element_cfg_free(ec);
|
||||
}
|
235
src/graph.c
Normal file
235
src/graph.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* graph.c Graph creation utility
|
||||
*
|
||||
* 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/graph.h>
|
||||
#include <bmon/input.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/history.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/unit.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
size_t graph_row_size(struct graph_cfg *cfg)
|
||||
{
|
||||
/* +1 for trailing \0 */
|
||||
return cfg->gc_width + 1;
|
||||
}
|
||||
|
||||
static inline size_t table_size(struct graph_cfg *cfg)
|
||||
{
|
||||
return cfg->gc_height * graph_row_size(cfg);
|
||||
}
|
||||
|
||||
static inline char *at_row(struct graph_cfg *cfg, char *col, int nrow)
|
||||
{
|
||||
return col + (nrow * graph_row_size(cfg));
|
||||
}
|
||||
|
||||
static inline char *at_col(char *row, int ncol)
|
||||
{
|
||||
return row + ncol;
|
||||
}
|
||||
|
||||
static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol)
|
||||
{
|
||||
return at_col(at_row(cfg, tbl, nrow), ncol);
|
||||
}
|
||||
|
||||
static void write_column(struct graph_cfg *cfg, struct graph_table *tbl, int ncol,
|
||||
uint64_t value, double *scale, double half_step)
|
||||
{
|
||||
char *col = at_col(tbl->gt_table, ncol);
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
if (value == UNK_DATA) {
|
||||
for (i = 0; i < height; i++)
|
||||
*(at_row(g, col, i)) = unk_char;
|
||||
#endif
|
||||
if (value) {
|
||||
*(at_row(cfg, col, 0)) = ':';
|
||||
|
||||
for (i = 0; i < cfg->gc_height; i++)
|
||||
if (value >= (scale[i] - half_step))
|
||||
*(at_row(cfg, col, i)) = cfg->gc_foreground;
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_table(struct graph *g, struct graph_table *tbl,
|
||||
struct history *h, struct history_store *data)
|
||||
{
|
||||
struct graph_cfg *cfg = &g->g_cfg;
|
||||
uint64_t max = 0, v;
|
||||
int i, n, t;
|
||||
float half_step, step;
|
||||
|
||||
if (!tbl->gt_table) {
|
||||
tbl->gt_table = xcalloc(table_size(cfg), sizeof(char));
|
||||
tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double));
|
||||
}
|
||||
|
||||
memset(tbl->gt_table, cfg->gc_background, table_size(cfg));
|
||||
|
||||
/* end each line with a \0 */
|
||||
for (i = 0; i < cfg->gc_height; i++)
|
||||
*tbl_pos(cfg, tbl->gt_table, i, cfg->gc_width) = '\0';
|
||||
|
||||
/* leave table blank if there is no data */
|
||||
if (!h || !data->hs_data)
|
||||
return;
|
||||
|
||||
if (cfg->gc_width > h->h_definition->hd_size)
|
||||
BUG();
|
||||
|
||||
/* find the largest peak */
|
||||
for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
|
||||
if (--n < 0)
|
||||
n = h->h_definition->hd_size - 1;
|
||||
v = history_data(h, data, n);
|
||||
if (v != HISTORY_UNKNOWN && max < v)
|
||||
max = v;
|
||||
}
|
||||
|
||||
step = (double) max / (double) cfg->gc_height;
|
||||
half_step = step / 2.0f;
|
||||
|
||||
for (i = 0; i < cfg->gc_height; i++)
|
||||
tbl->gt_scale[i] = (double) (i + 1) * step;
|
||||
|
||||
for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
|
||||
char * col = at_col(tbl->gt_table, i);
|
||||
|
||||
if (--n < 0)
|
||||
n = h->h_definition->hd_size - 1;
|
||||
v = history_data(h, data, n);
|
||||
|
||||
if (v == HISTORY_UNKNOWN) {
|
||||
for (t = 0; t < cfg->gc_height; t++)
|
||||
*(at_row(cfg, col, t)) = cfg->gc_unknown;
|
||||
} else if (v > 0) {
|
||||
*(at_row(cfg, col, 0)) = cfg->gc_noise;
|
||||
|
||||
for (t = 0; t < cfg->gc_height; t++)
|
||||
if (v >= (tbl->gt_scale[t] - half_step))
|
||||
*(at_row(cfg, col, t)) = cfg->gc_foreground;
|
||||
}
|
||||
}
|
||||
|
||||
n = (cfg->gc_height / 3) * 2;
|
||||
if (n >= cfg->gc_height)
|
||||
n = (cfg->gc_height - 1);
|
||||
|
||||
v = unit_divisor(tbl->gt_scale[n], cfg->gc_unit,
|
||||
&tbl->gt_y_unit, NULL);
|
||||
|
||||
for (i = 0; i < cfg->gc_height; i++)
|
||||
tbl->gt_scale[i] /= (double) v;
|
||||
}
|
||||
|
||||
struct graph *graph_alloc(struct history *h, struct graph_cfg *cfg)
|
||||
{
|
||||
struct graph *g;
|
||||
|
||||
if (!cfg->gc_height)
|
||||
BUG();
|
||||
|
||||
g = xcalloc(1, sizeof(*g));
|
||||
|
||||
memcpy(&g->g_cfg, cfg, sizeof(*cfg));
|
||||
|
||||
if (h != NULL &&
|
||||
(cfg->gc_width > h->h_definition->hd_size || !cfg->gc_width))
|
||||
g->g_cfg.gc_width = h->h_definition->hd_size;
|
||||
|
||||
if (!g->g_cfg.gc_width)
|
||||
BUG();
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void graph_refill(struct graph *g, struct history *h)
|
||||
{
|
||||
fill_table(g, &g->g_rx, h, h ? &h->h_rx : NULL);
|
||||
fill_table(g, &g->g_tx, h, h ? &h->h_tx : NULL);
|
||||
}
|
||||
|
||||
void graph_free(struct graph *g)
|
||||
{
|
||||
if (!g)
|
||||
return;
|
||||
|
||||
xfree(g->g_rx.gt_table);
|
||||
xfree(g->g_rx.gt_scale);
|
||||
xfree(g->g_tx.gt_table);
|
||||
xfree(g->g_tx.gt_scale);
|
||||
xfree(g);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
void new_graph(void)
|
||||
{
|
||||
if (ngraphs >= (MAX_GRAPHS - 1))
|
||||
return;
|
||||
set_ngraphs_hard(ngraphs + 1);
|
||||
}
|
||||
|
||||
void del_graph(void)
|
||||
{
|
||||
if (ngraphs <= 1)
|
||||
return;
|
||||
set_ngraphs_hard(ngraphs - 1);
|
||||
}
|
||||
|
||||
int next_graph(void)
|
||||
{
|
||||
struct item *it = item_current();
|
||||
if (it == NULL)
|
||||
return EMPTY_LIST;
|
||||
|
||||
if (it->i_graph_sel >= (ngraphs - 1))
|
||||
it->i_graph_sel = 0;
|
||||
else
|
||||
it->i_graph_sel++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prev_graph(void)
|
||||
{
|
||||
struct item *it = item_current();
|
||||
if (it == NULL)
|
||||
return EMPTY_LIST;
|
||||
|
||||
if (it->i_graph_sel <= 0)
|
||||
it->i_graph_sel = ngraphs - 1;
|
||||
else
|
||||
it->i_graph_sel--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
278
src/group.c
Normal file
278
src/group.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* group.c Group Management
|
||||
*
|
||||
* 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/element.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static LIST_HEAD(titles_list);
|
||||
static LIST_HEAD(group_list);
|
||||
static unsigned int ngroups;
|
||||
static struct element_group *current_group;
|
||||
|
||||
static void __group_foreach_element(struct element_group *g,
|
||||
struct list_head *list,
|
||||
void (*cb)(struct element_group *,
|
||||
struct element *, void *),
|
||||
void *arg)
|
||||
{
|
||||
struct element *e, *n;
|
||||
|
||||
list_for_each_entry_safe(e, n, list, e_list) {
|
||||
cb(g, e, arg);
|
||||
|
||||
if (!list_empty(&e->e_childs))
|
||||
__group_foreach_element(g, &e->e_childs, cb, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void group_foreach_element(struct element_group *g,
|
||||
void (*cb)(struct element_group *,
|
||||
struct element *, void *),
|
||||
void *arg)
|
||||
{
|
||||
__group_foreach_element(g, &g->g_elements, cb, arg);
|
||||
}
|
||||
|
||||
void group_foreach_recursive(void (*cb)(struct element_group *,
|
||||
struct element *, void *),
|
||||
void *arg)
|
||||
{
|
||||
struct element_group *g, *n;
|
||||
|
||||
list_for_each_entry_safe(g, n, &group_list, g_list)
|
||||
__group_foreach_element(g, &g->g_elements, cb, arg);
|
||||
}
|
||||
|
||||
void group_foreach(void (*cb)(struct element_group *, void *), void *arg)
|
||||
{
|
||||
struct element_group *g, *n;
|
||||
|
||||
list_for_each_entry_safe(g, n, &group_list, g_list)
|
||||
cb(g, arg);
|
||||
}
|
||||
|
||||
struct element_group *group_select_first(void)
|
||||
{
|
||||
if (list_empty(&group_list))
|
||||
current_group = NULL;
|
||||
else
|
||||
current_group = list_first_entry(&group_list,
|
||||
struct element_group, g_list);
|
||||
|
||||
return current_group;
|
||||
}
|
||||
|
||||
struct element_group *group_select_last(void)
|
||||
{
|
||||
if (list_empty(&group_list))
|
||||
current_group = NULL;
|
||||
else
|
||||
current_group = list_entry(group_list.prev,
|
||||
struct element_group, g_list);
|
||||
|
||||
return current_group;
|
||||
}
|
||||
|
||||
struct element_group *group_select_next(void)
|
||||
{
|
||||
if (!current_group)
|
||||
return group_select_first();
|
||||
|
||||
if (current_group->g_list.next != &group_list)
|
||||
current_group = list_entry(current_group->g_list.next,
|
||||
struct element_group,
|
||||
g_list);
|
||||
else
|
||||
return group_select_first();
|
||||
|
||||
return current_group;
|
||||
}
|
||||
|
||||
struct element_group *group_select_prev(void)
|
||||
{
|
||||
if (!current_group)
|
||||
return group_select_last();
|
||||
|
||||
if (current_group->g_list.prev != &group_list)
|
||||
current_group = list_entry(current_group->g_list.prev,
|
||||
struct element_group,
|
||||
g_list);
|
||||
else
|
||||
return group_select_last();
|
||||
|
||||
return current_group;
|
||||
}
|
||||
|
||||
struct element_group *group_current(void)
|
||||
{
|
||||
if (current_group == NULL)
|
||||
current_group = group_select_first();
|
||||
|
||||
return current_group;
|
||||
}
|
||||
|
||||
struct element_group *group_lookup(const char *name, int flags)
|
||||
{
|
||||
struct element_group *g;
|
||||
struct group_hdr *hdr;
|
||||
|
||||
list_for_each_entry(g, &group_list, g_list)
|
||||
if (!strcmp(name, g->g_name))
|
||||
return g;
|
||||
|
||||
if (!(flags & GROUP_CREATE))
|
||||
return NULL;
|
||||
|
||||
if (!(hdr = group_lookup_hdr(name))) {
|
||||
fprintf(stderr, "Cannot find title for group \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g = xcalloc(1, sizeof(*g));
|
||||
|
||||
init_list_head(&g->g_elements);
|
||||
|
||||
g->g_name = hdr->gh_name;
|
||||
g->g_hdr = hdr;
|
||||
|
||||
list_add_tail(&g->g_list, &group_list);
|
||||
ngroups++;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
static void group_free(struct element_group *g)
|
||||
{
|
||||
struct element *e, *n;
|
||||
struct element_group *next;
|
||||
|
||||
if (current_group == g) {
|
||||
next = group_select_next();
|
||||
if (!next || next == g)
|
||||
current_group = NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(e, n, &g->g_elements, e_list)
|
||||
element_free(e);
|
||||
|
||||
xfree(g);
|
||||
}
|
||||
|
||||
void reset_update_flags(void)
|
||||
{
|
||||
group_foreach_recursive(&element_reset_update_flag, NULL);
|
||||
}
|
||||
|
||||
void free_unused_elements(void)
|
||||
{
|
||||
group_foreach_recursive(&element_check_if_dead, NULL);
|
||||
}
|
||||
|
||||
struct group_hdr *group_lookup_hdr(const char *name)
|
||||
{
|
||||
struct group_hdr *hdr;
|
||||
|
||||
list_for_each_entry(hdr, &titles_list, gh_list)
|
||||
if (!strcmp(hdr->gh_name, name))
|
||||
return hdr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int group_new_hdr(const char *name, const char *title,
|
||||
const char *col1, const char *col2,
|
||||
const char *col3, const char *col4)
|
||||
{
|
||||
struct group_hdr *hdr;
|
||||
|
||||
if (group_lookup_hdr(name))
|
||||
return -EEXIST;
|
||||
|
||||
hdr = xcalloc(1, sizeof(*hdr));
|
||||
|
||||
init_list_head(&hdr->gh_list);
|
||||
|
||||
hdr->gh_name = strdup(name);
|
||||
hdr->gh_title = strdup(title);
|
||||
|
||||
hdr->gh_column[0] = strdup(col1);
|
||||
hdr->gh_column[1] = strdup(col2);
|
||||
hdr->gh_column[2] = strdup(col3);
|
||||
hdr->gh_column[3] = strdup(col4);
|
||||
|
||||
list_add_tail(&hdr->gh_list, &titles_list);
|
||||
|
||||
DBG("New group title %s \"%s\"", name, title);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int group_new_derived_hdr(const char *name, const char *title,
|
||||
const char *template)
|
||||
{
|
||||
struct group_hdr *t;
|
||||
|
||||
if (group_lookup_hdr(name))
|
||||
return -EEXIST;
|
||||
|
||||
if (!(t = group_lookup_hdr(template)))
|
||||
return -ENOENT;
|
||||
|
||||
return group_new_hdr(name, title, t->gh_column[0], t->gh_column[1],
|
||||
t->gh_column[2], t->gh_column[3]);
|
||||
}
|
||||
|
||||
static void group_hdr_free(struct group_hdr *hdr)
|
||||
{
|
||||
xfree(hdr->gh_name);
|
||||
xfree(hdr->gh_title);
|
||||
xfree(hdr->gh_column[0]);
|
||||
xfree(hdr->gh_column[1]);
|
||||
xfree(hdr->gh_column[2]);
|
||||
xfree(hdr->gh_column[3]);
|
||||
xfree(hdr);
|
||||
}
|
||||
|
||||
static void __init group_init(void)
|
||||
{
|
||||
DBG("init");
|
||||
|
||||
group_new_hdr("intf", "Interfaces",
|
||||
"RX bps", "pps", "TX bps", "pps");
|
||||
}
|
||||
|
||||
static void __exit group_exit(void)
|
||||
{
|
||||
struct element_group *g, *next;
|
||||
struct group_hdr *hdr, *gnext;
|
||||
|
||||
list_for_each_entry_safe(g, next, &group_list, g_list)
|
||||
group_free(g);
|
||||
|
||||
list_for_each_entry_safe(hdr, gnext, &titles_list, gh_list)
|
||||
group_hdr_free(hdr);
|
||||
}
|
318
src/history.c
Normal file
318
src/history.c
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* history.c History Management
|
||||
*
|
||||
* 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/history.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static LIST_HEAD(def_list);
|
||||
|
||||
static struct history_def *current_history;
|
||||
|
||||
struct history_def *history_def_lookup(const char *name)
|
||||
{
|
||||
struct history_def *def;
|
||||
|
||||
list_for_each_entry(def, &def_list, hd_list)
|
||||
if (!strcmp(def->hd_name, name))
|
||||
return def;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct history_def *history_def_alloc(const char *name)
|
||||
{
|
||||
struct history_def *def;
|
||||
|
||||
if ((def = history_def_lookup(name)))
|
||||
return def;
|
||||
|
||||
def = xcalloc(1, sizeof(*def));
|
||||
def->hd_name = strdup(name);
|
||||
|
||||
list_add_tail(&def->hd_list, &def_list);
|
||||
|
||||
DBG("New history definition %s", name);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static void history_def_free(struct history_def *def)
|
||||
{
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
xfree(def->hd_name);
|
||||
xfree(def);
|
||||
}
|
||||
|
||||
static void *history_alloc_data(struct history_def *def)
|
||||
{
|
||||
return xcalloc(def->hd_size, def->hd_type);
|
||||
}
|
||||
|
||||
static void history_store_data(struct history *h, struct history_store *hs,
|
||||
uint64_t total, float diff)
|
||||
{
|
||||
uint64_t delta;
|
||||
|
||||
if (!hs->hs_data) {
|
||||
if (total == HISTORY_UNKNOWN)
|
||||
return;
|
||||
|
||||
hs->hs_data = history_alloc_data(h->h_definition);
|
||||
}
|
||||
|
||||
if (total == HISTORY_UNKNOWN)
|
||||
delta = HISTORY_UNKNOWN;
|
||||
else {
|
||||
delta = (total - hs->hs_prev_total);
|
||||
|
||||
if (delta > 0)
|
||||
delta /= diff;
|
||||
hs->hs_prev_total = total;
|
||||
}
|
||||
|
||||
switch (h->h_definition->hd_type) {
|
||||
case HISTORY_TYPE_8:
|
||||
((uint8_t *) hs->hs_data)[h->h_index] = (uint8_t) delta;
|
||||
break;
|
||||
|
||||
case HISTORY_TYPE_16:
|
||||
((uint16_t *) hs->hs_data)[h->h_index] = (uint16_t) delta;
|
||||
break;
|
||||
|
||||
case HISTORY_TYPE_32:
|
||||
((uint32_t *) hs->hs_data)[h->h_index] = (uint32_t) delta;
|
||||
break;
|
||||
|
||||
case HISTORY_TYPE_64:
|
||||
((uint64_t *) hs->hs_data)[h->h_index] = (uint64_t) delta;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void inc_history_index(struct history *h)
|
||||
{
|
||||
if (h->h_index < (h->h_definition->hd_size - 1))
|
||||
h->h_index++;
|
||||
else
|
||||
h->h_index = 0;
|
||||
}
|
||||
|
||||
uint64_t history_data(struct history *h, struct history_store *hs, int index)
|
||||
{
|
||||
switch (h->h_definition->hd_type) {
|
||||
case HISTORY_TYPE_8: {
|
||||
uint8_t v = ((uint8_t *) hs->hs_data)[index];
|
||||
return (v == (uint8_t) -1) ? HISTORY_UNKNOWN : v;
|
||||
}
|
||||
|
||||
case HISTORY_TYPE_16: {
|
||||
uint16_t v = ((uint16_t *) hs->hs_data)[index];
|
||||
return (v == (uint16_t) -1) ? HISTORY_UNKNOWN : v;
|
||||
}
|
||||
|
||||
case HISTORY_TYPE_32: {
|
||||
uint32_t v = ((uint32_t *) hs->hs_data)[index];
|
||||
return (v == (uint32_t) -1) ? HISTORY_UNKNOWN : v;
|
||||
}
|
||||
|
||||
case HISTORY_TYPE_64: {
|
||||
uint64_t v = ((uint64_t *) hs->hs_data)[index];
|
||||
return (v == (uint64_t) -1) ? HISTORY_UNKNOWN : v;
|
||||
}
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
void history_update(struct attr *a, struct history *h, timestamp_t *ts)
|
||||
{
|
||||
struct history_def *def = h->h_definition;
|
||||
float timediff;
|
||||
|
||||
if (h->h_last_update.tv_sec)
|
||||
timediff = timestamp_diff(&h->h_last_update, ts);
|
||||
else {
|
||||
timediff = 0.0f; /* initial history update */
|
||||
|
||||
/* Need a delta when working with counters */
|
||||
if (a->a_def->ad_type == ATTR_TYPE_COUNTER)
|
||||
goto update_prev_total;
|
||||
}
|
||||
|
||||
/*
|
||||
* A read interval greater than the desired history interval
|
||||
* can't possibly result in anything useful. Discard it and
|
||||
* mark history data as invalid. The user has to adjust the
|
||||
* read interval.
|
||||
*/
|
||||
if (cfg_read_interval > def->hd_interval)
|
||||
goto discard;
|
||||
|
||||
/*
|
||||
* If the history interval matches the read interval it makes
|
||||
* sense to update upon every read. The reader timing already
|
||||
* took care of being as close as possible to the desired
|
||||
* interval.
|
||||
*/
|
||||
if (cfg_read_interval == def->hd_interval)
|
||||
goto update;
|
||||
|
||||
if (timediff > h->h_max_interval)
|
||||
goto discard;
|
||||
|
||||
if (timediff < h->h_min_interval)
|
||||
return;
|
||||
|
||||
update:
|
||||
history_store_data(h, &h->h_rx, a->a_rx_rate.r_total, timediff);
|
||||
history_store_data(h, &h->h_tx, a->a_tx_rate.r_total, timediff);
|
||||
inc_history_index(h);
|
||||
|
||||
goto update_ts;
|
||||
|
||||
discard:
|
||||
while(timediff >= (def->hd_interval / 2)) {
|
||||
history_store_data(h, &h->h_rx, HISTORY_UNKNOWN, 0.0f);
|
||||
history_store_data(h, &h->h_tx, HISTORY_UNKNOWN, 0.0f);
|
||||
|
||||
inc_history_index(h);
|
||||
timediff -= def->hd_interval;
|
||||
}
|
||||
|
||||
update_prev_total:
|
||||
h->h_rx.hs_prev_total = a->a_rx_rate.r_total;
|
||||
h->h_tx.hs_prev_total = a->a_tx_rate.r_total;
|
||||
|
||||
update_ts:
|
||||
copy_timestamp(&h->h_last_update, ts);
|
||||
}
|
||||
|
||||
struct history *history_alloc(struct history_def *def)
|
||||
{
|
||||
struct history *h;
|
||||
|
||||
h = xcalloc(1, sizeof(*h));
|
||||
|
||||
init_list_head(&h->h_list);
|
||||
|
||||
h->h_definition = def;
|
||||
|
||||
h->h_min_interval = (def->hd_interval - (cfg_read_interval / 2.0f));
|
||||
h->h_max_interval = (def->hd_interval / cfg_history_variance);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void history_free(struct history *h)
|
||||
{
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
xfree(h->h_rx.hs_data);
|
||||
xfree(h->h_tx.hs_data);
|
||||
|
||||
list_del(&h->h_list);
|
||||
|
||||
xfree(h);
|
||||
}
|
||||
|
||||
void history_attach(struct attr *attr)
|
||||
{
|
||||
struct history_def *def;
|
||||
struct history *h;
|
||||
|
||||
list_for_each_entry(def, &def_list, hd_list) {
|
||||
h = history_alloc(def);
|
||||
list_add_tail(&h->h_list, &attr->a_history_list);
|
||||
}
|
||||
}
|
||||
|
||||
struct history_def *history_select_first(void)
|
||||
{
|
||||
if (list_empty(&def_list))
|
||||
current_history = NULL;
|
||||
else
|
||||
current_history = list_first_entry(&def_list,
|
||||
struct history_def, hd_list);
|
||||
|
||||
return current_history;
|
||||
}
|
||||
|
||||
struct history_def *history_select_last(void)
|
||||
{
|
||||
if (list_empty(&def_list))
|
||||
current_history = NULL;
|
||||
else
|
||||
current_history = list_entry(def_list.prev,
|
||||
struct history_def, hd_list);
|
||||
|
||||
return current_history;
|
||||
}
|
||||
|
||||
struct history_def *history_select_next(void)
|
||||
{
|
||||
if (current_history && current_history->hd_list.next != &def_list) {
|
||||
current_history = list_entry(current_history->hd_list.next,
|
||||
struct history_def, hd_list);
|
||||
return current_history;
|
||||
}
|
||||
|
||||
return history_select_first();
|
||||
}
|
||||
|
||||
struct history_def *history_select_prev(void)
|
||||
{
|
||||
if (current_history && current_history->hd_list.prev != &def_list) {
|
||||
current_history = list_entry(current_history->hd_list.prev,
|
||||
struct history_def, hd_list);
|
||||
return current_history;
|
||||
}
|
||||
|
||||
return history_select_last();
|
||||
}
|
||||
|
||||
struct history_def *history_current(void)
|
||||
{
|
||||
if (!current_history)
|
||||
current_history = history_select_first();
|
||||
|
||||
return current_history;
|
||||
}
|
||||
|
||||
static void __exit history_exit(void)
|
||||
{
|
||||
struct history_def *def, *n;
|
||||
|
||||
list_for_each_entry_safe(def, n, &def_list, hd_list)
|
||||
history_def_free(def);
|
||||
}
|
243
src/in_dummy.c
Normal file
243
src/in_dummy.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* in_dummy.c Dummy Input Method
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/attr.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
#define MAXDEVS 32
|
||||
|
||||
static uint64_t c_rx_b_inc = 1000000000;
|
||||
static uint64_t c_tx_b_inc = 80000000;
|
||||
static uint64_t c_rx_p_inc = 1000;
|
||||
static uint64_t c_tx_p_inc = 800;
|
||||
static int c_numdev = 5;
|
||||
static int c_randomize = 0;
|
||||
static int c_mtu = 1540;
|
||||
static int c_maxpps = 100000;
|
||||
static int c_numgroups = 2;
|
||||
|
||||
static uint64_t *cnts;
|
||||
|
||||
enum {
|
||||
DUMMY_BYTES,
|
||||
DUMMY_PACKETS,
|
||||
NUM_DUMMY_VALUE,
|
||||
};
|
||||
|
||||
static struct attr_map link_attrs[NUM_DUMMY_VALUE] = {
|
||||
{
|
||||
.name = "bytes",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Bytes",
|
||||
},
|
||||
{
|
||||
.name = "packets",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Packtes",
|
||||
}
|
||||
};
|
||||
|
||||
/* cnts[ngroups][ndevs][2][2] */
|
||||
|
||||
static inline int cnt_size(void)
|
||||
{
|
||||
return c_numgroups * c_numdev * 2 * 2;
|
||||
}
|
||||
|
||||
static inline uint64_t *cnt(int group, int dev, int unit,
|
||||
int direction)
|
||||
{
|
||||
return cnts + (group * c_numdev * 2 * 2) +
|
||||
(dev * 2 * 2) +
|
||||
(unit * 2) +
|
||||
direction;
|
||||
}
|
||||
|
||||
static void dummy_read(void)
|
||||
{
|
||||
int gidx, n;
|
||||
|
||||
for (gidx = 0; gidx < c_numgroups; gidx++) {
|
||||
char gname[32];
|
||||
struct element_group *group;
|
||||
|
||||
snprintf(gname, sizeof(gname), "group%02d", gidx);
|
||||
group = group_lookup(gname, GROUP_CREATE);
|
||||
|
||||
for (n = 0; n < c_numdev; n++) {
|
||||
char ifname[IFNAMSIZ];
|
||||
struct element *e;
|
||||
int i;
|
||||
|
||||
snprintf(ifname, sizeof(ifname), "dummy%d", n);
|
||||
|
||||
if (!(e = element_lookup(group, ifname, 0, NULL, ELEMENT_CREAT)))
|
||||
return;
|
||||
|
||||
if (e->e_flags & ELEMENT_FLAG_CREATED) {
|
||||
if (element_set_key_attr(e, "bytes", "packets") ||
|
||||
element_set_usage_attr(e, "bytes"))
|
||||
BUG();
|
||||
e->e_flags &= ~ELEMENT_FLAG_CREATED;
|
||||
}
|
||||
|
||||
if (e->e_flags & ELEMENT_FLAG_UPDATED)
|
||||
continue;
|
||||
|
||||
if (c_randomize) {
|
||||
uint64_t rx = rand() % c_maxpps;
|
||||
uint64_t tx = rand() % c_maxpps;
|
||||
|
||||
*cnt(gidx, n, 0, 0) += rx;
|
||||
*cnt(gidx, n, 0, 1) += tx;
|
||||
*cnt(gidx, n, 1, 0) += rx * (rand() % c_mtu);
|
||||
*cnt(gidx, n, 1, 1) += tx * (rand() % c_mtu);
|
||||
} else {
|
||||
*cnt(gidx, n, 0, 0) += c_rx_p_inc;
|
||||
*cnt(gidx, n, 0, 1) += c_tx_p_inc;
|
||||
*cnt(gidx, n, 1, 0) += c_rx_b_inc;
|
||||
*cnt(gidx, n, 1, 1) += c_tx_b_inc;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
|
||||
struct attr_map *m = &link_attrs[i];
|
||||
|
||||
attr_update(e, m->attrid,
|
||||
*cnt(gidx, n, i, 0),
|
||||
*cnt(gidx, n, i, 1),
|
||||
UPDATE_FLAG_RX | UPDATE_FLAG_TX |
|
||||
UPDATE_FLAG_64BIT);
|
||||
}
|
||||
|
||||
element_notify_update(e, NULL);
|
||||
element_lifesign(e, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"dummy - Statistic generator module (dummy)\n" \
|
||||
"\n" \
|
||||
" Basic statistic generator for testing purposes. Can produce a\n" \
|
||||
" constant or random statistic flow with configurable parameters.\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n" \
|
||||
" Options:\n" \
|
||||
" rxb=NUM RX bytes increment amount (default: 10^9)\n" \
|
||||
" txb=NUM TX bytes increment amount (default: 8*10^7)\n" \
|
||||
" rxp=NUM RX packets increment amount (default: 1K)\n" \
|
||||
" txp=NUM TX packets increment amount (default: 800)\n" \
|
||||
" num=NUM Number of devices (default: 5)\n" \
|
||||
" numgroups=NUM Number of groups (default: 2)\n" \
|
||||
" randomize Randomize counters (default: off)\n" \
|
||||
" seed=NUM Seed for randomizer (default: time(0))\n" \
|
||||
" mtu=NUM Maximal Transmission Unit (default: 1540)\n" \
|
||||
" maxpps=NUM Upper limit for packets per second (default: 100K)\n" \
|
||||
"\n" \
|
||||
" Randomizer:\n" \
|
||||
" RX-packets := Rand() %% maxpps\n" \
|
||||
" TX-packets := Rand() %% maxpps\n" \
|
||||
" RX-bytes := RX-packets * (Rand() %% mtu)\n" \
|
||||
" TX-bytes := TX-packets * (Rand() %% mtu)\n");
|
||||
}
|
||||
|
||||
static void dummy_parse_opt(const char *value, const char *type)
|
||||
{
|
||||
if (!strcasecmp(type, "rxb") && value)
|
||||
c_rx_b_inc = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "txb") && value)
|
||||
c_tx_b_inc = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "rxp") && value)
|
||||
c_rx_p_inc = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "txp") && value)
|
||||
c_tx_p_inc = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "num") && value)
|
||||
c_numdev = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "randomize")) {
|
||||
c_randomize = 1;
|
||||
srand(time(0));
|
||||
} else if (!strcasecmp(type, "seed") && value)
|
||||
srand(strtol(value, NULL, 0));
|
||||
else if (!strcasecmp(type, "mtu") && value)
|
||||
c_mtu = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "maxpps") && value)
|
||||
c_maxpps = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "numgroups") && value)
|
||||
c_numgroups = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int dummy_do_init(void)
|
||||
{
|
||||
if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)))
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_probe(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (c_numdev >= MAXDEVS) {
|
||||
fprintf(stderr, "numdev must be in range 0..%d\n", MAXDEVS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cnts = xcalloc(cnt_size(), sizeof(uint64_t));
|
||||
|
||||
for (i = 0; i < c_numgroups; i++) {
|
||||
char groupname[32];
|
||||
snprintf(groupname, sizeof(groupname), "group%02d", i);
|
||||
|
||||
group_new_derived_hdr(groupname, groupname, DEFAULT_GROUP);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct bmon_module dummy_ops = {
|
||||
.m_name = "dummy",
|
||||
.m_do = dummy_read,
|
||||
.m_parse_opt = dummy_parse_opt,
|
||||
.m_probe = dummy_probe,
|
||||
.m_init = dummy_do_init,
|
||||
};
|
||||
|
||||
static void __init dummy_init(void)
|
||||
{
|
||||
input_register(&dummy_ops);
|
||||
}
|
868
src/in_netlink.c
Normal file
868
src/in_netlink.c
Normal file
@ -0,0 +1,868 @@
|
||||
/*
|
||||
* in_netlink.c Netlink input
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/attr.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/input.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static int c_notc = 0;
|
||||
static struct element_group *grp;
|
||||
static struct bmon_module netlink_ops;
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/cache.h>
|
||||
#include <netlink/utils.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/tc.h>
|
||||
#include <netlink/route/qdisc.h>
|
||||
#include <netlink/route/class.h>
|
||||
#include <netlink/route/classifier.h>
|
||||
#include <netlink/route/qdisc/htb.h>
|
||||
|
||||
static struct attr_map link_attrs[] = {
|
||||
{
|
||||
.name = "bytes",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Bytes",
|
||||
.rxid = RTNL_LINK_RX_BYTES,
|
||||
.txid = RTNL_LINK_TX_BYTES,
|
||||
},
|
||||
{
|
||||
.name = "packets",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Packtes",
|
||||
.rxid = RTNL_LINK_RX_PACKETS,
|
||||
.txid = RTNL_LINK_TX_PACKETS,
|
||||
},
|
||||
{
|
||||
.name = "errors",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Errors",
|
||||
.rxid = RTNL_LINK_RX_ERRORS,
|
||||
.txid = RTNL_LINK_TX_ERRORS,
|
||||
},
|
||||
{
|
||||
.name = "drop",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Dropped",
|
||||
.rxid = RTNL_LINK_RX_DROPPED,
|
||||
.txid = RTNL_LINK_TX_DROPPED,
|
||||
},
|
||||
{
|
||||
.name = "compressed",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Compressed",
|
||||
.rxid = RTNL_LINK_RX_COMPRESSED,
|
||||
.txid = RTNL_LINK_TX_COMPRESSED,
|
||||
},
|
||||
{
|
||||
.name = "fifoerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "FIFO Error",
|
||||
.rxid = RTNL_LINK_RX_FIFO_ERR,
|
||||
.txid = RTNL_LINK_TX_FIFO_ERR,
|
||||
},
|
||||
{
|
||||
.name = "lenerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Length Error",
|
||||
.rxid = RTNL_LINK_RX_LEN_ERR,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "overerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Over Error",
|
||||
.rxid = RTNL_LINK_RX_OVER_ERR,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "crcerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "CRC Error",
|
||||
.rxid = RTNL_LINK_RX_CRC_ERR,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "frameerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Frame Error",
|
||||
.rxid = RTNL_LINK_RX_FRAME_ERR,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "misserr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Missed Error",
|
||||
.rxid = RTNL_LINK_RX_MISSED_ERR,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "aborterr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Abort Error",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_TX_ABORT_ERR,
|
||||
},
|
||||
{
|
||||
.name = "carrerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Carrier Error",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_TX_CARRIER_ERR,
|
||||
},
|
||||
{
|
||||
.name = "hbeaterr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Heartbeat Error",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_TX_HBEAT_ERR,
|
||||
},
|
||||
{
|
||||
.name = "winerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Window Error",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_TX_WIN_ERR,
|
||||
},
|
||||
{
|
||||
.name = "coll",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Collisions",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_COLLISIONS,
|
||||
},
|
||||
{
|
||||
.name = "mcast",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Multicast",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_MULTICAST,
|
||||
},
|
||||
{
|
||||
.name = "ip6pkts",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6Pkts",
|
||||
.rxid = RTNL_LINK_IP6_INPKTS,
|
||||
.txid = RTNL_LINK_IP6_OUTPKTS,
|
||||
},
|
||||
{
|
||||
.name = "ip6discards",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6Discards",
|
||||
.rxid = RTNL_LINK_IP6_INDISCARDS,
|
||||
.txid = RTNL_LINK_IP6_OUTDISCARDS,
|
||||
},
|
||||
{
|
||||
.name = "ip6octets",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Ip6Octets",
|
||||
.rxid = RTNL_LINK_IP6_INOCTETS,
|
||||
.txid = RTNL_LINK_IP6_OUTOCTETS,
|
||||
},
|
||||
{
|
||||
.name = "ip6bcastp",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Broadcast Packets",
|
||||
.rxid = RTNL_LINK_IP6_INBCASTPKTS,
|
||||
.txid = RTNL_LINK_IP6_OUTBCASTPKTS,
|
||||
},
|
||||
{
|
||||
.name = "ip6bcast",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Ip6 Broadcast",
|
||||
.rxid = RTNL_LINK_IP6_INBCASTOCTETS,
|
||||
.txid = RTNL_LINK_IP6_OUTBCASTOCTETS,
|
||||
},
|
||||
{
|
||||
.name = "ip6mcastp",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Multicast Packets",
|
||||
.rxid = RTNL_LINK_IP6_INMCASTPKTS,
|
||||
.txid = RTNL_LINK_IP6_OUTMCASTPKTS,
|
||||
},
|
||||
{
|
||||
.name = "ip6mcast",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Ip6 Multicast",
|
||||
.rxid = RTNL_LINK_IP6_INMCASTOCTETS,
|
||||
.txid = RTNL_LINK_IP6_OUTMCASTOCTETS,
|
||||
},
|
||||
{
|
||||
.name = "ip6noroute",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 No Route",
|
||||
.rxid = RTNL_LINK_IP6_INNOROUTES,
|
||||
.txid = RTNL_LINK_IP6_OUTNOROUTES,
|
||||
},
|
||||
{
|
||||
.name = "ip6forward",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Forwarded",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_LINK_IP6_OUTFORWDATAGRAMS,
|
||||
},
|
||||
{
|
||||
.name = "ip6delivers",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Delivers",
|
||||
.rxid = RTNL_LINK_IP6_INDELIVERS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "icmp6",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "ICMPv6",
|
||||
.rxid = RTNL_LINK_ICMP6_INMSGS,
|
||||
.txid = RTNL_LINK_ICMP6_OUTMSGS,
|
||||
},
|
||||
{
|
||||
.name = "icmp6err",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "ICMPv6 Errors",
|
||||
.rxid = RTNL_LINK_ICMP6_INERRORS,
|
||||
.txid = RTNL_LINK_ICMP6_OUTERRORS,
|
||||
},
|
||||
{
|
||||
.name = "ip6inhdrerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Header Error",
|
||||
.rxid = RTNL_LINK_IP6_INHDRERRORS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6toobigerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Too Big Error",
|
||||
.rxid = RTNL_LINK_IP6_INTOOBIGERRORS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6trunc",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Truncated Packets",
|
||||
.rxid = RTNL_LINK_IP6_INTRUNCATEDPKTS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6unkproto",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Unknown Protocol Error",
|
||||
.rxid = RTNL_LINK_IP6_INUNKNOWNPROTOS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6addrerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Address Error",
|
||||
.rxid = RTNL_LINK_IP6_INADDRERRORS,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6reasmtimeo",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Reassembly Timeouts",
|
||||
.rxid = RTNL_LINK_IP6_REASMTIMEOUT,
|
||||
.txid = -1,
|
||||
},
|
||||
{
|
||||
.name = "ip6fragok",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Reasm/Frag OK",
|
||||
.rxid = RTNL_LINK_IP6_REASMOKS,
|
||||
.txid = RTNL_LINK_IP6_FRAGOKS,
|
||||
},
|
||||
{
|
||||
.name = "ip6fragfail",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Reasm/Frag Failures",
|
||||
.rxid = RTNL_LINK_IP6_REASMFAILS,
|
||||
.txid = RTNL_LINK_IP6_FRAGFAILS,
|
||||
},
|
||||
{
|
||||
.name = "ip6fragcreate",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Ip6 Reasm/Frag Requests",
|
||||
.rxid = RTNL_LINK_IP6_REASMREQDS,
|
||||
.txid = RTNL_LINK_IP6_FRAGCREATES,
|
||||
}
|
||||
};
|
||||
|
||||
static struct attr_map tc_attrs[] = {
|
||||
{
|
||||
.name = "tc_bytes",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Bytes",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_BYTES,
|
||||
},
|
||||
{
|
||||
.name = "tc_packets",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Packets",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_PACKETS,
|
||||
},
|
||||
{
|
||||
.name = "tc_overlimits",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Overlimits",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_OVERLIMITS,
|
||||
},
|
||||
{
|
||||
.name = "tc_drop",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Dropped",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_DROPS,
|
||||
},
|
||||
{
|
||||
.name = "tc_bps",
|
||||
.type = ATTR_TYPE_RATE,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Byte Rate/s",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_RATE_BPS,
|
||||
},
|
||||
{
|
||||
.name = "tc_pps",
|
||||
.type = ATTR_TYPE_RATE,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Packet Rate/s",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_RATE_PPS,
|
||||
},
|
||||
{
|
||||
.name = "tc_qlen",
|
||||
.type = ATTR_TYPE_RATE,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Queue Length",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_QLEN,
|
||||
},
|
||||
{
|
||||
.name = "tc_backlog",
|
||||
.type = ATTR_TYPE_RATE,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Backlog",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_BACKLOG,
|
||||
},
|
||||
{
|
||||
.name = "tc_requeues",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Requeues",
|
||||
.rxid = -1,
|
||||
.txid = RTNL_TC_REQUEUES,
|
||||
}
|
||||
};
|
||||
|
||||
struct rdata {
|
||||
struct element * parent;
|
||||
int level;
|
||||
};
|
||||
|
||||
static struct nl_sock *sock;
|
||||
static struct nl_cache *link_cache, *qdisc_cache, *class_cache;
|
||||
|
||||
static void update_tc_attrs(struct element *e, struct rtnl_tc *tc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tc_attrs); i++) {
|
||||
uint64_t c_tx = rtnl_tc_get_stat(tc, tc_attrs[i].txid);
|
||||
attr_update(e, tc_attrs[i].attrid, 0, c_tx, UPDATE_FLAG_TX);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_tc_infos(struct element *e, struct rtnl_tc *tc)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mtu(tc));
|
||||
element_update_info(e, "MTU", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mpu(tc));
|
||||
element_update_info(e, "MPU", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_overhead(tc));
|
||||
element_update_info(e, "Overhead", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_handle(tc));
|
||||
element_update_info(e, "Id", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_parent(tc));
|
||||
element_update_info(e, "Parent", buf);
|
||||
|
||||
}
|
||||
|
||||
static void handle_qdisc(struct nl_object *obj, void *);
|
||||
static void find_classes(uint32_t, struct rdata *);
|
||||
static void find_qdiscs(uint32_t, struct rdata *);
|
||||
|
||||
static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
|
||||
struct rdata *rdata)
|
||||
{
|
||||
char buf[IFNAME_MAX], name[IFNAME_MAX];
|
||||
uint32_t id = rtnl_tc_get_handle(tc);
|
||||
struct element *e;
|
||||
|
||||
rtnl_tc_handle2str(id, buf, sizeof(buf));
|
||||
snprintf(name, sizeof(name), "%s %s (%s)",
|
||||
prefix, buf, rtnl_tc_get_kind(tc));
|
||||
|
||||
if (!(e = element_lookup(grp, name, id, rdata ? rdata->parent : NULL, ELEMENT_CREAT)))
|
||||
return NULL;
|
||||
|
||||
if (e->e_flags & ELEMENT_FLAG_CREATED) {
|
||||
e->e_level = rdata ? rdata->level : 0;
|
||||
|
||||
if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
|
||||
element_set_usage_attr(e, "tc_bytes"))
|
||||
BUG();
|
||||
|
||||
update_tc_infos(e, tc);
|
||||
|
||||
e->e_flags &= ~ELEMENT_FLAG_CREATED;
|
||||
}
|
||||
|
||||
update_tc_attrs(e, tc);
|
||||
|
||||
element_notify_update(e, NULL);
|
||||
element_lifesign(e, 1);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static void handle_cls(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct rtnl_cls *cls = (struct rtnl_cls *) obj;
|
||||
struct rdata *rdata = arg;
|
||||
|
||||
handle_tc_obj((struct rtnl_tc *) cls, "cls", rdata);
|
||||
}
|
||||
|
||||
static void handle_class(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct rtnl_tc *tc = (struct rtnl_tc *) obj;
|
||||
struct element *e;
|
||||
struct rdata *rdata = arg;
|
||||
struct rdata ndata = {
|
||||
.level = rdata->level + 1,
|
||||
};
|
||||
|
||||
if (!(e = handle_tc_obj(tc, "class", rdata)))
|
||||
return;
|
||||
|
||||
ndata.parent = e;
|
||||
|
||||
if (!strcmp(rtnl_tc_get_kind(tc), "htb"))
|
||||
element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc));
|
||||
|
||||
find_classes(rtnl_tc_get_handle(tc), &ndata);
|
||||
find_qdiscs(rtnl_tc_get_handle(tc), &ndata);
|
||||
}
|
||||
|
||||
static void find_qdiscs(uint32_t parent, struct rdata *rdata)
|
||||
{
|
||||
struct rtnl_qdisc *filter;
|
||||
|
||||
if (!(filter = rtnl_qdisc_alloc()))
|
||||
return;
|
||||
|
||||
rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
|
||||
|
||||
nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
|
||||
handle_qdisc, rdata);
|
||||
|
||||
rtnl_qdisc_put(filter);
|
||||
}
|
||||
|
||||
static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata)
|
||||
{
|
||||
struct nl_cache *cls_cache;
|
||||
|
||||
if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
|
||||
return;
|
||||
|
||||
nl_cache_foreach(cls_cache, handle_cls, rdata);
|
||||
|
||||
nl_cache_free(cls_cache);
|
||||
}
|
||||
|
||||
static void find_classes(uint32_t parent, struct rdata *rdata)
|
||||
{
|
||||
struct rtnl_class *filter;
|
||||
|
||||
if (!(filter = rtnl_class_alloc()))
|
||||
return;
|
||||
|
||||
rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
|
||||
|
||||
nl_cache_foreach_filter(class_cache, OBJ_CAST(filter),
|
||||
handle_class, rdata);
|
||||
|
||||
rtnl_class_put(filter);
|
||||
}
|
||||
|
||||
static void handle_qdisc(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct rtnl_tc *tc = (struct rtnl_tc *) obj;
|
||||
struct element *e;
|
||||
struct rdata *rdata = arg;
|
||||
struct rdata ndata = {
|
||||
.level = rdata->level + 1,
|
||||
};
|
||||
|
||||
if (!(e = handle_tc_obj(tc, "qdisc", rdata)))
|
||||
return;
|
||||
|
||||
ndata.parent = e;
|
||||
|
||||
find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);
|
||||
|
||||
if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
|
||||
find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata);
|
||||
find_classes(TC_H_ROOT, &ndata);
|
||||
}
|
||||
|
||||
find_classes(rtnl_tc_get_handle(tc), &ndata);
|
||||
}
|
||||
|
||||
static void handle_tc(struct element *e, struct rtnl_link *link)
|
||||
{
|
||||
struct rtnl_qdisc *qdisc;
|
||||
int ifindex = rtnl_link_get_ifindex(link);
|
||||
struct rdata rdata = {
|
||||
.level = 1,
|
||||
.parent = e,
|
||||
};
|
||||
|
||||
if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
|
||||
return;
|
||||
|
||||
qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
|
||||
if (qdisc) {
|
||||
handle_qdisc(OBJ_CAST(qdisc), &rdata);
|
||||
rtnl_qdisc_put(qdisc);
|
||||
}
|
||||
|
||||
qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
|
||||
if (qdisc) {
|
||||
handle_qdisc(OBJ_CAST(qdisc), &rdata);
|
||||
rtnl_qdisc_put(qdisc);
|
||||
}
|
||||
|
||||
qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
|
||||
if (qdisc) {
|
||||
handle_qdisc(OBJ_CAST(qdisc), &rdata);
|
||||
rtnl_qdisc_put(qdisc);
|
||||
}
|
||||
|
||||
nl_cache_free(class_cache);
|
||||
}
|
||||
|
||||
static void update_link_infos(struct element *e, struct rtnl_link *link)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link));
|
||||
element_update_info(e, "MTU", buf);
|
||||
|
||||
rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf));
|
||||
element_update_info(e, "Flags", buf);
|
||||
|
||||
rtnl_link_operstate2str(rtnl_link_get_operstate(link),
|
||||
buf, sizeof(buf));
|
||||
element_update_info(e, "Operstate", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link));
|
||||
element_update_info(e, "IfIndex", buf);
|
||||
|
||||
nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf));
|
||||
element_update_info(e, "Address", buf);
|
||||
|
||||
nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf));
|
||||
element_update_info(e, "Broadcast", buf);
|
||||
|
||||
rtnl_link_mode2str(rtnl_link_get_linkmode(link),
|
||||
buf, sizeof(buf));
|
||||
element_update_info(e, "Mode", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link));
|
||||
element_update_info(e, "TXQlen", buf);
|
||||
|
||||
nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf));
|
||||
element_update_info(e, "Family", buf);
|
||||
|
||||
element_update_info(e, "Alias",
|
||||
rtnl_link_get_ifalias(link) ? : "");
|
||||
|
||||
element_update_info(e, "Qdisc",
|
||||
rtnl_link_get_qdisc(link) ? : "");
|
||||
|
||||
if (rtnl_link_get_link(link)) {
|
||||
snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link));
|
||||
element_update_info(e, "SlaveOfIndex", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_link(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct rtnl_link *link = (struct rtnl_link *) obj;
|
||||
struct element *e, *e_parent = NULL;
|
||||
int i, master_ifindex;
|
||||
|
||||
if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) {
|
||||
/* FIXME: delete element */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the interface is a slave of another interface */
|
||||
if ((master_ifindex = rtnl_link_get_link(link))) {
|
||||
char parent[IFNAMSIZ+1];
|
||||
|
||||
rtnl_link_i2name(link_cache, master_ifindex,
|
||||
parent, sizeof(parent));
|
||||
|
||||
e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0);
|
||||
}
|
||||
|
||||
if (!(e = element_lookup(grp, rtnl_link_get_name(link),
|
||||
rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT)))
|
||||
return;
|
||||
|
||||
if (e->e_flags & ELEMENT_FLAG_CREATED) {
|
||||
if (e->e_parent)
|
||||
e->e_level = e->e_parent->e_level + 1;
|
||||
|
||||
if (element_set_key_attr(e, "bytes", "packets") ||
|
||||
element_set_usage_attr(e, "bytes"))
|
||||
BUG();
|
||||
|
||||
/* FIXME: Update link infos every 1s or so */
|
||||
update_link_infos(e, link);
|
||||
|
||||
e->e_flags &= ~ELEMENT_FLAG_CREATED;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
|
||||
struct attr_map *m = &link_attrs[i];
|
||||
uint64_t c_rx = 0, c_tx = 0;
|
||||
int flags = 0;
|
||||
|
||||
if (m->rxid >= 0) {
|
||||
c_rx = rtnl_link_get_stat(link, m->rxid);
|
||||
flags |= UPDATE_FLAG_RX;
|
||||
}
|
||||
|
||||
if (m->txid >= 0) {
|
||||
c_tx = rtnl_link_get_stat(link, m->txid);
|
||||
flags |= UPDATE_FLAG_TX;
|
||||
}
|
||||
|
||||
attr_update(e, m->attrid, c_rx, c_tx, flags);
|
||||
}
|
||||
|
||||
if (!c_notc)
|
||||
handle_tc(e, link);
|
||||
|
||||
element_notify_update(e, NULL);
|
||||
element_lifesign(e, 1);
|
||||
}
|
||||
|
||||
static void netlink_read(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) {
|
||||
fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err));
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
|
||||
fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err));
|
||||
goto disable;
|
||||
}
|
||||
|
||||
nl_cache_foreach(link_cache, do_link, NULL);
|
||||
|
||||
return;
|
||||
|
||||
disable:
|
||||
netlink_ops.m_flags &= ~BMON_MODULE_ENABLED;
|
||||
}
|
||||
|
||||
static void netlink_shutdown(void)
|
||||
{
|
||||
nl_cache_free(link_cache);
|
||||
nl_cache_free(qdisc_cache);
|
||||
nl_socket_free(sock);
|
||||
}
|
||||
|
||||
static int netlink_do_init(void)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
if (!(sock = nl_socket_alloc())) {
|
||||
fprintf(stderr, "Unable to allocate netlink socket\n");
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0) {
|
||||
fprintf(stderr, "Unable to connect netlink socket: %s\n", nl_geterror(err));
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
|
||||
fprintf(stderr, "Unable to allocate link cache: %s\n", nl_geterror(err));
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) {
|
||||
fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err));
|
||||
goto disable;
|
||||
}
|
||||
|
||||
if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) ||
|
||||
attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs)))
|
||||
BUG();
|
||||
|
||||
if (!(grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE)))
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
|
||||
disable:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int netlink_probe(void)
|
||||
{
|
||||
struct nl_sock *sock;
|
||||
struct nl_cache *lc;
|
||||
int ret = 0;
|
||||
|
||||
if (!(sock = nl_socket_alloc()))
|
||||
return 0;
|
||||
|
||||
if (nl_connect(sock, NETLINK_ROUTE) < 0)
|
||||
return 0;
|
||||
|
||||
if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &lc) == 0) {
|
||||
nl_cache_free(lc);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
nl_socket_free(sock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"netlink - Netlink statistic collector for Linux\n" \
|
||||
"\n" \
|
||||
" Powerful statistic collector for Linux using netlink sockets\n" \
|
||||
" to collect link and traffic control statistics.\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n" \
|
||||
" Options:\n" \
|
||||
" notc Do not collect traffic control statistics\n");
|
||||
}
|
||||
|
||||
static void netlink_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "notc"))
|
||||
c_notc = 1;
|
||||
else if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bmon_module netlink_ops = {
|
||||
.m_name = "netlink",
|
||||
.m_flags = BMON_MODULE_DEFAULT,
|
||||
.m_do = netlink_read,
|
||||
.m_shutdown = netlink_shutdown,
|
||||
.m_parse_opt = netlink_parse_opt,
|
||||
.m_probe = netlink_probe,
|
||||
.m_init = netlink_do_init,
|
||||
};
|
||||
|
||||
static void __init netlink_init(void)
|
||||
{
|
||||
input_register(&netlink_ops);
|
||||
}
|
62
src/in_null.c
Normal file
62
src/in_null.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* in_null.c Null Input Method
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static void null_read(void)
|
||||
{
|
||||
DBG("null: reading...");
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"null - Do not collect statistics at all\n" \
|
||||
"\n" \
|
||||
" Will not collect any statistics at all, used to disable \n" \
|
||||
" local statistics collection.\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n");
|
||||
}
|
||||
|
||||
static void null_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bmon_module null_ops = {
|
||||
.m_name = "null",
|
||||
.m_do = null_read,
|
||||
.m_parse_opt = null_parse_opt,
|
||||
};
|
||||
|
||||
static void __init null_init(void)
|
||||
{
|
||||
input_register(&null_ops);
|
||||
}
|
234
src/in_proc.c
Normal file
234
src/in_proc.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* in_proc.c /proc/net/dev Input (Linux)
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/attr.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static const char *c_path = "/proc/net/dev";
|
||||
static const char *c_group = DEFAULT_GROUP;
|
||||
static struct element_group *grp;
|
||||
|
||||
enum {
|
||||
PROC_BYTES,
|
||||
PROC_PACKETS,
|
||||
PROC_ERRORS,
|
||||
PROC_DROP,
|
||||
PROC_COMPRESSED,
|
||||
PROC_FIFO,
|
||||
PROC_FRAME,
|
||||
PROC_MCAST,
|
||||
NUM_PROC_VALUE,
|
||||
};
|
||||
|
||||
static struct attr_map link_attrs[NUM_PROC_VALUE] = {
|
||||
{
|
||||
.name = "bytes",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_BYTE,
|
||||
.description = "Bytes",
|
||||
},
|
||||
{
|
||||
.name = "packets",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Packtes",
|
||||
},
|
||||
{
|
||||
.name = "errors",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Errors",
|
||||
},
|
||||
{
|
||||
.name = "drop",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Dropped",
|
||||
},
|
||||
{
|
||||
.name = "compressed",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Compressed",
|
||||
},
|
||||
{
|
||||
.name = "fifoerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "FIFO Error",
|
||||
},
|
||||
{
|
||||
.name = "frameerr",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Frame Error",
|
||||
},
|
||||
{
|
||||
.name = "mcast",
|
||||
.type = ATTR_TYPE_COUNTER,
|
||||
.unit = UNIT_NUMBER,
|
||||
.description = "Multicast",
|
||||
}
|
||||
};
|
||||
|
||||
static void proc_read(void)
|
||||
{
|
||||
struct element *e;
|
||||
FILE *fd;
|
||||
char buf[512], *p, *s;
|
||||
int w;
|
||||
|
||||
if (!(fd = fopen(c_path, "r")))
|
||||
quit("Unable to open file %s: %s\n", c_path, strerror(errno));
|
||||
|
||||
/* Ignore header */
|
||||
fgets(buf, sizeof(buf), fd);
|
||||
fgets(buf, sizeof(buf), fd);
|
||||
|
||||
for (; fgets(buf, sizeof(buf), fd);) {
|
||||
uint64_t data[NUM_PROC_VALUE][2];
|
||||
int i;
|
||||
|
||||
if (buf[0] == '\r' || buf[0] == '\n')
|
||||
continue;
|
||||
|
||||
if (!(p = strchr(buf, ':')))
|
||||
continue;
|
||||
*p = '\0';
|
||||
s = (p + 1);
|
||||
|
||||
for (p = &buf[0]; *p == ' '; p++);
|
||||
|
||||
w = sscanf(s, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " "
|
||||
"%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " "
|
||||
"%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " "
|
||||
"%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
|
||||
"\n",
|
||||
&data[PROC_BYTES][0],
|
||||
&data[PROC_PACKETS][0],
|
||||
&data[PROC_ERRORS][0],
|
||||
&data[PROC_DROP][0],
|
||||
&data[PROC_FIFO][0],
|
||||
&data[PROC_FRAME][0],
|
||||
&data[PROC_COMPRESSED][0],
|
||||
&data[PROC_MCAST][0],
|
||||
&data[PROC_BYTES][1],
|
||||
&data[PROC_PACKETS][1],
|
||||
&data[PROC_ERRORS][1],
|
||||
&data[PROC_DROP][1],
|
||||
&data[PROC_FIFO][1],
|
||||
&data[PROC_FRAME][1],
|
||||
&data[PROC_COMPRESSED][1],
|
||||
&data[PROC_MCAST][1]);
|
||||
|
||||
if (w != 16)
|
||||
continue;
|
||||
|
||||
if (!(e = element_lookup(grp, p, 0, NULL, ELEMENT_CREAT)))
|
||||
return;
|
||||
|
||||
if (e->e_flags & ELEMENT_FLAG_CREATED) {
|
||||
if (element_set_key_attr(e, "bytes", "packets") ||
|
||||
element_set_usage_attr(e, "bytes"))
|
||||
BUG();
|
||||
|
||||
e->e_flags &= ~ELEMENT_FLAG_CREATED;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(link_attrs); i++) {
|
||||
struct attr_map *m = &link_attrs[i];
|
||||
|
||||
attr_update(e, m->attrid, data[i][0], data[i][1],
|
||||
UPDATE_FLAG_RX | UPDATE_FLAG_TX);
|
||||
}
|
||||
|
||||
element_notify_update(e, NULL);
|
||||
element_lifesign(e, 1);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"proc - procfs statistic collector for Linux" \
|
||||
"\n" \
|
||||
" Reads statistics from procfs (/proc/net/dev)\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n" \
|
||||
" Options:\n" \
|
||||
" file=PATH Path to statistics file (default: /proc/net/dev)\n"
|
||||
" group=NAME Name of group\n");
|
||||
}
|
||||
|
||||
static void proc_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "file") && value)
|
||||
c_path = value;
|
||||
else if (!strcasecmp(type, "group") && value)
|
||||
c_group = value;
|
||||
else if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int proc_do_init(void)
|
||||
{
|
||||
if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) ||
|
||||
!(grp = group_lookup(c_group, GROUP_CREATE)))
|
||||
BUG();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proc_probe(void)
|
||||
{
|
||||
FILE *fd = fopen(c_path, "r");
|
||||
|
||||
if (fd) {
|
||||
fclose(fd);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bmon_module proc_ops = {
|
||||
.m_name = "proc",
|
||||
.m_do = proc_read,
|
||||
.m_parse_opt = proc_parse_opt,
|
||||
.m_probe = proc_probe,
|
||||
.m_init = proc_do_init,
|
||||
};
|
||||
|
||||
static void __init proc_init(void)
|
||||
{
|
||||
input_register(&proc_ops);
|
||||
}
|
83
src/input.c
Normal file
83
src/input.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* input.c Input API
|
||||
*
|
||||
* 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/input.h>
|
||||
#include <bmon/module.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static struct bmon_subsys input_subsys;
|
||||
|
||||
void input_register(struct bmon_module *m)
|
||||
{
|
||||
module_register(&input_subsys, m);
|
||||
}
|
||||
|
||||
static void activate_default(void)
|
||||
{
|
||||
/*
|
||||
* Try to activate a default input module if the user did not make
|
||||
* a selection
|
||||
*/
|
||||
if (!input_subsys.s_nmod) {
|
||||
struct bmon_module *m;
|
||||
|
||||
if (!input_set("netlink"))
|
||||
return;
|
||||
|
||||
if (!input_set("proc"))
|
||||
return;
|
||||
|
||||
/* Fall back to anything that could act as default */
|
||||
list_for_each_entry(m, &input_subsys.s_mod_list, m_list) {
|
||||
if (m->m_flags & BMON_MODULE_DEFAULT)
|
||||
if (!input_set(m->m_name))
|
||||
return;
|
||||
}
|
||||
|
||||
quit("No input module found\n");
|
||||
}
|
||||
}
|
||||
|
||||
void input_read(void)
|
||||
{
|
||||
module_foreach_run_enabled(&input_subsys);
|
||||
}
|
||||
|
||||
int input_set(const char *name)
|
||||
{
|
||||
return module_set(&input_subsys, name);
|
||||
}
|
||||
|
||||
static struct bmon_subsys input_subsys = {
|
||||
.s_name = "input",
|
||||
.s_activate_default = &activate_default,
|
||||
.s_mod_list = LIST_SELF(input_subsys.s_mod_list),
|
||||
};
|
||||
|
||||
static void __init __input_init(void)
|
||||
{
|
||||
module_register_subsys(&input_subsys);
|
||||
}
|
195
src/module.c
Normal file
195
src/module.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* module.c Module API
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static LIST_HEAD(subsys_list);
|
||||
|
||||
static void module_foreach(struct bmon_subsys *ss, void (*cb)(struct bmon_module *))
|
||||
{
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, &ss->s_mod_list, m_list)
|
||||
cb(m);
|
||||
}
|
||||
|
||||
void module_foreach_run_enabled_pre(struct bmon_subsys *ss)
|
||||
{
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, &ss->s_mod_list, m_list)
|
||||
if (m->m_flags & BMON_MODULE_ENABLED && m->m_pre)
|
||||
m->m_pre();
|
||||
}
|
||||
|
||||
void module_foreach_run_enabled(struct bmon_subsys *ss)
|
||||
{
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, &ss->s_mod_list, m_list)
|
||||
if (m->m_flags & BMON_MODULE_ENABLED && m->m_do)
|
||||
m->m_do();
|
||||
}
|
||||
|
||||
void module_foreach_run_enabled_post(struct bmon_subsys *ss)
|
||||
{
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, &ss->s_mod_list, m_list)
|
||||
if (m->m_flags & BMON_MODULE_ENABLED && m->m_post)
|
||||
m->m_post();
|
||||
}
|
||||
|
||||
static struct bmon_module *module_lookup(struct bmon_subsys *ss, const char *name)
|
||||
{
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, &ss->s_mod_list, m_list)
|
||||
if (!strcmp(m->m_name, name))
|
||||
return m;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void module_list(struct bmon_subsys *ss, struct list_head *list)
|
||||
{
|
||||
printf("%s modules:\n", ss->s_name);
|
||||
if (list_empty(list))
|
||||
printf("\tNo %s modules found.\n", ss->s_name);
|
||||
else {
|
||||
struct bmon_module *m;
|
||||
|
||||
list_for_each_entry(m, list, m_list)
|
||||
printf("\t%s\n", m->m_name);
|
||||
}
|
||||
}
|
||||
|
||||
static int module_configure(struct bmon_module *m, module_conf_t *cfg)
|
||||
{
|
||||
DBG("Configuring module %s", m->m_name);
|
||||
|
||||
if (m->m_parse_opt) {
|
||||
tv_t *tv;
|
||||
|
||||
list_for_each_entry(tv, &cfg->m_attrs, tv_list)
|
||||
m->m_parse_opt(tv->tv_type, tv->tv_value);
|
||||
}
|
||||
|
||||
if (m->m_probe && !m->m_probe())
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void module_register(struct bmon_subsys *ss, struct bmon_module *m)
|
||||
{
|
||||
list_add_tail(&m->m_list, &ss->s_mod_list);
|
||||
}
|
||||
|
||||
int module_set(struct bmon_subsys *ss, const char *name)
|
||||
{
|
||||
struct bmon_module *mod;
|
||||
struct list_head *list;
|
||||
LIST_HEAD(tmp_list);
|
||||
module_conf_t *m;
|
||||
int nmod = 0;
|
||||
|
||||
if (!name || !strcasecmp(name, "list")) {
|
||||
module_list(ss, &ss->s_mod_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
parse_module_param(name, &tmp_list);
|
||||
|
||||
list_for_each_entry(m, &tmp_list, m_list) {
|
||||
if (!(mod = module_lookup(ss, m->m_name)))
|
||||
quit("Unknown %s module: %s\n", ss->s_name, m->m_name);
|
||||
|
||||
if (module_configure(mod, m) == 0) {
|
||||
DBG("Enabling module %s", mod->m_name);
|
||||
mod->m_flags |= BMON_MODULE_ENABLED;
|
||||
nmod++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nmod)
|
||||
quit("No working %s module found\n", ss->s_name);
|
||||
|
||||
DBG("Configured %d modules", nmod);
|
||||
ss->s_nmod = nmod;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __module_init(struct bmon_module *m)
|
||||
{
|
||||
if (m->m_init) {
|
||||
DBG("Initializing %s...", m->m_name);
|
||||
if (m->m_init())
|
||||
m->m_flags &= ~BMON_MODULE_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
void module_init(void)
|
||||
{
|
||||
struct bmon_subsys *ss;
|
||||
|
||||
DBG("Initializing modules");
|
||||
|
||||
list_for_each_entry(ss, &subsys_list, s_list) {
|
||||
if (ss->s_activate_default)
|
||||
ss->s_activate_default();
|
||||
|
||||
module_foreach(ss, __module_init);
|
||||
}
|
||||
}
|
||||
|
||||
static void __module_shutdown(struct bmon_module *m)
|
||||
{
|
||||
if (m->m_shutdown) {
|
||||
DBG("Shutting down %s...", m->m_name);
|
||||
m->m_shutdown();
|
||||
m->m_flags &= ~BMON_MODULE_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
void module_shutdown(void)
|
||||
{
|
||||
DBG("Shutting down modules");
|
||||
|
||||
struct bmon_subsys *ss;
|
||||
|
||||
list_for_each_entry(ss, &subsys_list, s_list)
|
||||
module_foreach(ss, __module_shutdown);
|
||||
}
|
||||
|
||||
void module_register_subsys(struct bmon_subsys *ss)
|
||||
{
|
||||
DBG("Module %s registered", ss->s_name);
|
||||
|
||||
list_add_tail(&ss->s_list, &subsys_list);
|
||||
}
|
299
src/out_ascii.c
Normal file
299
src/out_ascii.c
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* out_ascii.c ASCII Output
|
||||
*
|
||||
* 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/output.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/attr.h>
|
||||
#include <bmon/graph.h>
|
||||
#include <bmon/history.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
typedef enum diagram_type_e {
|
||||
D_LIST,
|
||||
D_GRAPH,
|
||||
D_DETAILS
|
||||
} diagram_type_t;
|
||||
|
||||
static struct graph_cfg graph_cfg = {
|
||||
.gc_foreground = '*',
|
||||
.gc_background = ' ',
|
||||
.gc_noise = '.',
|
||||
.gc_unknown = '?',
|
||||
.gc_height = 6,
|
||||
};
|
||||
|
||||
static diagram_type_t c_diagram_type = D_LIST;
|
||||
static char *c_hist = "second";
|
||||
static int c_quit_after = -1;
|
||||
|
||||
static void print_list(struct element *e)
|
||||
{
|
||||
char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = "";
|
||||
double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f;
|
||||
int rx1prec, tx1prec, rx2prec, tx2prec;
|
||||
char pad[IFNAMSIZ + 32];
|
||||
struct attr *a;
|
||||
|
||||
if (e->e_key_attr[GT_MAJOR] &&
|
||||
(a = attr_lookup(e, e->e_key_attr[GT_MAJOR]->ad_id)))
|
||||
attr_rate2float(a, &rx1, &rxu1, &rx1prec,
|
||||
&tx1, &txu1, &tx1prec);
|
||||
|
||||
if (e->e_key_attr[GT_MINOR] &&
|
||||
(a = attr_lookup(e, e->e_key_attr[GT_MINOR]->ad_id)))
|
||||
attr_rate2float(a, &rx2, &rxu2, &rx2prec,
|
||||
&tx2, &txu2, &tx2prec);
|
||||
|
||||
memset(pad, 0, sizeof(pad));
|
||||
memset(pad, ' ', e->e_level < 15 ? e->e_level : 15);
|
||||
|
||||
strncat(pad, e->e_name, sizeof(pad) - strlen(pad) - 1);
|
||||
|
||||
if (e->e_description) {
|
||||
strncat(pad, " (", sizeof(pad) - strlen(pad) - 1);
|
||||
strncat(pad, e->e_description, sizeof(pad) - strlen(pad) - 1);
|
||||
strncat(pad, ")", sizeof(pad) - strlen(pad) - 1);
|
||||
}
|
||||
|
||||
printf(" %-36s %8.*f%-3s %8.*f%-3s ",
|
||||
pad, rx1prec, rx1, rxu1, rx2prec, rx2, rxu2);
|
||||
|
||||
if (e->e_rx_usage == FLT_MAX)
|
||||
printf(" ");
|
||||
else
|
||||
printf("%2.0f%%", e->e_rx_usage);
|
||||
|
||||
printf(" %8.*f%-3s %8.*f%-3s ", tx1prec, tx1, txu1, tx2prec, tx2, txu2);
|
||||
|
||||
if (e->e_tx_usage == FLT_MAX)
|
||||
printf(" \n");
|
||||
else
|
||||
printf("%2.0f%%\n", e->e_tx_usage);
|
||||
}
|
||||
|
||||
static void print_attr_detail(struct element *e, struct attr *a, void *arg)
|
||||
{
|
||||
char *rx_u, *tx_u;
|
||||
int rxprec, txprec;
|
||||
|
||||
double rx = unit_value2str(a->a_rx_rate.r_total,
|
||||
a->a_def->ad_unit,
|
||||
&rx_u, &rxprec);
|
||||
double tx = unit_value2str(a->a_tx_rate.r_total,
|
||||
a->a_def->ad_unit,
|
||||
&tx_u, &txprec);
|
||||
|
||||
printf(" %-36s %12.*f%-3s %12.*f%-3s\n",
|
||||
a->a_def->ad_description, rxprec, rx, rx_u, txprec, tx, tx_u);
|
||||
}
|
||||
|
||||
static void print_details(struct element *e)
|
||||
{
|
||||
printf(" %s", e->e_name);
|
||||
|
||||
if (e->e_id)
|
||||
printf(" (%u)", e->e_id);
|
||||
|
||||
printf("\n");
|
||||
|
||||
element_foreach_attr(e, print_attr_detail, NULL);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_table(struct graph *g, struct graph_table *tbl, const char *hdr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!tbl->gt_table)
|
||||
return;
|
||||
|
||||
printf("%s %s\n", hdr, tbl->gt_y_unit);
|
||||
|
||||
for (i = (g->g_cfg.gc_height - 1); i >= 0; i--)
|
||||
printf("%8.2f %s\n", tbl->gt_scale[i],
|
||||
tbl->gt_table + (i * graph_row_size(&g->g_cfg)));
|
||||
|
||||
printf(" 1 5 10 15 20 25 30 35 40 " \
|
||||
"45 50 55 60\n");
|
||||
}
|
||||
|
||||
static void __print_graph(struct element *e, struct attr *a, void *arg)
|
||||
{
|
||||
struct history *h;
|
||||
struct graph *g;
|
||||
|
||||
if (!(a->a_flags & ATTR_DOING_HISTORY))
|
||||
return;
|
||||
|
||||
graph_cfg.gc_unit = a->a_def->ad_unit;
|
||||
|
||||
list_for_each_entry(h, &a->a_history_list, h_list) {
|
||||
if (strcasecmp(c_hist, h->h_definition->hd_name))
|
||||
continue;
|
||||
|
||||
g = graph_alloc(h, &graph_cfg);
|
||||
graph_refill(g, h);
|
||||
|
||||
printf("Interface: %s\n", e->e_name);
|
||||
printf("Attribute: %s\n", a->a_def->ad_description);
|
||||
|
||||
print_table(g, &g->g_rx, "RX");
|
||||
print_table(g, &g->g_tx, "TX");
|
||||
|
||||
graph_free(g);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void print_graph(struct element *e)
|
||||
{
|
||||
element_foreach_attr(e, __print_graph, NULL);
|
||||
}
|
||||
|
||||
static void ascii_draw_element(struct element_group *g, struct element *e,
|
||||
void *arg)
|
||||
{
|
||||
switch (c_diagram_type) {
|
||||
case D_LIST:
|
||||
print_list(e);
|
||||
break;
|
||||
|
||||
case D_DETAILS:
|
||||
print_details(e);
|
||||
break;
|
||||
|
||||
case D_GRAPH:
|
||||
print_graph(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ascii_draw_group(struct element_group *g, void *arg)
|
||||
{
|
||||
if (c_diagram_type == D_LIST)
|
||||
printf("%-37s%10s %11s %%%10s %11s %%\n",
|
||||
g->g_hdr->gh_title,
|
||||
g->g_hdr->gh_column[0],
|
||||
g->g_hdr->gh_column[1],
|
||||
g->g_hdr->gh_column[2],
|
||||
g->g_hdr->gh_column[3]);
|
||||
else
|
||||
printf("%s\n", g->g_hdr->gh_title);
|
||||
|
||||
group_foreach_element(g, ascii_draw_element, NULL);
|
||||
}
|
||||
|
||||
static void ascii_draw(void)
|
||||
{
|
||||
group_foreach(ascii_draw_group, NULL);
|
||||
|
||||
if (c_quit_after > 0)
|
||||
if (--c_quit_after == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"ascii - ASCII Output\n" \
|
||||
"\n" \
|
||||
" Plain configurable ASCII output.\n" \
|
||||
"\n" \
|
||||
" scriptable: (output graph for eth1 10 times)\n" \
|
||||
" bmon -p eth1 -o 'ascii:diagram=graph;quitafter=10'\n" \
|
||||
" show details for all ethernet interfaces:\n" \
|
||||
" bmon -p 'eth*' -o 'ascii:diagram=details;quitafter=1'\n" \
|
||||
"\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n" \
|
||||
" Options:\n" \
|
||||
" diagram=TYPE Diagram type\n" \
|
||||
" fgchar=CHAR Foreground character (default: '*')\n" \
|
||||
" bgchar=CHAR Background character (default: '.')\n" \
|
||||
" nchar=CHAR Noise character (default: ':')\n" \
|
||||
" uchar=CHAR Unknown character (default: '?')\n" \
|
||||
" height=NUM Height of graph (default: 6)\n" \
|
||||
" xunit=UNIT X-Axis Unit (default: seconds)\n" \
|
||||
" yunit=UNIT Y-Axis Unit (default: dynamic)\n" \
|
||||
" quitafter=NUM Quit bmon after NUM outputs\n");
|
||||
}
|
||||
|
||||
static void ascii_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "diagram") && value) {
|
||||
if (tolower(*value) == 'l')
|
||||
c_diagram_type = D_LIST;
|
||||
else if (tolower(*value) == 'g')
|
||||
c_diagram_type = D_GRAPH;
|
||||
else if (tolower(*value) == 'd')
|
||||
c_diagram_type = D_DETAILS;
|
||||
else
|
||||
quit("Unknown diagram type '%s'\n", value);
|
||||
} else if (!strcasecmp(type, "fgchar") && value)
|
||||
graph_cfg.gc_foreground = value[0];
|
||||
else if (!strcasecmp(type, "bgchar") && value)
|
||||
graph_cfg.gc_background = value[0];
|
||||
else if (!strcasecmp(type, "nchar") && value)
|
||||
graph_cfg.gc_noise = value[0];
|
||||
#if 0
|
||||
else if (!strcasecmp(type, "uchar") && value)
|
||||
set_unk_char(value[0]);
|
||||
#endif
|
||||
else if (!strcasecmp(type, "xunit") && value)
|
||||
c_hist = strdup(value);
|
||||
#if 0
|
||||
else if (!strcasecmp(type, "yunit") && value) {
|
||||
struct unit *u;
|
||||
|
||||
if (!(u = unit_lookup(value)))
|
||||
quit("Unknown unit '%s'\n", value);
|
||||
|
||||
graph_cfg.gc_unit = u;
|
||||
#endif
|
||||
else if (!strcasecmp(type, "height") && value)
|
||||
graph_cfg.gc_height = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "quitafter") && value)
|
||||
c_quit_after = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
} else
|
||||
quit("Unknown module option '%s'\n", type);
|
||||
}
|
||||
|
||||
static struct bmon_module ascii_ops = {
|
||||
.m_name = "ascii",
|
||||
.m_do = ascii_draw,
|
||||
.m_parse_opt = ascii_parse_opt,
|
||||
};
|
||||
|
||||
static void __init ascii_init(void)
|
||||
{
|
||||
output_register(&ascii_ops);
|
||||
}
|
1277
src/out_curses.c
Normal file
1277
src/out_curses.c
Normal file
File diff suppressed because it is too large
Load Diff
373
src/out_format.c
Normal file
373
src/out_format.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* out_format.c Formatted Output
|
||||
*
|
||||
* 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/graph.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/output.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/element.h>
|
||||
#include <bmon/input.h>
|
||||
#include <bmon/utils.h>
|
||||
#include <bmon/attr.h>
|
||||
|
||||
static int c_quit_after = -1;
|
||||
static char *c_format;
|
||||
static int c_debug = 0;
|
||||
static FILE *c_fd;
|
||||
|
||||
enum {
|
||||
OT_STRING,
|
||||
OT_TOKEN
|
||||
};
|
||||
|
||||
static struct out_token {
|
||||
int ot_type;
|
||||
char *ot_str;
|
||||
} *out_tokens;
|
||||
|
||||
static int token_index;
|
||||
static int out_tokens_size;
|
||||
|
||||
static char *get_token(struct element_group *g, struct element *e,
|
||||
const char *token, char *buf, size_t len)
|
||||
{
|
||||
if (!strncasecmp(token, "group:", 6)) {
|
||||
const char *n = token + 6;
|
||||
|
||||
if (!strcasecmp(n, "nelements")) {
|
||||
snprintf(buf, len, "%u", g->g_nelements);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "name"))
|
||||
return g->g_name;
|
||||
else if (!strcasecmp(n, "title"))
|
||||
return g->g_hdr->gh_title;
|
||||
|
||||
} else if (!strncasecmp(token, "element:", 8)) {
|
||||
const char *n = token + 8;
|
||||
|
||||
if (!strcasecmp(n, "name"))
|
||||
return e->e_name;
|
||||
else if (!strcasecmp(n, "description"))
|
||||
return e->e_description;
|
||||
else if (!strcasecmp(n, "nattrs")) {
|
||||
snprintf(buf, len, "%u", e->e_nattrs);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "lifecycles")) {
|
||||
snprintf(buf, len, "%u", e->e_lifecycles);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "level")) {
|
||||
snprintf(buf, len, "%u", e->e_level);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "parent"))
|
||||
return e->e_parent ? e->e_parent->e_name : "";
|
||||
else if (!strcasecmp(n, "id")) {
|
||||
snprintf(buf, len, "%u", e->e_id);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "rxusage")) {
|
||||
snprintf(buf, len, "%2.0f",
|
||||
e->e_rx_usage == FLT_MAX ? e->e_rx_usage : 0.0f);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "txusage")) {
|
||||
snprintf(buf, len, "%2.0f",
|
||||
e->e_tx_usage == FLT_MAX ? e->e_tx_usage : 0.0f);
|
||||
return buf;
|
||||
} else if (!strcasecmp(n, "haschilds")) {
|
||||
snprintf(buf, len, "%u",
|
||||
list_empty(&e->e_childs) ? 0 : 1);
|
||||
return buf;
|
||||
}
|
||||
} else if (!strncasecmp(token, "attr:", 5)) {
|
||||
const char *type = token + 5;
|
||||
char *name = strchr(type, ':');
|
||||
struct attr_def *def;
|
||||
struct attr *a;
|
||||
|
||||
if (!name) {
|
||||
fprintf(stderr, "Invalid attribute field \"%s\"\n",
|
||||
type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
name++;
|
||||
|
||||
def = attr_def_lookup(name);
|
||||
if (!def) {
|
||||
fprintf(stderr, "Undefined attribute \"%s\"\n", name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(a = attr_lookup(e, def->ad_id))) {
|
||||
fprintf(stderr, "Unable to find attribute %u (%s)\n",
|
||||
def->ad_id, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strncasecmp(type, "rx:", 3)) {
|
||||
snprintf(buf, len, "%lu", a->a_rx_rate.r_total);
|
||||
return buf;
|
||||
} else if (!strncasecmp(type, "tx:", 3)) {
|
||||
snprintf(buf, len, "%lu", a->a_tx_rate.r_total);
|
||||
return buf;
|
||||
} else if (!strncasecmp(type, "rxrate:", 7)) {
|
||||
snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate);
|
||||
return buf;
|
||||
} else if (!strncasecmp(token+5, "txrate:", 7))
|
||||
snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate);
|
||||
return buf;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unknown field \"%s\"\n", token);
|
||||
out:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void draw_element(struct element_group *g, struct element *e, void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < token_index; i++) {
|
||||
char buf[128];
|
||||
char *p;
|
||||
|
||||
if (out_tokens[i].ot_type == OT_STRING)
|
||||
p = out_tokens[i].ot_str;
|
||||
else if (out_tokens[i].ot_type == OT_TOKEN)
|
||||
p = get_token(g, e, out_tokens[i].ot_str,
|
||||
buf, sizeof(buf));
|
||||
else
|
||||
BUG();
|
||||
|
||||
if (p)
|
||||
fprintf(c_fd, "%s", p);
|
||||
}
|
||||
}
|
||||
|
||||
static void format_draw(void)
|
||||
{
|
||||
group_foreach_recursive(draw_element, NULL);
|
||||
|
||||
if (c_quit_after > 0)
|
||||
if (--c_quit_after == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static inline void add_token(int type, char *data)
|
||||
{
|
||||
if (!out_tokens_size) {
|
||||
out_tokens_size = 32;
|
||||
out_tokens = calloc(out_tokens_size, sizeof(struct out_token));
|
||||
if (out_tokens == NULL)
|
||||
quit("Cannot allocate out token array\n");
|
||||
}
|
||||
|
||||
if (out_tokens_size <= token_index) {
|
||||
out_tokens_size += 32;
|
||||
out_tokens = realloc(out_tokens, out_tokens_size * sizeof(struct out_token));
|
||||
if (out_tokens == NULL)
|
||||
quit("Cannot reallocate out token array\n");
|
||||
}
|
||||
|
||||
|
||||
out_tokens[token_index].ot_type = type;
|
||||
out_tokens[token_index].ot_str = data;
|
||||
token_index++;
|
||||
}
|
||||
|
||||
static int format_probe(void)
|
||||
{
|
||||
int new_one = 1;
|
||||
char *p, *e;
|
||||
|
||||
for (p = c_format; *p; p++) {
|
||||
if (*p == '$') {
|
||||
char *s = p;
|
||||
s++;
|
||||
if (*s == '(') {
|
||||
s++;
|
||||
if (!*s)
|
||||
goto unexpected_end;
|
||||
e = strchr(s, ')');
|
||||
if (e == NULL)
|
||||
goto invalid;
|
||||
|
||||
*p = '\0';
|
||||
*e = '\0';
|
||||
add_token(OT_TOKEN, s);
|
||||
new_one = 1;
|
||||
p = e;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p == '\\') {
|
||||
char *s = p;
|
||||
s++;
|
||||
switch (*s) {
|
||||
case 'n':
|
||||
*s = '\n';
|
||||
goto finish_escape;
|
||||
case 't':
|
||||
*s = '\t';
|
||||
goto finish_escape;
|
||||
case 'r':
|
||||
*s = '\r';
|
||||
goto finish_escape;
|
||||
case 'v':
|
||||
*s = '\v';
|
||||
goto finish_escape;
|
||||
case 'b':
|
||||
*s = '\b';
|
||||
goto finish_escape;
|
||||
case 'f':
|
||||
*s = '\f';
|
||||
goto finish_escape;
|
||||
case 'a':
|
||||
*s = '\a';
|
||||
goto finish_escape;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
finish_escape:
|
||||
*p = '\0';
|
||||
add_token(OT_STRING, s);
|
||||
p = s;
|
||||
new_one = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
out:
|
||||
if (new_one) {
|
||||
add_token(OT_STRING, p);
|
||||
new_one = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (c_debug) {
|
||||
int i;
|
||||
for (i = 0; i < token_index; i++)
|
||||
printf(">>%s<\n", out_tokens[i].ot_str);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
unexpected_end:
|
||||
fprintf(stderr, "Unexpected end of format string\n");
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
fprintf(stderr, "Missing ')' in format string\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"format - Formatable Output\n" \
|
||||
"\n" \
|
||||
" Formatable ASCII output for scripts. Calls a drawing function for\n" \
|
||||
" every item per node and outputs according to the specified format\n" \
|
||||
" string. The format string consists of normal text and placeholders\n" \
|
||||
" in the form of $(placeholder).\n" \
|
||||
"\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n" \
|
||||
" Options:\n" \
|
||||
" fmt=FORMAT Format string\n" \
|
||||
" stderr Write to stderr instead of stdout\n" \
|
||||
" quitafter=NUM Quit bmon after NUM outputs\n" \
|
||||
"\n" \
|
||||
" Placeholders:\n" \
|
||||
" group:nelements Number of elements this group\n" \
|
||||
" :name Name of group\n" \
|
||||
" :title Title of group\n" \
|
||||
" element:name Name of element\n" \
|
||||
" :desc Description of element\n" \
|
||||
" :nattrs Number of attributes\n" \
|
||||
" :lifecycles Number of lifecycles\n" \
|
||||
" :level Indentation level\n" \
|
||||
" :parent Name of parent element\n" \
|
||||
" :rxusage RX usage in percent\n" \
|
||||
" :txusage TX usage in percent)\n" \
|
||||
" :id ID of element\n" \
|
||||
" :haschilds Indicate if element has childs (0|1)\n" \
|
||||
" attr:rx:<name> RX counter of attribute <name>\n" \
|
||||
" :tx:<name> TX counter of attribute <name>\n" \
|
||||
" :rxrate:<name> RX rate of attribute <name>\n" \
|
||||
" :txrate:<name> TX rate of attribute <name>\n" \
|
||||
"\n" \
|
||||
" Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \
|
||||
"\n" \
|
||||
" Examples:\n" \
|
||||
" \"$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n\"\n" \
|
||||
" lo 12074 12074\n" \
|
||||
"\n" \
|
||||
" \"$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n\"\n" \
|
||||
" eth0 33 5\n" \
|
||||
"\n" \
|
||||
" \"Element: $(element:name)\\nBytes Rate: \" \\\n" \
|
||||
" \"$(attr:rxrate:bytes)/$(attr:txrate:bytes)\\nPackets Rate: \" \\\n" \
|
||||
" \"$(attr:rxrate:packets)/$(attr:txrate:packets)\\n\"\n" \
|
||||
" Item: eth0\n" \
|
||||
" Bytes Rate: 49130/2119\n" \
|
||||
" Packets Rate: 40/11\n" \
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void format_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "stderr"))
|
||||
c_fd = stderr;
|
||||
else if (!strcasecmp(type, "debug"))
|
||||
c_debug = 1;
|
||||
else if (!strcasecmp(type, "fmt")) {
|
||||
if (c_format)
|
||||
free(c_format);
|
||||
c_format = strdup(value);
|
||||
} else if (!strcasecmp(type, "quitafter") &&
|
||||
value)
|
||||
c_quit_after = strtol(value, NULL, 0);
|
||||
else if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bmon_module format_ops = {
|
||||
.m_name = "format",
|
||||
.m_do = format_draw,
|
||||
.m_probe = format_probe,
|
||||
.m_parse_opt = format_parse_opt,
|
||||
};
|
||||
|
||||
static void __init ascii_init(void)
|
||||
{
|
||||
c_fd = stdout;
|
||||
c_format = strdup("$(element:name) $(attr:rx:bytes) $(attr:tx:bytes) " \
|
||||
"$(attr:rx:packets) $(attr:tx:packets)\\n");
|
||||
|
||||
output_register(&format_ops);
|
||||
}
|
56
src/out_null.c
Normal file
56
src/out_null.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* out_null.c Null Output
|
||||
*
|
||||
* 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/output.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"null - No output\n" \
|
||||
"\n" \
|
||||
" Disable primary output method\n" \
|
||||
" Author: Thomas Graf <tgraf@suug.ch>\n" \
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void null_parse_opt(const char *type, const char *value)
|
||||
{
|
||||
if (!strcasecmp(type, "help")) {
|
||||
print_help();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bmon_module null_ops = {
|
||||
.m_name = "null",
|
||||
.m_parse_opt = null_parse_opt,
|
||||
};
|
||||
|
||||
static void __init null_init(void)
|
||||
{
|
||||
output_register(&null_ops);
|
||||
}
|
95
src/output.c
Normal file
95
src/output.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* output.c Output API
|
||||
*
|
||||
* 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/output.h>
|
||||
#include <bmon/module.h>
|
||||
#include <bmon/conf.h>
|
||||
#include <bmon/group.h>
|
||||
#include <bmon/utils.h>
|
||||
|
||||
static struct bmon_subsys output_subsys;
|
||||
|
||||
void output_register(struct bmon_module *m)
|
||||
{
|
||||
module_register(&output_subsys, m);
|
||||
}
|
||||
|
||||
static void activate_default(void)
|
||||
{
|
||||
/*
|
||||
* Try to activate a default output module if the user did not make
|
||||
* a selection
|
||||
*/
|
||||
if (!output_subsys.s_nmod) {
|
||||
struct bmon_module *m;
|
||||
|
||||
if (!output_set("curses"))
|
||||
return;
|
||||
|
||||
if (!output_set("ascii"))
|
||||
return;
|
||||
|
||||
/* Fall back to anything that could act as default */
|
||||
list_for_each_entry(m, &output_subsys.s_mod_list, m_list) {
|
||||
if (m->m_flags & BMON_MODULE_DEFAULT)
|
||||
if (!output_set(m->m_name))
|
||||
return;
|
||||
}
|
||||
|
||||
quit("No output module found\n");
|
||||
}
|
||||
}
|
||||
|
||||
void output_pre(void)
|
||||
{
|
||||
module_foreach_run_enabled_pre(&output_subsys);
|
||||
}
|
||||
|
||||
void output_draw(void)
|
||||
{
|
||||
module_foreach_run_enabled(&output_subsys);
|
||||
}
|
||||
|
||||
void output_post(void)
|
||||
{
|
||||
module_foreach_run_enabled_post(&output_subsys);
|
||||
}
|
||||
|
||||
int output_set(const char *name)
|
||||
{
|
||||
return module_set(&output_subsys, name);
|
||||
}
|
||||
|
||||
static struct bmon_subsys output_subsys = {
|
||||
.s_name = "output",
|
||||
.s_activate_default = &activate_default,
|
||||
.s_mod_list = LIST_SELF(output_subsys.s_mod_list),
|
||||
};
|
||||
|
||||
static void __init __output_init(void)
|
||||
{
|
||||
return module_register_subsys(&output_subsys);
|
||||
}
|
216
src/unit.c
Normal file
216
src/unit.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* unit.c Unit Definitions
|
||||
*
|
||||
* 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/utils.h>
|
||||
#include <bmon/unit.h>
|
||||
|
||||
static struct unit *byte_unit, *bit_unit, *number_unit;
|
||||
|
||||
static LIST_HEAD(units);
|
||||
|
||||
static struct list_head *get_flist(struct unit *unit)
|
||||
{
|
||||
static int cached = 0, div = UNIT_DEFAULT;
|
||||
|
||||
if (!cached && cfg_getbool(cfg, "use_si"))
|
||||
div = UNIT_SI;
|
||||
|
||||
if (!list_empty(&unit->u_div[UNIT_SI]) && div == UNIT_SI)
|
||||
return &unit->u_div[UNIT_SI];
|
||||
else
|
||||
return &unit->u_div[UNIT_DEFAULT];
|
||||
}
|
||||
|
||||
struct unit *unit_lookup(const char *name)
|
||||
{
|
||||
struct unit *unit;
|
||||
|
||||
list_for_each_entry(unit, &units, u_list)
|
||||
if (!strcmp(name, unit->u_name))
|
||||
return unit;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup best divisor to use for a certain situation
|
||||
* @hint Value in question (for DYNAMIC_EXP)
|
||||
* @unit Unit of value
|
||||
* @name Place to store name of divisor used
|
||||
* @prec Place to store suggested precision
|
||||
*
|
||||
* Searches for the best divisor to be used depending on the unit
|
||||
* exponent configured by the user. If a dynamic exponent is
|
||||
* configured, the divisor is selected based on the value of hint
|
||||
* so that hint is dividied into a small float >= 1.0. The name
|
||||
* of the divisor used is stored in *name.
|
||||
*
|
||||
* If prec points to a vaild integer, a number of precision digits
|
||||
* is suggested to avoid n.00 to make pretty printing easier.
|
||||
*/
|
||||
uint64_t unit_divisor(uint64_t hint, struct unit *unit, char **name,
|
||||
int *prec)
|
||||
{
|
||||
struct list_head *flist = get_flist(unit);
|
||||
struct fraction *f;
|
||||
|
||||
if (prec)
|
||||
*prec = 2;
|
||||
|
||||
if (cfg_unit_exp == DYNAMIC_EXP) {
|
||||
list_for_each_entry_reverse(f, flist, f_list) {
|
||||
if (hint >= f->f_divisor)
|
||||
goto found_it;
|
||||
}
|
||||
} else {
|
||||
int n = cfg_unit_exp;
|
||||
list_for_each_entry(f, flist, f_list) {
|
||||
if (--n == 0)
|
||||
goto found_it;
|
||||
}
|
||||
}
|
||||
|
||||
*name = "";
|
||||
return 1;
|
||||
|
||||
found_it:
|
||||
if (f->f_divisor == 1 && prec)
|
||||
*prec = 0;
|
||||
|
||||
*name = f->f_name;
|
||||
return f->f_divisor;
|
||||
}
|
||||
|
||||
double unit_value2str(uint64_t value, struct unit *unit,
|
||||
char **name, int *prec)
|
||||
{
|
||||
uint64_t div = unit_divisor(value, unit, name, prec);
|
||||
|
||||
if (value % div == 0 && prec)
|
||||
*prec = 0;
|
||||
|
||||
return (double) value / (double) div;
|
||||
}
|
||||
|
||||
void fraction_free(struct fraction *f)
|
||||
{
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
xfree(f->f_name);
|
||||
xfree(f);
|
||||
}
|
||||
|
||||
void unit_add_div(struct unit *unit, int type, const char *txt, float div)
|
||||
{
|
||||
struct fraction *f;
|
||||
|
||||
if (!unit)
|
||||
BUG();
|
||||
|
||||
f = xcalloc(1, sizeof(*f));
|
||||
|
||||
init_list_head(&f->f_list);
|
||||
|
||||
f->f_divisor = div;
|
||||
f->f_name = strdup(txt);
|
||||
|
||||
list_add_tail(&f->f_list, &unit->u_div[type]);
|
||||
}
|
||||
|
||||
struct unit *unit_add(const char *name)
|
||||
{
|
||||
struct unit *unit;
|
||||
int i;
|
||||
|
||||
if (!(unit = unit_lookup(name))) {
|
||||
unit = xcalloc(1, sizeof(*unit));
|
||||
unit->u_name = strdup(name);
|
||||
|
||||
for (i = 0; i < __UNIT_MAX; i++)
|
||||
init_list_head(&unit->u_div[i]);
|
||||
|
||||
list_add_tail(&unit->u_list, &units);
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
static void unit_free(struct unit *u)
|
||||
{
|
||||
struct fraction *f, *n;
|
||||
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(f, n, &u->u_div[UNIT_DEFAULT], f_list)
|
||||
fraction_free(f);
|
||||
|
||||
list_for_each_entry_safe(f, n, &u->u_div[UNIT_SI], f_list)
|
||||
fraction_free(f);
|
||||
|
||||
xfree(u->u_name);
|
||||
xfree(u);
|
||||
}
|
||||
|
||||
char *unit_bytes2str(uint64_t bytes, char *buf, size_t len)
|
||||
{
|
||||
char *ustr;
|
||||
int prec;
|
||||
double v;
|
||||
|
||||
if (byte_unit) {
|
||||
v = unit_value2str(bytes, byte_unit, &ustr, &prec);
|
||||
snprintf(buf, len, "%'.*f%3s", prec, v, ustr);
|
||||
} else
|
||||
snprintf(buf, len, "%llu", (unsigned long long) bytes);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *unit_bit2str(uint64_t bits, char *buf, size_t len)
|
||||
{
|
||||
char *ustr;
|
||||
int prec;
|
||||
double v;
|
||||
|
||||
if (bit_unit) {
|
||||
v = unit_value2str(bits, bit_unit, &ustr, &prec);
|
||||
snprintf(buf, len, "%'.*f%3s", prec, v, ustr);
|
||||
} else
|
||||
snprintf(buf, len, "%llu", (unsigned long long) bits);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void __exit unit_exit(void)
|
||||
{
|
||||
struct unit *u, *n;
|
||||
|
||||
list_for_each_entry_safe(u, n, &units, u_list)
|
||||
unit_free(u);
|
||||
}
|
421
src/utils.c
Normal file
421
src/utils.c
Normal file
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* utils.c General purpose utilities
|
||||
*
|
||||
* 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/utils.h>
|
||||
|
||||
void *xcalloc(size_t n, size_t s)
|
||||
{
|
||||
void *d = calloc(n, s);
|
||||
|
||||
if (NULL == d) {
|
||||
fprintf(stderr, "xalloc: Out of memory\n");
|
||||
exit(ENOMEM);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void *xrealloc(void *p, size_t s)
|
||||
{
|
||||
void *d = realloc(p, s);
|
||||
|
||||
if (NULL == d) {
|
||||
fprintf(stderr, "xrealloc: Out of memory!\n");
|
||||
exit(ENOMEM);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void xfree(void *d)
|
||||
{
|
||||
if (d)
|
||||
free(d);
|
||||
}
|
||||
|
||||
float timestamp_to_float(timestamp_t *src)
|
||||
{
|
||||
return (float) src->tv_sec + ((float) src->tv_usec / 1000000.0f);
|
||||
}
|
||||
|
||||
int64_t timestamp_to_int(timestamp_t *src)
|
||||
{
|
||||
return (src->tv_sec * 1000000ULL) + src->tv_usec;
|
||||
}
|
||||
|
||||
void float_to_timestamp(timestamp_t *dst, float src)
|
||||
{
|
||||
dst->tv_sec = (time_t) src;
|
||||
dst->tv_usec = (src - ((float) ((time_t) src))) * 1000000.0f;
|
||||
}
|
||||
|
||||
void timestamp_add(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
|
||||
{
|
||||
dst->tv_sec = src1->tv_sec + src2->tv_sec;
|
||||
dst->tv_usec = src1->tv_usec + src2->tv_usec;
|
||||
|
||||
if (dst->tv_usec >= 1000000) {
|
||||
dst->tv_sec++;
|
||||
dst->tv_usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void timestamp_sub(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2)
|
||||
{
|
||||
dst->tv_sec = src1->tv_sec - src2->tv_sec;
|
||||
dst->tv_usec = src1->tv_usec - src2->tv_usec;
|
||||
if (dst->tv_usec < 0) {
|
||||
dst->tv_sec--;
|
||||
dst->tv_usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
int timestamp_le(timestamp_t *a, timestamp_t *b)
|
||||
{
|
||||
if (a->tv_sec > b->tv_sec)
|
||||
return 0;
|
||||
|
||||
if (a->tv_sec < b->tv_sec || a->tv_usec <= b->tv_usec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timestamp_is_negative(timestamp_t *ts)
|
||||
{
|
||||
return (ts->tv_sec < 0 || ts->tv_usec < 0);
|
||||
}
|
||||
|
||||
void update_timestamp(timestamp_t *dst)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
dst->tv_sec = tv.tv_sec;
|
||||
dst->tv_usec = tv.tv_usec;
|
||||
}
|
||||
|
||||
void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2)
|
||||
{
|
||||
ts1->tv_sec = ts2->tv_sec;
|
||||
ts2->tv_usec = ts2->tv_usec;
|
||||
}
|
||||
|
||||
float timestamp_diff(timestamp_t *t1, timestamp_t *t2)
|
||||
{
|
||||
float diff;
|
||||
|
||||
diff = t2->tv_sec - t1->tv_sec;
|
||||
diff += (((float) t2->tv_usec - (float) t1->tv_usec) / 1000000.0f);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
float diff_now(timestamp_t *t1)
|
||||
{
|
||||
timestamp_t now;
|
||||
update_ts(&now);
|
||||
return time_diff(t1, &now);
|
||||
}
|
||||
|
||||
const char *xinet_ntop(struct sockaddr *src, char *dst, socklen_t cnt)
|
||||
{
|
||||
void *s;
|
||||
int family;
|
||||
|
||||
if (src->sa_family == AF_INET6) {
|
||||
s = &((struct sockaddr_in6 *) src)->sin6_addr;
|
||||
family = AF_INET6;
|
||||
} else if (src->sa_family == AF_INET) {
|
||||
s = &((struct sockaddr_in *) src)->sin_addr;
|
||||
family = AF_INET;
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
return inet_ntop(family, s, dst, cnt);
|
||||
}
|
||||
|
||||
uint64_t parse_size(const char *str)
|
||||
{
|
||||
char *p;
|
||||
uint64_t l = strtol(str, &p, 0);
|
||||
if (p == str)
|
||||
return -1;
|
||||
|
||||
if (*p) {
|
||||
if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
|
||||
l *= 1024;
|
||||
else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
|
||||
l *= 1024*1024*1024;
|
||||
else if (!strcasecmp(p, "gbit"))
|
||||
l *= 1024*1024*1024/8;
|
||||
else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
|
||||
l *= 1024*1024;
|
||||
else if (!strcasecmp(p, "mbit"))
|
||||
l *= 1024*1024/8;
|
||||
else if (!strcasecmp(p, "kbit"))
|
||||
l *= 1024/8;
|
||||
else if (strcasecmp(p, "b") != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(const char *s)
|
||||
{
|
||||
char *t = xcalloc(1, strlen(s) + 1);
|
||||
memcpy(t, s, strlen(s));
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *timestamp2str(timestamp_t *ts, char *buf, size_t len)
|
||||
{
|
||||
int i, split[5];
|
||||
char *units[] = {"d", "h", "m", "s", "usec"};
|
||||
time_t sec = ts->tv_sec;
|
||||
|
||||
#define _SPLIT(idx, unit) if ((split[idx] = sec / unit) > 0) sec %= unit
|
||||
_SPLIT(0, 86400); /* days */
|
||||
_SPLIT(1, 3600); /* hours */
|
||||
_SPLIT(2, 60); /* minutes */
|
||||
_SPLIT(3, 1); /* seconds */
|
||||
#undef _SPLIT
|
||||
split[4] = ts->tv_usec;
|
||||
|
||||
memset(buf, 0, len);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(split); i++) {
|
||||
if (split[i] > 0) {
|
||||
char t[64];
|
||||
snprintf(t, sizeof(t), "%s%d%s",
|
||||
strlen(buf) ? " " : "", split[i], units[i]);
|
||||
strncat(buf, t, len - strlen(buf) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int parse_date(const char *str, xdate_t *dst)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm *now_tm = localtime(&now);
|
||||
const char *next;
|
||||
char *p;
|
||||
struct tm backup;
|
||||
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
|
||||
if (strchr(str, '-')) {
|
||||
next = strptime(str, "%Y-%m-%d", &dst->d_tm);
|
||||
if (next == NULL ||
|
||||
(*next != '\0' && *next != ' '))
|
||||
goto invalid_date;
|
||||
} else {
|
||||
dst->d_tm.tm_mday = now_tm->tm_mday;
|
||||
dst->d_tm.tm_mon = now_tm->tm_mon;
|
||||
dst->d_tm.tm_year = now_tm->tm_year;
|
||||
dst->d_tm.tm_wday = now_tm->tm_wday;
|
||||
dst->d_tm.tm_yday = now_tm->tm_yday;
|
||||
dst->d_tm.tm_isdst = now_tm->tm_isdst;
|
||||
next = str;
|
||||
}
|
||||
|
||||
if (*next == '\0')
|
||||
return 0;
|
||||
|
||||
while (*next == ' ')
|
||||
next++;
|
||||
|
||||
if (*next == '.')
|
||||
goto read_us;
|
||||
|
||||
/* Make a backup, we can't rely on strptime to not screw
|
||||
* up what we've got so far. */
|
||||
memset(&backup, 0, sizeof(backup));
|
||||
memcpy(&backup, &dst->d_tm, sizeof(backup));
|
||||
|
||||
next = strptime(next, "%H:%M:%S", &dst->d_tm);
|
||||
if (next == NULL ||
|
||||
(*next != '\0' && *next != '.'))
|
||||
goto invalid_date;
|
||||
|
||||
dst->d_tm.tm_mday = backup.tm_mday;
|
||||
dst->d_tm.tm_mon = backup.tm_mon;
|
||||
dst->d_tm.tm_year = backup.tm_year;
|
||||
dst->d_tm.tm_wday = backup.tm_wday;
|
||||
dst->d_tm.tm_yday = backup.tm_yday;
|
||||
dst->d_tm.tm_isdst = backup.tm_isdst;
|
||||
|
||||
if (*next == '\0')
|
||||
return 0;
|
||||
read_us:
|
||||
if (*next == '.')
|
||||
next++;
|
||||
else
|
||||
BUG();
|
||||
|
||||
dst->d_usec = strtoul(next, &p, 10);
|
||||
|
||||
if (*p != '\0')
|
||||
goto invalid_date;
|
||||
|
||||
return 0;
|
||||
|
||||
invalid_date:
|
||||
fprintf(stderr, "Invalid date \"%s\"\n", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void print_token(FILE *fd, struct db_token *tok)
|
||||
{
|
||||
fprintf(fd, "%s", tok->t_name);
|
||||
|
||||
if (tok->t_flags & DB_T_ATTR)
|
||||
fprintf(fd, "<attr>");
|
||||
}
|
||||
|
||||
void db_print_filter(FILE *fd, struct db_filter *filter)
|
||||
{
|
||||
if (filter->f_node)
|
||||
print_token(fd, filter->f_node);
|
||||
|
||||
if (filter->f_group) {
|
||||
fprintf(fd, ".");
|
||||
print_token(fd, filter->f_group);
|
||||
}
|
||||
|
||||
if (filter->f_item) {
|
||||
fprintf(fd, ".");
|
||||
print_token(fd, filter->f_item);
|
||||
}
|
||||
|
||||
if (filter->f_attr) {
|
||||
fprintf(fd, ".");
|
||||
print_token(fd, filter->f_attr);
|
||||
}
|
||||
|
||||
if (filter->f_field)
|
||||
fprintf(fd, "@%s", filter->f_field);
|
||||
}
|
||||
|
||||
void *db_filter__scan_string(const char *);
|
||||
void db_filter__switch_to_buffer(void *);
|
||||
int db_filter_parse(void);
|
||||
|
||||
struct db_filter * parse_db_filter(const char *buf)
|
||||
{
|
||||
struct db_filter *f;
|
||||
struct db_token *tok, *t;
|
||||
|
||||
void *state = db_filter__scan_string(buf);
|
||||
db_filter__switch_to_buffer(state);
|
||||
|
||||
if (db_filter_parse()) {
|
||||
fprintf(stderr, "Failed to parse filter \"%s\"\n", buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tok = db_filter_out; /* generated by yacc */
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
|
||||
f = xcalloc(1, sizeof(*f));
|
||||
|
||||
f->f_node = tok;
|
||||
|
||||
if (!tok->t_next)
|
||||
goto out;
|
||||
tok = tok->t_next;
|
||||
|
||||
if (tok->t_flags & DB_T_ATTR) {
|
||||
fprintf(stderr, "Node may not contain an attribute field\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
f->f_group = tok;
|
||||
if (!tok->t_next)
|
||||
goto out;
|
||||
tok = tok->t_next;
|
||||
|
||||
if (tok->t_flags & DB_T_ATTR) {
|
||||
fprintf(stderr, "Group may not contain an attribute field\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
f->f_item = tok;
|
||||
|
||||
if (!tok->t_next)
|
||||
goto out;
|
||||
tok = tok->t_next;
|
||||
|
||||
if (tok->t_flags & DB_T_ATTR) {
|
||||
if (!tok->t_name)
|
||||
BUG();
|
||||
f->f_field = tok->t_name;
|
||||
goto out;
|
||||
} else
|
||||
f->f_attr = tok;
|
||||
|
||||
if (!tok->t_next)
|
||||
goto out;
|
||||
tok = tok->t_next;
|
||||
|
||||
if (tok->t_flags & DB_T_ATTR) {
|
||||
if (!tok->t_name)
|
||||
BUG();
|
||||
f->f_field = tok->t_name;
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected additional token after attribute\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
out:
|
||||
/* free unused tokens */
|
||||
for (tok = tok->t_next ; tok; tok = t) {
|
||||
t = tok->t_next;
|
||||
if (tok->t_name)
|
||||
free(tok->t_name);
|
||||
free(tok);
|
||||
}
|
||||
|
||||
return f;
|
||||
|
||||
errout:
|
||||
free(f);
|
||||
f = NULL;
|
||||
tok = db_filter_out;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user