pax_global_header00006660000000000000000000000064125546512210014515gustar00rootroot0000000000000052 comment=964f48465a36c48adfec84430081adabf841e2aa bmon-3.8/000077500000000000000000000000001255465122100123225ustar00rootroot00000000000000bmon-3.8/.gitignore000066400000000000000000000001741255465122100143140ustar00rootroot00000000000000*.o *.a *.so *.so.* *.swp .deps Makefile.in Makefile /autom4te.cache /cscope.* /build-aux/ /aclocal.m4 /configure /config.* bmon-3.8/.travis.yml000066400000000000000000000003641255465122100144360ustar00rootroot00000000000000language: c compiler: - gcc - clang before_install: - sudo apt-get install libconfuse-dev - sudo apt-get install libnl-3-dev libnl-route-3-dev - sudo apt-get install libncurses-dev # Change this to your needs script: ./.travis/run.sh bmon-3.8/.travis/000077500000000000000000000000001255465122100137105ustar00rootroot00000000000000bmon-3.8/.travis/run.sh000077500000000000000000000002731255465122100150550ustar00rootroot00000000000000#!/bin/bash FLAGS="-Werror" if [ $CC = "clang" ]; then FLAGS="$FLAGS -Wno-error=unused-command-line-argument" fi ./autogen.sh && ./configure && make CFLAGS="$FLAGS" && make distcheck bmon-3.8/ChangeLog000066400000000000000000000000001255465122100140620ustar00rootroot00000000000000bmon-3.8/LICENSE.BSD000066400000000000000000000022501255465122100137350ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bmon-3.8/LICENSE.MIT000066400000000000000000000017771255465122100137730ustar00rootroot00000000000000Permission 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. bmon-3.8/Makefile.am000066400000000000000000000002171255465122100143560ustar00rootroot00000000000000# -*- Makefile -*- ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src man include examples EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.md bmon-3.8/NEWS000066400000000000000000000015241255465122100130230ustar00rootroot00000000000000v3.8 - July 25, 2015 ---------------------- * Don't disable Netlink if TC stats are unavailable v3.7 - November 22, 2014 ---------------------- * Bugfixes * Documentation updates * Provide minimal interface information on BSD v3.6 - November 22, 2014 ---------------------- * Build fix for uclinux * Fix LICENSE links v3.5 - August 30, 2014 ---------------------- * Fixes for all defects identified by coverity * Fix accuracy issue on total rate calculation * Travis-CI support * Various other small bugfixes v3.4 - August 24, 2014 ---------------------- * Bugfixes * blank screen with config file * quick-help toggle with '?' in curses * Better bmon.conf example v3.3 - July 6, 2014 ------------------- * MacOS X port * Only initialize curses module if actually used * Assorted bug and spelling fixes * Various build fixes bmon-3.8/README.md000066400000000000000000000030721255465122100136030ustar00rootroot00000000000000# bmon - Bandwidth Monitor [![Build Status](https://travis-ci.org/tgraf/bmon.svg?branch=master)](https://travis-ci.org/tgraf/bmon) [![Coverity Status](https://scan.coverity.com/projects/2864/badge.svg)](https://scan.coverity.com/projects/2864) 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. ## Download * [Latest Release](https://github.com/tgraf/bmon/releases/latest) * [Older Releases](https://github.com/tgraf/bmon/releases) ## Debian/Ubuntu Installation ``` git clone https://github.com/tgraf/bmon.git cd bmon apt-get install build-essential make libconfuse-dev libnl-3-dev libnl-route-3-dev libncurses-dev ./autogen.sh ./configure make make install bmon ``` ------------- ## New in 3.8 * Don't disable Netlink if TC stats are unavailable ------------- ### Usage To run bmon in the default curses mode: > bmon There are many other options available and full help is provided via: > bmon --help ## Screenshots ![Screenshot 1](https://github.com/tgraf/bmon/raw/gh-pages/images/shot1.png) ![Screenshot 2](https://github.com/tgraf/bmon/raw/gh-pages/images/shot2.png) ## Copyright > *Copyright (c) 2001-2014 Thomas Graf * > *Copyright (c) 2013 Red Hat, Inc.* Please see the [LICENSE.BSD](https://github.com/tgraf/bmon/blob/master/LICENSE.BSD) and [LICENSE.MIT](https://github.com/tgraf/bmon/blob/master/LICENSE.MIT) files for additional details. bmon-3.8/autogen.sh000077500000000000000000000000641255465122100143230ustar00rootroot00000000000000#!/bin/bash autoreconf -fi; rm -Rf autom4te.cache; bmon-3.8/configure.ac000066400000000000000000000124321255465122100146120ustar00rootroot00000000000000# # configure.in Configure Script # # Copyright (c) 2001-2013 Thomas Graf # # 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.8, [], [], [http://www.infradead.org/~tgr/bmon/]) AC_CONFIG_HEADERS(include/bmon/defs.h) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AC_CANONICAL_SYSTEM 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])) case ${target_os} in linux*|uclinux*) PKG_CHECK_MODULES([LIBNL], [libnl-3.0], [], AC_MSG_ERROR([requires libnl3-dev])) PKG_CHECK_MODULES([LIBNL_ROUTE], [libnl-route-3.0], [], AC_MSG_ERROR([requires libnl3-route])) ;; esac 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 include/Makefile src/Makefile man/Makefile examples/Makefile ]) AC_OUTPUT bmon-3.8/examples/000077500000000000000000000000001255465122100141405ustar00rootroot00000000000000bmon-3.8/examples/Makefile.am000066400000000000000000000001761255465122100162000ustar00rootroot00000000000000# -*- Makefile -*- exampledir = $(datarootdir)/doc/@PACKAGE@/examples example_DATA = bmon.conf EXTRA_DIST = $(example_DATA) bmon-3.8/examples/bmon.conf000066400000000000000000000030011255465122100157340ustar00rootroot00000000000000/* * 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" } } variant bit { div = { 0.125, 125, 125000, 125000000, 125000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } } unit bit { variant default { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } variant si { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } variant bit { 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 } bmon-3.8/include/000077500000000000000000000000001255465122100137455ustar00rootroot00000000000000bmon-3.8/include/Makefile.am000066400000000000000000000004771255465122100160110ustar00rootroot00000000000000noinst_HEADERS = \ bmon/attr.h \ bmon/bmon.h \ bmon/compile-fixes.h \ bmon/conf.h \ bmon/config.h \ bmon/defs.h \ bmon/element_cfg.h \ bmon/element.h \ bmon/graph.h \ bmon/group.h \ bmon/history.h \ bmon/info.h \ bmon/input.h \ bmon/list.h \ bmon/module.h \ bmon/output.h \ bmon/unit.h \ bmon/utils.h bmon-3.8/include/bmon/000077500000000000000000000000001255465122100147005ustar00rootroot00000000000000bmon-3.8/include/bmon/.gitignore000066400000000000000000000000211255465122100166610ustar00rootroot00000000000000defs.h* stamp-h1 bmon-3.8/include/bmon/attr.h000066400000000000000000000072071255465122100160310ustar00rootroot00000000000000/* * bmon/attr.h Attributes * * Copyright (c) 2001-2013 Thomas Graf * 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 #include 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 bmon-3.8/include/bmon/bmon.h000066400000000000000000000043071255465122100160100ustar00rootroot00000000000000/* * bmon.h All-include Header * * Copyright (c) 2001-2013 Thomas Graf * 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 #include 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)) #define __unused__ __attribute__ ((unused)) #else #define __init #define __exit #define __unused__ #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 bmon-3.8/include/bmon/compile-fixes.h000066400000000000000000000025071255465122100176210ustar00rootroot00000000000000/* * compile_fixes.h * * Copyright (c) 2001-2013 Thomas Graf * 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 #ifndef HAVE_SUSECONDS_T typedef long suseconds_t; #endif #endif bmon-3.8/include/bmon/conf.h000066400000000000000000000047601255465122100160050ustar00rootroot00000000000000/* * conf.h Config Crap * * Copyright (c) 2001-2013 Thomas Graf * 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 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 bmon-3.8/include/bmon/config.h000066400000000000000000000065121255465122100163220ustar00rootroot00000000000000/* * config.h Global Config * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #if STDC_HEADERS != 1 #error "*** ERROR: ANSI C headers required for compilation ***" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SYS_BSD # include #else # include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_VFORK_H #include #endif #if !HAVE_WORKING_VFORK #define vfork fork #endif #if defined HAVE_STRING_H #include #elif defined HAVE_STRINGS_H #include #else #error "*** ERROR: No string header file found ***" #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INITTYPES_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #if defined HAVE_GETOPT_H #include #endif #include #include #include #include #if defined HAVE_SYS_UTSNAME_H #include #endif #if defined HAVE_NCURSESW_CURSES_H # include #elif defined HAVE_NCURSESW_H # include #elif defined HAVE_NCURSES_CURSES_H # include #elif defined HAVE_NCURSES_H # include #elif defined HAVE_CURSES_H # include #else # error "SysV or X/Open-compatible Curses header file required" #endif #include #if defined HAVE_NETINET6_IN6_H #include #endif #include #include #include #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 bmon-3.8/include/bmon/defs.h.in000066400000000000000000000140261255465122100164020ustar00rootroot00000000000000/* 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 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 header file. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the 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 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 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 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 is present */ #undef HAVE_NCURSESW_CURSES_H /* Define to 1 if is present */ #undef HAVE_NCURSESW_H /* Define to 1 if is present */ #undef HAVE_NCURSES_CURSES_H /* Define to 1 if is present */ #undef HAVE_NCURSES_H /* Define to 1 if you have the header file. */ #undef HAVE_NCURSES_NCURSES_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET6_IN6_H /* Define to 1 if you have the 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 header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the 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 header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the 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 header file. */ #undef HAVE_SYSCTL_IOCTL_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the 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 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 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 and . */ #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 does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define as `fork' if `vfork' does not work. */ #undef vfork bmon-3.8/include/bmon/element.h000066400000000000000000000073021255465122100165040ustar00rootroot00000000000000/* * bmon/element.h Elements * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #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 bmon-3.8/include/bmon/element_cfg.h000066400000000000000000000040201255465122100173150ustar00rootroot00000000000000/* * element_cfg.h Element Configuration * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #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 bmon-3.8/include/bmon/graph.h000066400000000000000000000040141255465122100161510ustar00rootroot00000000000000/* * bmon/graph.h Graph creation utility * * Copyright (c) 2001-2013 Thomas Graf * 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 #include 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 bmon-3.8/include/bmon/group.h000066400000000000000000000055671255465122100162220ustar00rootroot00000000000000/* * bmon/group.h Group Management * * Copyright (c) 2001-2013 Thomas Graf * 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 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 bmon-3.8/include/bmon/history.h000066400000000000000000000052651255465122100165620ustar00rootroot00000000000000/* * bmon/history.h History Management * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #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 bmon-3.8/include/bmon/info.h000066400000000000000000000026011255465122100160030ustar00rootroot00000000000000/* * bmon/info.h Info Attributes * * Copyright (c) 2001-2013 Thomas Graf * 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 #include struct element; struct info { char * i_name; char * i_value; struct list_head i_list; }; #endif bmon-3.8/include/bmon/input.h000066400000000000000000000032751255465122100162170ustar00rootroot00000000000000/* * input.h Input API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include 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 bmon-3.8/include/bmon/list.h000066400000000000000000000050511255465122100160250ustar00rootroot00000000000000/* * bmon/list.h Kernel List Implementation * * Copied and adapted from the kernel sources * */ #ifndef BMON_LIST_H_ #define BMON_LIST_H_ #ifdef __APPLE__ /* Apple systems define these macros in system headers, so we undef * them prior to inclusion of this file */ #undef LIST_HEAD #undef LIST_HEAD_INIT #undef INIT_LIST_HEAD #endif 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 bmon-3.8/include/bmon/module.h000066400000000000000000000046661255465122100163520ustar00rootroot00000000000000/* * module.h Module API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #define BMON_MODULE_ENABLED (1 << 0) /* Enabled */ #define BMON_MODULE_DEFAULT (1 << 1) /* Suitable as default */ #define BMON_MODULE_AUTO (1 << 2) /* Auto enable */ struct bmon_subsys; 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 *m_subsys; }; 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 int 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 bmon-3.8/include/bmon/output.h000066400000000000000000000027721255465122100164210ustar00rootroot00000000000000/* * output.h Output API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include 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 bmon-3.8/include/bmon/unit.h000066400000000000000000000040761255465122100160370ustar00rootroot00000000000000/* * bmon/unit.h Units * * Copyright (c) 2001-2013 Thomas Graf * 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 #define DYNAMIC_EXP (-1) enum { UNIT_DEFAULT, UNIT_SI, UNIT_BIT, __UNIT_MAX, }; #define UNIT_MAX (__UNIT_MAX - 1) #define UNIT_BYTE "byte" #define UNIT_NUMBER "number" struct fraction { float 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 double 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 bmon-3.8/include/bmon/utils.h000066400000000000000000000057261255465122100162230ustar00rootroot00000000000000/* * utils.h General purpose utilities * * Copyright (c) 2001-2013 Thomas Graf * 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 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 bmon-3.8/m4/000077500000000000000000000000001255465122100126425ustar00rootroot00000000000000bmon-3.8/m4/ax_with_curses.m4000066400000000000000000000607331255465122100161440ustar00rootroot00000000000000# =========================================================================== # 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 is present and should be used # HAVE_NCURSESW_H - if should be used # HAVE_NCURSES_H - if should be used # HAVE_NCURSESW_CURSES_H - if should be used # HAVE_NCURSES_CURSES_H - if 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 . 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 # #elif defined HAVE_NCURSESW_H # # include # #elif defined HAVE_NCURSES_CURSES_H # # include # #elif defined HAVE_NCURSES_H # # include # #elif defined HAVE_CURSES_H # # include # #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 # Copyright (c) 2009 Damian Pietras # Copyright (c) 2012 Reuben Thomas # Copyright (c) 2011 John Zaitseff # # 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 . # # 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 ]], [[ 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 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 ]], [[ 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 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 ]], [[ 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 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 ]], [[ 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 is present]) ]) AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ 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 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 ]], [[ 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 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 @%:@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 ]], [[ 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 ]], [[ 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 bmon-3.8/man/000077500000000000000000000000001255465122100130755ustar00rootroot00000000000000bmon-3.8/man/Makefile.am000066400000000000000000000000541255465122100151300ustar00rootroot00000000000000# -*- Makefile -*- dist_man8_MANS = bmon.8 bmon-3.8/man/bmon.8000066400000000000000000000130531255465122100141230ustar00rootroot00000000000000.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 (1KB = 1'000 bytes) 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 \-b\fR, \fB\-\-use\-bit\fR .RS 4 Show rates in bits per second instead of bytes per second. .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, ... .PP Examples: .PP .RS 4 lo,eth0,eth1 .br eth*,!eth0 .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 among others bmon-3.8/src/000077500000000000000000000000001255465122100131115ustar00rootroot00000000000000bmon-3.8/src/.gitignore000066400000000000000000000000111255465122100150710ustar00rootroot00000000000000*.o bmon bmon-3.8/src/Makefile.am000066400000000000000000000012051255465122100151430ustar00rootroot00000000000000# -*- Makefile -*- bin_PROGRAMS = bmon bmon_CFLAGS = \ -I${top_srcdir}/include \ -I${top_builddir}/include \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -D_GNU_SOURCE \ -Wall \ $(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 \ in_sysctl.c \ out_null.c \ out_format.c \ out_ascii.c \ out_curses.c bmon-3.8/src/attr.c000066400000000000000000000316261255465122100142370ustar00rootroot00000000000000/* * attr.c Attributes * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include #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); } bmon-3.8/src/bmon.c000066400000000000000000000206571255465122100142220ustar00rootroot00000000000000/* * src/bmon.c Bandwidth Monitor * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include 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 Output 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-interval=FLOAT Rate interval in seconds (float)\n" \ " -s, --sleep-interval=FLOAT Sleep time in seconds (float)\n" \ " -L, --lifetime=LIFETIME Lifetime of an element in seconds (float)\n" \ "\n" \ "Output:\n" \ " -U, --use-si Use SI units\n" \ " -b, --use-bit Display in bits instead of bytes\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-2015 by Thomas Graf \n"); printf("Copyright (C) 2013 Red Hat, Inc.\n"); printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \ "software, and you\nare welcome to redistribute it under " \ "certain conditions. See the source\ncode for details.\n"); } static void parse_args_pre(int argc, char *argv[]) { DBG("Parsing arguments pre state"); for (;;) { char *gostr = "+:hvVf:"; struct option long_opts[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"configfile", 1, 0, 'f'}, {0, 0, 0, 0}, }; int c = getopt_long(argc, argv, gostr, long_opts, NULL); if (c == -1) break; switch (c) { case 'f': set_configfile(optarg); break; case 'h': print_version(); printf("\n%s", usage_text); exit(1); case 'V': case 'v': print_version(); exit(0); } } } static int parse_args_post(int argc, char *argv[]) { DBG("Parsing arguments post state"); optind = 1; for (;;) { char *gostr = "i:o:p:r:R:s:aUb" \ "L:hvVf:"; struct option long_opts[] = { {"input", 1, 0, 'i'}, {"output", 1, 0, 'o'}, {"policy", 1, 0, 'p'}, {"read-interval", 1, 0, 'r'}, {"rate-interval", 1, 0, 'R'}, {"sleep-interval", 1, 0, 's'}, {"show-all", 0, 0, 'a'}, {"use-si", 0, 0, 'U'}, {"use-bit", 0, 0, 'b'}, {"lifetime", 1, 0, 'L'}, {0, 0, 0, 0}, }; int c = getopt_long(argc, argv, gostr, long_opts, NULL); if (c == -1) break; switch (c) { case 'i': if (input_set(optarg)) return 1; break; case 'o': if (output_set(optarg)) return 1; break; case 'p': cfg_setstr(cfg, "policy", optarg); break; case 'r': cfg_setfloat(cfg, "read_interval", strtod(optarg, NULL)); break; case 'R': cfg_setfloat(cfg, "rate_interval", strtod(optarg, NULL)); break; case 's': cfg_setint(cfg, "sleep_time", strtoul(optarg, NULL, 0)); break; case 'a': cfg_setbool(cfg, "show_all", cfg_true); break; case 'U': cfg_setbool(cfg, "use_si", cfg_true); break; case 'b': cfg_setbool(cfg, "use_bit", cfg_true); break; case 'L': cfg_setint(cfg, "lifetime", strtoul(optarg, NULL, 0)); break; case 'f': /* Already handled in pre getopt loop */ break; default: quit("Aborting...\n"); break; } } return 0; } #if 0 static void calc_variance(timestamp_t *c, timestamp_t *ri) { float v = (ts_to_float(c) / ts_to_float(ri)) * 100.0f; rtiming.rt_variance.v_error = v; rtiming.rt_variance.v_total += v; if (v > rtiming.rt_variance.v_max) rtiming.rt_variance.v_max = v; if (v < rtiming.rt_variance.v_min) rtiming.rt_variance.v_min = v; } #endif int main(int argc, char *argv[]) { unsigned long sleep_time; double read_interval; start_time = time(0); memset(&rtiming, 0, sizeof(rtiming)); rtiming.rt_variance.v_min = FLT_MAX; /* * Early initialization before reading config */ conf_init_pre(); parse_args_pre(argc, argv); /* * Reading the configuration file */ configfile_read(); /* * Late initialization after reading config */ if (parse_args_post(argc, argv)) return 1; conf_init_post(); module_init(); read_interval = cfg_read_interval; sleep_time = cfg_getint(cfg, "sleep_time"); if (((double) sleep_time / 1000000.0f) > read_interval) sleep_time = (unsigned long) (read_interval * 1000000.0f); DBG("Entering mainloop..."); do { /* * E := Elapsed time * NR := Next Read * LR := Last Read * RI := Read Interval * ST := Sleep Time * C := Correction */ timestamp_t e, ri, tmp; unsigned long st; float_to_timestamp(&ri, read_interval); /* * NR := NOW */ update_timestamp(&rtiming.rt_next_read); for (;;) { output_pre(); /* * E := NOW */ update_timestamp(&e); /* * IF NR <= E THEN */ if (timestamp_le(&rtiming.rt_next_read, &e)) { timestamp_t c; /* * C := (NR - E) */ timestamp_sub(&c, &rtiming.rt_next_read, &e); //calc_variance(&c, &ri); /* * LR := E */ copy_timestamp(&rtiming.rt_last_read, &e); /* * NR := E + RI + C */ timestamp_add(&rtiming.rt_next_read, &e, &ri); timestamp_add(&rtiming.rt_next_read, &rtiming.rt_next_read, &c); reset_update_flags(); input_read(); free_unused_elements(); output_draw(); output_post(); } if (do_quit) exit(0); /* * ST := Configured ST */ st = sleep_time; /* * IF (NR - E) < ST THEN */ timestamp_sub(&tmp, &rtiming.rt_next_read, &e); if (tmp.tv_sec < 0) continue; if (tmp.tv_sec == 0 && tmp.tv_usec < st) { if (tmp.tv_usec < 0) continue; /* * ST := (NR - E) */ st = tmp.tv_usec; } /* * SLEEP(ST) */ usleep(st); } } while (0); return 0; /* buddha says i'll never be reached */ } static void __init bmon_init(void) { atexit(&sig_exit); //signal(SIGINT, &sig_int); } bmon-3.8/src/conf.c000066400000000000000000000332651255465122100142130ustar00rootroot00000000000000/* * conf.c Config Crap * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include 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_BOOL("use_bit", 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), CFG_END() }; 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 if (!strcasecmp(vtitle, "bit")) add_div(u, UNIT_BIT, variant); else quit("Unknown unit variant \'%s\'\n", vtitle); } } } static void configfile_read_attrs(void) { int i, nattrs, t = 0; 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\" }" \ " }" \ " variant bit {" \ " div = { 0.125, 125, 125000, 125000000, 125000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " }" \ "unit bit {" \ " variant default {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " variant si {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " variant bit {" \ " 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 "/bmon.conf", 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); } bmon-3.8/src/element.c000066400000000000000000000260441255465122100147140ustar00rootroot00000000000000/* * src/element.c Elements * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include 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); 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); } bmon-3.8/src/element_cfg.c000066400000000000000000000046411255465122100155320ustar00rootroot00000000000000/* * element_cfg.c Element Configuration * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include 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); } bmon-3.8/src/graph.c000066400000000000000000000117321255465122100143620ustar00rootroot00000000000000/* * graph.c Graph creation utility * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include 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 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; double 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] /= 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 bmon-3.8/src/group.c000066400000000000000000000145141255465122100144160ustar00rootroot00000000000000/* * group.c Group Management * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include 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); } bmon-3.8/src/history.c000066400000000000000000000163331255465122100147640ustar00rootroot00000000000000/* * history.c History Management * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include 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); } bmon-3.8/src/in_dummy.c000066400000000000000000000151121255465122100150760ustar00rootroot00000000000000/* * in_dummy.c Dummy Input Method * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #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 = "Packets", } }; /* 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 \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 *type, const char *value) { 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); } bmon-3.8/src/in_netlink.c000066400000000000000000000501321255465122100154100ustar00rootroot00000000000000/* * in_netlink.c Netlink input * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #ifndef SYS_BSD static int c_notc = 0; static struct element_group *grp; static struct bmon_module netlink_ops; #include #include #include #include #include #include #include #include #include #include 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 = "Packets", .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 && qdisc_cache) 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 (qdisc_cache && (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 void netlink_use_bit(struct attr_map *map, const int size) { if(cfg_getbool(cfg, "use_bit")) { for(int i = 0; i < size; ++i) { if(!strcmp(map[i].description, "Bytes")) { map[i].description = "Bits"; } } } } static int netlink_do_init(void) { int err; 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, "Warning: Unable to allocate qdisc cache: %s\n", nl_geterror(err)); fprintf(stderr, "Disabling QoS statistics.\n"); qdisc_cache = NULL; } netlink_use_bit(link_attrs, ARRAY_SIZE(link_attrs)); netlink_use_bit(tc_attrs, ARRAY_SIZE(tc_attrs)); 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 \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); } #endif bmon-3.8/src/in_null.c000066400000000000000000000035771255465122100147310ustar00rootroot00000000000000/* * in_null.c Null Input Method * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include 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 \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); } bmon-3.8/src/in_proc.c000066400000000000000000000126731255465122100147170ustar00rootroot00000000000000/* * in_proc.c /proc/net/dev Input (Linux) * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include 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 = "Packets", }, { .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, *unused __unused__; int w; if (!(fd = fopen(c_path, "r"))) quit("Unable to open file %s: %s\n", c_path, strerror(errno)); /* Ignore header */ unused = fgets(buf, sizeof(buf), fd); unused = 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))) goto skip; 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); } skip: 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 \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); } bmon-3.8/src/in_sysctl.c000066400000000000000000000155261255465122100152750ustar00rootroot00000000000000/* * in_sysctl.c sysctl (BSD) * * $Id: in_sysctl.c 20 2004-10-30 22:46:16Z tgr $ * * Copyright (c) 2001-2004 Thomas Graf * Copyright (c) 2014 Žilvinas Valinskas * * 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 #include #include #include #include #include #if defined SYS_BSD #include #include #include #include #include #include static int c_debug = 0; static struct element_group *grp; enum { SYSCTL_RX_BYTES = 0x100, SYSCTL_TX_BYTES, SYSCTL_RX_PACKETS, SYSCTL_TX_PACKETS, SYSCTL_RX_ERRORS, SYSCTL_TX_ERRORS, SYSCTL_RX_DROPS, SYSCTL_RX_MCAST, SYSCTL_TX_MCAST, SYSCTL_TX_COLLS, }; static struct attr_map link_attrs[] = { { .name = "bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .rxid = SYSCTL_RX_BYTES, .txid = SYSCTL_TX_BYTES, .description = "Bytes", }, { .name = "packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_PACKETS, .txid = SYSCTL_TX_PACKETS, .description = "Packets", }, { .name = "errors", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_ERRORS, .txid = SYSCTL_TX_ERRORS, .description = "Errors", }, { .name = "drop", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_DROPS, .description = "Dropped", }, { .name = "coll", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .txid = SYSCTL_TX_COLLS, .description = "Collisions", }, { .name = "mcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_MCAST, .txid = SYSCTL_TX_MCAST, .description = "Multicast", } }; uint64_t sysctl_get_stats(const struct if_msghdr *ifm, int what) { switch(what) { case SYSCTL_RX_BYTES: return ifm->ifm_data.ifi_ibytes; case SYSCTL_TX_BYTES: return ifm->ifm_data.ifi_obytes; case SYSCTL_RX_PACKETS: return ifm->ifm_data.ifi_ipackets; case SYSCTL_TX_PACKETS: return ifm->ifm_data.ifi_opackets; case SYSCTL_RX_ERRORS: return ifm->ifm_data.ifi_ierrors; case SYSCTL_TX_ERRORS: return ifm->ifm_data.ifi_oerrors; case SYSCTL_RX_DROPS: return ifm->ifm_data.ifi_iqdrops; case SYSCTL_RX_MCAST: return ifm->ifm_data.ifi_imcasts; case SYSCTL_TX_MCAST: return ifm->ifm_data.ifi_omcasts; case SYSCTL_TX_COLLS: return ifm->ifm_data.ifi_collisions; default: return 0; }; } static void sysctl_read(void) { int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; size_t n; char *buf, *next, *lim; if (sysctl(mib, 6, NULL, &n, NULL, 0) < 0) quit("sysctl() failed"); if (c_debug) fprintf(stderr, "sysctl 1-pass n=%zd\n", n); buf = xcalloc(1, n); if (sysctl(mib, 6, buf, &n, NULL, 0) < 0) quit("sysctl() failed"); if (c_debug) fprintf(stderr, "sysctl 2-pass n=%zd\n", n); lim = (buf + n); for (next = buf; next < lim; ) { struct element *e, *e_parent = NULL; struct if_msghdr *ifm, *nextifm; struct sockaddr_dl *sdl; char info_buf[64]; ifm = (struct if_msghdr *) next; if (ifm->ifm_type != RTM_IFINFO) break; next += ifm->ifm_msglen; while (next < lim) { nextifm = (struct if_msghdr *) next; if (nextifm->ifm_type != RTM_NEWADDR) break; next += nextifm->ifm_msglen; } sdl = (struct sockaddr_dl *) (ifm + 1); if (!cfg_show_all && !(ifm->ifm_flags & IFF_UP)) continue; if (sdl->sdl_family != AF_LINK) continue; if (c_debug) fprintf(stderr, "Processing %s\n", sdl->sdl_data); sdl->sdl_data[sdl->sdl_nlen] = '\0'; e = element_lookup(grp, sdl->sdl_data, sdl->sdl_index, e_parent, ELEMENT_CREAT); if (!e) continue; 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(); e->e_flags &= ~ELEMENT_FLAG_CREATED; } int i; for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; uint64_t rx = 0, tx = 0; int flags = 0; if (m->rxid) { rx = sysctl_get_stats(ifm, m->rxid); flags |= UPDATE_FLAG_RX; } if (m->txid) { tx = sysctl_get_stats(ifm, m->txid); flags |= UPDATE_FLAG_TX; } attr_update(e, m->attrid, rx, tx, flags); } snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_mtu); element_update_info(e, "MTU", info_buf); snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_metric); element_update_info(e, "Metric", info_buf); snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_recvquota); element_update_info(e, "RX-Quota", info_buf); snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_xmitquota); element_update_info(e, "TX-Quota", info_buf); element_notify_update(e, NULL); element_lifesign(e, 1); } xfree(buf); } static void print_help(void) { printf( "sysctl - sysctl statistic collector for BSD and Darwin\n" \ "\n" \ " BSD and Darwin statistic collector using sysctl()\n" \ " Author: Thomas Graf \n" \ "\n"); } static void sysctl_set_opts(const char* type, const char* value) { if (!strcasecmp(type, "debug")) c_debug = 1; else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static int sysctl_probe(void) { size_t n; int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; if (sysctl(mib, 6, NULL, &n, NULL, 0) < 0) return 0; return 1; } static int sysctl_do_init(void) { if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs))) BUG(); grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE); if (!grp) BUG(); return 0; } static struct bmon_module kstat_ops = { .m_name = "sysctl", .m_do = sysctl_read, .m_parse_opt = sysctl_set_opts, .m_probe = sysctl_probe, .m_init = sysctl_do_init, }; static void __init sysctl_init(void) { input_register(&kstat_ops); } #endif bmon-3.8/src/input.c000066400000000000000000000045671255465122100144300ustar00rootroot00000000000000/* * input.c Input API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include 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; #ifdef SYS_LINUX if (!input_set("netlink")) return; if (!input_set("proc")) return; #endif #ifdef SYS_BSD if (!input_set("sysctl")) return; #endif /* 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); } bmon-3.8/src/module.c000066400000000000000000000115511255465122100145450ustar00rootroot00000000000000/* * module.c Module API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include 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 && cfg) { 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; m->m_flags |= BMON_MODULE_ENABLED; m->m_subsys->s_nmod++; return 0; } int module_register(struct bmon_subsys *ss, struct bmon_module *m) { if (m->m_subsys) return -EBUSY; list_add_tail(&m->m_list, &ss->s_mod_list); m->m_subsys = ss; return 0; } static void __auto_load(struct bmon_module *m) { if ((m->m_flags & BMON_MODULE_AUTO) && !(m->m_flags & BMON_MODULE_ENABLED)) { if (module_configure(m, NULL) == 0) DBG("Auto-enabled module %s", m->m_name); } } int module_set(struct bmon_subsys *ss, const char *name) { struct bmon_module *mod; LIST_HEAD(tmp_list); module_conf_t *m; 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("Enabled module %s", mod->m_name); } module_foreach(ss, __auto_load); if (!ss->s_nmod) quit("No working %s module found\n", ss->s_name); DBG("Configured modules"); 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); } bmon-3.8/src/out_ascii.c000066400000000000000000000174711255465122100152460ustar00rootroot00000000000000/* * out_ascii.c ASCII Output * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include #include 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 = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0; 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 \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); } bmon-3.8/src/out_curses.c000066400000000000000000000646371255465122100154700ustar00rootroot00000000000000/* * out_curses.c Curses Output * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include #include #include enum { GRAPH_DISPLAY_SIDE_BY_SIDE = 1, GRAPH_DISPLAY_STANDARD = 2, }; enum { KEY_TOGGLE_LIST = 'l', KEY_TOGGLE_GRAPH = 'g', KEY_TOGGLE_DETAILS = 'd', KEY_TOGGLE_INFO = 'i', KEY_COLLECT_HISTORY = 'h', }; #define DETAILS_COLS 40 #define LIST_COL_1 31 #define LIST_COL_2 55 /* Set to element_current() before drawing */ static struct element *current_element; static struct attr *current_attr; /* Length of list to draw, updated in draw_content() */ static int list_length; static int list_req; /* Number of graphs to draw (may be < c_ngraph) */ static int ngraph; /* * Offset in number of lines within the the element list of the currently * selected element. Updated while summing up required lines. */ static unsigned int selection_offset; /* * Offset in number of lines of the first element to be drawn. Updated * in draw_content() */ static int offset; /* * Offset to the first graph to draw in number of attributes with graphs. */ static unsigned int graph_offset; static int graph_display = GRAPH_DISPLAY_STANDARD; /* * Number of detail columns */ static int detail_cols; static int info_cols; static int initialized; static int print_help; static int quit_mode; static int help_page; /* Current row */ static int row; /* Number of rows */ static int rows; /* Number of columns */ static int cols; static int c_show_graph = 1; static int c_ngraph = 1; static int c_use_colors = 1; static int c_show_details = 0; static int c_show_list = 1; static int c_show_info = 0; static int c_list_min = 6; static struct graph_cfg c_graph_cfg = { .gc_width = 60, .gc_height = 6, .gc_foreground = '|', .gc_background = '.', .gc_noise = ':', .gc_unknown = '?', }; #define NEXT_ROW() \ do { \ row++; \ if (row >= rows - 1) \ return; \ move(row, 0); \ } while(0) static void apply_layout(int layout) { if (c_use_colors) attrset(COLOR_PAIR(layout) | cfg_layout[layout].l_attr); else attrset(cfg_layout[layout].l_attr); } char *float2str(double value, int width, int prec, char *buf, size_t len) { snprintf(buf, len, "%'*.*f", width, value == 0.0f ? 0 : prec, value); return buf; } static void put_line(const char *fmt, ...) { va_list args; char buf[2048]; int x, y __unused__; memset(buf, 0, sizeof(buf)); getyx(stdscr, y, x); va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (strlen(buf) > cols-x) buf[cols - x] = '\0'; else memset(&buf[strlen(buf)], ' ', cols - strlen(buf)-x); addstr(buf); } static void center_text(const char *fmt, ...) { va_list args; char *str; unsigned int col; va_start(args, fmt); if (vasprintf(&str, fmt, args) < 0) { fprintf(stderr, "vasprintf: Out of memory\n"); exit(ENOMEM); } va_end(args); col = (cols / 2) - (strlen(str) / 2); if (col > cols - 1) col = cols - 1; move(row, col); addstr(str); move(row, 0); free(str); } static int curses_init(void) { if (!initscr()) { fprintf(stderr, "Unable to initialize curses screen\n"); return -EOPNOTSUPP; } initialized = 1; if (!has_colors()) c_use_colors = 0; if (c_use_colors) { int i; start_color(); #if defined HAVE_USE_DEFAULT_COLORS use_default_colors(); #endif for (i = 1; i < LAYOUT_MAX+1; i++) init_pair(i, cfg_layout[i].l_fg, cfg_layout[i].l_bg); } keypad(stdscr, TRUE); nonl(); cbreak(); noecho(); nodelay(stdscr, TRUE); /* getch etc. must be non-blocking */ clear(); curs_set(0); return 0; } static void curses_shutdown(void) { if (initialized) endwin(); } struct detail_arg { int nattr; }; static void draw_attr_detail(struct element *e, struct attr *a, void *arg) { char *rx_u, *tx_u, buf1[32], buf2[32]; int rxprec, txprec, ncol; struct detail_arg *da = arg; 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); if (da->nattr >= detail_cols) { NEXT_ROW(); da->nattr = 0; } ncol = (da->nattr * DETAILS_COLS) - 1; move(row, ncol); if (ncol > 0) addch(ACS_VLINE); put_line(" %-14.14s %8s%-3s %8s%-3s\n", a->a_def->ad_description, (a->a_flags & ATTR_RX_ENABLED) ? float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u, (a->a_flags & ATTR_TX_ENABLED) ? float2str(tx, 8, txprec, buf2, sizeof(buf2)) : "-", tx_u); da->nattr++; } static void draw_details(void) { int i; struct detail_arg arg = { .nattr = 0, }; if (!current_element->e_nattrs) return; for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS) - 1, ACS_TTEE); NEXT_ROW(); put_line(""); for (i = 0; i < detail_cols; i++) { if (i > 0) mvaddch(row, (i * DETAILS_COLS) - 1, ACS_VLINE); move(row, (i * DETAILS_COLS) + 22); put_line("RX TX"); } NEXT_ROW(); element_foreach_attr(current_element, draw_attr_detail, &arg); /* * If the last row was incomplete, not all vlines have been drawn. * draw them here */ for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE); } static void print_message(const char *text) { int i, y = (rows/2) - 2; int len = strlen(text); int x = (cols/2) - (len / 2); attrset(A_STANDOUT); mvaddch(y - 2, x - 1, ACS_ULCORNER); mvaddch(y + 2, x - 1, ACS_LLCORNER); mvaddch(y - 2, x + len, ACS_URCORNER); mvaddch(y + 2, x + len, ACS_LRCORNER); for (i = 0; i < 3; i++) { mvaddch(y - 1 + i, x + len, ACS_VLINE); mvaddch(y - 1 + i, x - 1 ,ACS_VLINE); } for (i = 0; i < len; i++) { mvaddch(y - 2, x + i, ACS_HLINE); mvaddch(y - 1, x + i, ' '); mvaddch(y + 1, x + i, ' '); mvaddch(y + 2, x + i, ACS_HLINE); } mvaddstr(y, x, text); attroff(A_STANDOUT); row = y + 2; } static void draw_help(void) { #define HW 46 #define HH 19 int i, y = (rows/2) - (HH/2); int x = (cols/2) - (HW/2); char pad[HW+1]; memset(pad, ' ', sizeof(pad)); pad[sizeof(pad) - 1] = '\0'; attron(A_STANDOUT); for (i = 0; i < HH; i++) mvaddnstr(y + i, x, pad, -1); mvaddch(y - 1, x - 1, ACS_ULCORNER); mvaddch(y + HH, x - 1, ACS_LLCORNER); mvaddch(y - 1, x + HW, ACS_URCORNER); mvaddch(y + HH, x + HW, ACS_LRCORNER); for (i = 0; i < HH; i++) { mvaddch(y + i, x - 1, ACS_VLINE); mvaddch(y + i, x + HW, ACS_VLINE); } for (i = 0; i < HW; i++) { mvaddch(y - 1, x + i, ACS_HLINE); mvaddch(y + HH, x + i, ACS_HLINE); } attron(A_BOLD); mvaddnstr(y- 1, x+15, "QUICK REFERENCE", -1); attron(A_UNDERLINE); mvaddnstr(y+ 0, x+1, "Navigation", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 1, x+3, "Up, Down Previous/Next element", -1); mvaddnstr(y+ 2, x+3, "PgUp, PgDown Scroll up/down entire page", -1); mvaddnstr(y+ 3, x+3, "Left, Right Previous/Next attribute", -1); mvaddnstr(y+ 4, x+3, "[, ] Previous/Next group", -1); mvaddnstr(y+ 5, x+3, "? Toggle quick reference", -1); mvaddnstr(y+ 6, x+3, "q Quit bmon", -1); attron(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 8, x+1, "Display Settings", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 9, x+3, "d Toggle detailed statistics", -1); mvaddnstr(y+10, x+3, "l Toggle element list", -1); mvaddnstr(y+11, x+3, "i Toggle additional info", -1); attron(A_BOLD | A_UNDERLINE); mvaddnstr(y+13, x+1, "Graph Settings", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+14, x+3, "g Toggle graphical statistics", -1); mvaddnstr(y+15, x+3, "H Start recording history data", -1); mvaddnstr(y+16, x+3, "TAB Switch time unit of graph", -1); mvaddnstr(y+17, x+3, "<, > Change number of graphs", -1); attroff(A_STANDOUT); row = y + HH; } static int lines_required_for_header(void) { return 1; } static void draw_header(void) { apply_layout(LAYOUT_STATUSBAR); if (current_element) put_line(" %s %c%s%c", current_element->e_name, current_element->e_description ? '(' : ' ', current_element->e_description ? : "", current_element->e_description ? ')' : ' '); else put_line(""); move(row, COLS - strlen(PACKAGE_STRING) - 1); put_line("%s", PACKAGE_STRING); move(row, 0); } static int lines_required_for_statusbar(void) { return 1; } static void draw_statusbar(void) { static const char *help_text = "Press ? for help"; char s[27]; time_t t = time(0); apply_layout(LAYOUT_STATUSBAR); asctime_r(localtime(&t), s); s[strlen(s) - 1] = '\0'; row = rows-1; move(row, 0); put_line(" %s", s); move(row, COLS - strlen(help_text) - 1); put_line("%s", help_text); move(row, 0); } static void count_attr_graph(struct element *g, struct attr *a, void *arg) { if (a == current_attr) graph_offset = ngraph; ngraph++; } static int lines_required_for_graph(void) { int lines = 0; ngraph = 0; if (c_show_graph && current_element) { graph_display = GRAPH_DISPLAY_STANDARD; element_foreach_attr(current_element, count_attr_graph, NULL); if (ngraph > c_ngraph) ngraph = c_ngraph; /* check if we have room to draw graphs on the same level */ if (cols > (2 * (c_graph_cfg.gc_width + 10))) graph_display = GRAPH_DISPLAY_SIDE_BY_SIDE; /* +2 = header + time axis */ lines = ngraph * (graph_display * (c_graph_cfg.gc_height + 2)); } return lines + 1; } static int lines_required_for_details(void) { int lines = 1; if (c_show_details && current_element) { lines++; /* header */ detail_cols = cols / DETAILS_COLS; if (!detail_cols) detail_cols = 1; lines += (current_element->e_nattrs / detail_cols); if (current_element->e_nattrs % detail_cols) lines++; } return lines; } static void count_element_lines(struct element_group *g, struct element *e, void *arg) { int *lines = arg; if (e == current_element) selection_offset = *lines; (*lines)++; } static void count_group_lines(struct element_group *g, void *arg) { int *lines = arg; /* group title */ (*lines)++; group_foreach_element(g, &count_element_lines, arg); } static int lines_required_for_list(void) { int lines = 0; if (c_show_list) group_foreach(&count_group_lines, &lines); else lines = 1; return lines; } static inline int line_visible(int line) { return line >= offset && line < (offset + list_length); } static void draw_attr(double rate1, int prec1, char *unit1, double rate2, int prec2, char *unit2, float usage, int ncol) { char buf[32]; move(row, ncol); addch(ACS_VLINE); printw("%7s%-3s", float2str(rate1, 7, prec1, buf, sizeof(buf)), unit1); printw("%7s%-3s", float2str(rate2, 7, prec2, buf, sizeof(buf)), unit2); if (usage != FLT_MAX) printw("%2.0f%%", usage); else printw("%3s", ""); } static void draw_element(struct element_group *g, struct element *e, void *arg) { int *line = arg; apply_layout(LAYOUT_LIST); if (line_visible(*line)) { char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = ""; double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f; char pad[IFNAMSIZ + 32]; int rx1prec = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0; struct attr *a; NEXT_ROW(); 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 < 6 ? e->e_level * 2 : 12); 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); } if (*line == offset) { attron(A_BOLD); addch(ACS_UARROW); attroff(A_BOLD); addch(' '); } else if (e == current_element) { apply_layout(LAYOUT_SELECTED); addch(' '); attron(A_BOLD); addch(ACS_RARROW); attroff(A_BOLD); apply_layout(LAYOUT_LIST); } else if (*line == offset + list_length - 1 && *line < (list_req - 1)) { attron(A_BOLD); addch(ACS_DARROW); attroff(A_BOLD); addch(' '); } else printw(" "); put_line("%-30.30s", pad); draw_attr(rx1, rx1prec, rxu1, rx2, rx2prec, rxu2, e->e_rx_usage, LIST_COL_1); draw_attr(tx1, tx1prec, txu1, tx2, tx2prec, txu2, e->e_tx_usage, LIST_COL_2); } (*line)++; } static void draw_group(struct element_group *g, void *arg) { int *line = arg; if (line_visible(*line)) { NEXT_ROW(); attron(A_BOLD); put_line("%s", g->g_hdr->gh_title); attroff(A_BOLD); mvaddch(row, LIST_COL_1, ACS_VLINE); attron(A_BOLD); put_line("%7s %7s %%", g->g_hdr->gh_column[0], g->g_hdr->gh_column[1]); attroff(A_BOLD); mvaddch(row, LIST_COL_2, ACS_VLINE); attron(A_BOLD); put_line("%7s %7s %%", g->g_hdr->gh_column[2], g->g_hdr->gh_column[3]); } (*line)++; group_foreach_element(g, draw_element, arg); } static void draw_element_list(void) { int line = 0; group_foreach(draw_group, &line); } static inline int attr_visible(int nattr) { return nattr >= graph_offset && nattr < (graph_offset + ngraph); } static void draw_graph_centered(struct graph *g, int row, int ncol, const char *text) { int hcenter = (g->g_cfg.gc_width / 2) - (strlen(text) / 2) + 8; if (hcenter < 9) hcenter = 9; mvprintw(row, ncol + hcenter, "%.*s", g->g_cfg.gc_width, text); } static void draw_table(struct graph *g, struct graph_table *tbl, struct attr *a, struct history *h, const char *hdr, int ncol) { int i, save_row; char buf[32]; if (!tbl->gt_table) { for (i = g->g_cfg.gc_height; i >= 0; i--) { move(++row, ncol); put_line(""); } return; } move(++row, ncol); put_line("%8s", tbl->gt_y_unit ? : ""); snprintf(buf, sizeof(buf), "(%s %s/%s)", hdr, a->a_def->ad_description, h ? h->h_definition->hd_name : "?"); draw_graph_centered(g, row, ncol, buf); //move(row, ncol + g->g_cfg.gc_width - 3); //put_line("[err %.2f%%]", rtiming.rt_variance.v_error); for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) { move(++row, ncol); put_line("%'8.2f %s", tbl->gt_scale[i], tbl->gt_table + (i * graph_row_size(&g->g_cfg))); } move(++row, ncol); put_line(" 1"); for (i = 1; i <= g->g_cfg.gc_width; i++) { if (i % 5 == 0) { move(row, ncol + i + 7); printw("%2d", i); } } if (!h) { const char *t1 = " No history data available. "; const char *t2 = " Press h to start collecting history. "; int vcenter = g->g_cfg.gc_height / 2; save_row = row; draw_graph_centered(g, save_row - vcenter - 1, ncol, t1); draw_graph_centered(g, save_row - vcenter, ncol, t2); row = save_row; } } static void draw_history_graph(struct attr *a, struct history *h) { struct graph *g; int ncol = 0, save_row; g = graph_alloc(h, &c_graph_cfg); graph_refill(g, h); save_row = row; draw_table(g, &g->g_rx, a, h, "RX", ncol); if (graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE) { ncol = cols / 2; row = save_row; } draw_table(g, &g->g_tx, a, h, "TX", ncol); graph_free(g); } static void draw_attr_graph(struct element *e, struct attr *a, void *arg) { int *nattr = arg; if (attr_visible(*nattr)) { struct history_def *sel; struct history *h; sel = history_current(); c_graph_cfg.gc_unit = a->a_def->ad_unit; list_for_each_entry(h, &a->a_history_list, h_list) { if (h->h_definition != sel) continue; draw_history_graph(a, h); goto out; } draw_history_graph(a, NULL); } out: (*nattr)++; } static void draw_graph(void) { int nattr = 0; element_foreach_attr(current_element, &draw_attr_graph, &nattr); } static int lines_required_for_info(void) { int lines = 1; if (c_show_info) { info_cols = cols / DETAILS_COLS; if (!info_cols) info_cols = 1; lines += (current_element->e_ninfo / info_cols); if (current_element->e_ninfo % info_cols) lines++; } return lines; } static void __draw_info(struct element *e, struct info *info, int *ninfo) { int ncol; ncol = ((*ninfo) * DETAILS_COLS) - 1; move(row, ncol); if (ncol > 0) addch(ACS_VLINE); put_line(" %-14.14s %22.22s", info->i_name, info->i_value); if (++(*ninfo) >= info_cols) { NEXT_ROW(); *ninfo = 0; } } static void draw_info(void) { struct info *info; int i, ninfo = 0; if (!current_element->e_ninfo) return; for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS) - 1, c_show_details ? ACS_PLUS : ACS_TTEE); NEXT_ROW(); list_for_each_entry(info, ¤t_element->e_info_list, i_list) __draw_info(current_element, info, &ninfo); /* * If the last row was incomplete, not all vlines have been drawn. * draw them here */ for (i = 1; i < info_cols; i++) mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE); } static void draw_content(void) { int graph_req, details_req, lines_available, total_req; int info_req, empty_lines; int disable_graph = 0, disable_details = 0, disable_info = 0; if (!current_element) return; /* * Reset selection offset. Will be set in lines_required_for_list(). */ selection_offset = 0; offset = 0; /* Reset graph offset, will be set in lines_required_for_graph() */ graph_offset = 0; lines_available = rows - lines_required_for_statusbar() - lines_required_for_header(); list_req = lines_required_for_list(); graph_req = lines_required_for_graph(); details_req = lines_required_for_details(); info_req = lines_required_for_info(); total_req = list_req + graph_req + details_req + info_req; if (total_req <= lines_available) { /* * Enough lines available for all data to displayed, all * is good. Display the full list. */ list_length = list_req; goto draw; } /* * Not enough lines available for full list and all details * requested... */ if (c_show_list) { /* * ... try shortening the list first. */ list_length = lines_available - (total_req - list_req); if (list_length >= c_list_min) goto draw; } if (c_show_info) { /* try disabling info */ list_length = lines_available - (total_req - info_req + 1); if (list_length >= c_list_min) { disable_info = 1; goto draw; } } if (c_show_details) { /* ... try disabling details */ list_length = lines_available - (total_req - details_req + 1); if (list_length >= c_list_min) { disable_details = 1; goto draw; } } /* ... try disabling graph, details, and info */ list_length = lines_available - 1 - 1 - 1; if (list_length >= c_list_min) { disable_graph = 1; disable_details = 1; disable_info = 1; goto draw; } NEXT_ROW(); put_line("A minimum of %d lines is required to display content.\n", (rows - lines_available) + c_list_min + 2); return; draw: if (selection_offset && list_length > 0) { /* * Vertically align the selected element in the middle * of the list. */ offset = selection_offset - (list_length / 2); /* * If element 0..(list_length/2) is selected, offset is * negative here. Start drawing from first element. */ if (offset < 0) offset = 0; /* * Ensure the full list length is used if one of the * last (list_length/2) elements is selected. */ if (offset > (list_req - list_length)) offset = (list_req - list_length); if (offset >= list_req) BUG(); } if (c_show_list) { draw_element_list(); } else { NEXT_ROW(); hline(ACS_HLINE, cols); center_text(" Press %c to enable list view ", KEY_TOGGLE_LIST); } /* * Graphical statistics */ NEXT_ROW(); hline(ACS_HLINE, cols); mvaddch(row, LIST_COL_1, ACS_BTEE); mvaddch(row, LIST_COL_2, ACS_BTEE); if (!c_show_graph) center_text(" Press %c to enable graphical statistics ", KEY_TOGGLE_GRAPH); else { if (disable_graph) center_text(" Increase screen height to see graphical statistics "); else draw_graph(); } empty_lines = rows - row - details_req - info_req - lines_required_for_statusbar() - 1; while (empty_lines-- > 0) { NEXT_ROW(); put_line(""); } /* * Detailed statistics */ NEXT_ROW(); hline(ACS_HLINE, cols); if (!c_show_details) center_text(" Press %c to enable detailed statistics ", KEY_TOGGLE_DETAILS); else { if (disable_details) center_text(" Increase screen height to see detailed statistics "); else draw_details(); } /* * Additional information */ NEXT_ROW(); hline(ACS_HLINE, cols); if (!c_show_info) center_text(" Press %c to enable additional information ", KEY_TOGGLE_INFO); else { if (disable_info) center_text(" Increase screen height to see additional information "); else draw_info(); } } static void curses_draw(void) { row = 0; move(0,0); getmaxyx(stdscr, rows, cols); if (rows < 4) { clear(); put_line("Screen must be at least 4 rows in height"); goto out; } if (cols < 48) { clear(); put_line("Screen must be at least 48 columns width"); goto out; } current_element = element_current(); current_attr = attr_current(); draw_header(); apply_layout(LAYOUT_DEFAULT); draw_content(); /* fill empty lines with blanks */ while (row < (rows - 1 - lines_required_for_statusbar())) { move(++row, 0); put_line(""); } draw_statusbar(); if (quit_mode) print_message(" Really Quit? (y/n) "); else if (print_help) { if (help_page == 0) draw_help(); #if 0 else draw_help_2(); #endif } out: attrset(0); refresh(); } static int handle_input(int ch) { switch (ch) { case 'q': if (print_help) print_help = 0; else quit_mode = quit_mode ? 0 : 1; return 1; case 0x1b: quit_mode = 0; print_help = 0; return 1; case 'y': if (quit_mode) exit(0); break; case 'n': if (quit_mode) quit_mode = 0; return 1; case 12: case KEY_CLEAR: #ifdef HAVE_REDRAWWIN redrawwin(stdscr); #endif clear(); return 1; case '?': clear(); print_help = print_help ? 0 : 1; return 1; case KEY_TOGGLE_GRAPH: c_show_graph = !c_show_graph; if (c_show_graph && !c_ngraph) c_ngraph = 1; return 1; case KEY_TOGGLE_DETAILS: c_show_details = !c_show_details; return 1; case KEY_TOGGLE_LIST: c_show_list = !c_show_list; return 1; case KEY_TOGGLE_INFO: c_show_info = !c_show_info; return 1; case KEY_COLLECT_HISTORY: if (current_attr) { attr_start_collecting_history(current_attr); return 1; } break; case KEY_PPAGE: { int i; for (i = 1; i < list_length; i++) element_select_prev(); } return 1; case KEY_NPAGE: { int i; for (i = 1; i < list_length; i++) element_select_next(); } return 1; case KEY_DOWN: element_select_next(); return 1; case KEY_UP: element_select_prev(); return 1; case KEY_LEFT: attr_select_prev(); return 1; case KEY_RIGHT: attr_select_next(); return 1; case ']': group_select_next(); return 1; case '[': group_select_prev(); return 1; case '<': c_ngraph--; if (c_ngraph <= 1) c_ngraph = 1; return 1; case '>': c_ngraph++; if (c_ngraph > 32) c_ngraph = 32; return 1; case '\t': history_select_next(); return 1; } return 0; } static void curses_pre(void) { static int init = 0; if (!init) { curses_init(); init = 1; } for (;;) { int ch = getch(); if (ch == -1) break; if (handle_input(ch)) curses_draw(); } } static void print_module_help(void) { printf( "curses - Curses Output\n" \ "\n" \ " Interactive curses UI. Press '?' to see help.\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\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" \ " gheight=NUM Height of graph (default: 6)\n" \ " gwidth=NUM Width of graph (default: 60)\n" \ " ngraph=NUM Number of graphs (default: 1)\n" \ " nocolors Do not use colors\n" \ " graph Show graphical stats by default\n" \ " details Show detailed stats by default\n" \ " minlist=INT Minimum item list length\n"); } static void curses_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "fgchar") && value) c_graph_cfg.gc_foreground = value[0]; else if (!strcasecmp(type, "bgchar") && value) c_graph_cfg.gc_background = value[0]; else if (!strcasecmp(type, "nchar") && value) c_graph_cfg.gc_noise = value[0]; else if (!strcasecmp(type, "uchar") && value) c_graph_cfg.gc_unknown = value[0]; else if (!strcasecmp(type, "gheight") && value) c_graph_cfg.gc_height = strtol(value, NULL, 0); else if (!strcasecmp(type, "gwidth") && value) c_graph_cfg.gc_width = strtol(value, NULL, 0); else if (!strcasecmp(type, "ngraph") && value) { c_ngraph = strtol(value, NULL, 0); c_show_graph = !!c_ngraph; } else if (!strcasecmp(type, "details")) c_show_details = 1; else if (!strcasecmp(type, "nocolors")) c_use_colors = 0; else if (!strcasecmp(type, "minlist") && value) c_list_min = strtol(value, NULL, 0); else if (!strcasecmp(type, "help")) { print_module_help(); exit(0); } } static struct bmon_module curses_ops = { .m_name = "curses", .m_flags = BMON_MODULE_DEFAULT, .m_shutdown = curses_shutdown, .m_pre = curses_pre, .m_do = curses_draw, .m_parse_opt = curses_parse_opt, }; static void __init do_curses_init(void) { output_register(&curses_ops); } bmon-3.8/src/out_format.c000066400000000000000000000225731255465122100154450ustar00rootroot00000000000000/* * out_format.c Formatted Output * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include #include #include #include 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))) goto out; if (!strncasecmp(type, "rx:", 3)) { snprintf(buf, len, "%" PRIu64, a->a_rx_rate.r_total); return buf; } else if (!strncasecmp(type, "tx:", 3)) { snprintf(buf, len, "%" PRIu64, 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 \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 children (0|1)\n" \ " attr:rx: RX counter of attribute \n" \ " :tx: TX counter of attribute \n" \ " :rxrate: RX rate of attribute \n" \ " :txrate: TX rate of attribute \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" \ " \"Item: $(element:name)\\n\" \\\n" \ " \"Bytes Rate: $(attr:rxrate:bytes)/$(attr:txrate:bytes)\\n\" \\\n" \ " \"Packets Rate: $(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); } bmon-3.8/src/out_null.c000066400000000000000000000033331255465122100151200ustar00rootroot00000000000000/* * out_null.c Null Output * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include static void print_help(void) { printf( "null - No output\n" \ "\n" \ " Disable primary output method\n" \ " Author: Thomas Graf \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); } bmon-3.8/src/output.c000066400000000000000000000050171255465122100146200ustar00rootroot00000000000000/* * output.c Output API * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include #include #include 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); } bmon-3.8/src/unit.c000066400000000000000000000115771255465122100142470ustar00rootroot00000000000000/* * unit.c Unit Definitions * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include #include static struct unit *byte_unit, *bit_unit; static LIST_HEAD(units); static struct list_head *get_flist(struct unit *unit) { int div = UNIT_DEFAULT; if (cfg_getbool(cfg, "use_bit")) div = UNIT_BIT; else if (cfg_getbool(cfg, "use_si")) div = UNIT_SI; if (!list_empty(&unit->u_div[div])) return &unit->u_div[div]; 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. */ double 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.0f && prec) *prec = 0; *name = f->f_name; return f->f_divisor; } double unit_value2str(uint64_t value, struct unit *unit, char **name, int *prec) { double div = unit_divisor(value, unit, name, prec); double v = (double) value; if (fmod(v, div) == 0.0f && prec) *prec = 0; return v / div; } void fraction_free(struct fraction *f) { if (!f) return; list_del(&f->f_list); 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, "%" PRIu64, 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, "%" PRIu64, 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); } bmon-3.8/src/utils.c000066400000000000000000000210601255465122100144140ustar00rootroot00000000000000/* * utils.c General purpose utilities * * Copyright (c) 2001-2013 Thomas Graf * 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 #include #include 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; ts1->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, ""); } 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