Compare commits
	
		
			47 Commits
		
	
	
		
			coverity_s
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 969cebd4ae | |||
| 5677863e61 | |||
| ed8528cf9c | |||
| 737c642819 | |||
| b44d0152c4 | |||
| fdd139ada2 | |||
| 49ce252ec5 | |||
| 14db0bff4c | |||
| 3413751795 | |||
| 1b3f11bde3 | |||
| af8923b779 | |||
| 3e4970485d | |||
| f312679738 | |||
| 2efc2f4a60 | |||
| a3d894000b | |||
| 8b2638c349 | |||
| a5301347f6 | |||
| 29fb4317d7 | |||
| 32d8c76b18 | |||
| 577112870d | |||
| 5b938e05c7 | |||
| 5cd24ffd6a | |||
| 702df3c0a1 | |||
| 7317715e15 | |||
| 86f6da0703 | |||
| 723f6a5b47 | |||
| ddcd5e7d24 | |||
| df271c43a4 | |||
| 8f39217bd7 | |||
| e47a376f70 | |||
| 828b5b5368 | |||
| 1c25eacc95 | |||
| f177718f24 | |||
| cc22e4e35d | |||
| 19c35e4990 | |||
| 70e6f97b65 | |||
| a6c635dc96 | |||
| f78c0e5b98 | |||
| 0e08ec1b79 | |||
| 74770b8806 | |||
| fa6abf3a80 | |||
| 0103671f1f | |||
| 4efaa8ce9e | |||
| 1f79ea4396 | |||
| 67b6ee3bd6 | |||
| cbcdab6669 | |||
| 8dcd666db6 | 
							
								
								
									
										42
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								.travis.yml
									
									
									
									
									
								
							| @ -1,10 +1,40 @@ | ||||
| language: c | ||||
|  | ||||
| os: | ||||
|   - linux | ||||
|   - osx | ||||
|  | ||||
| env: | ||||
|   global: | ||||
|     - secure: "C87Pgf5AVDoyQfm9MIv81g" | ||||
|  | ||||
| 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 | ||||
|  | ||||
| # container-based builds | ||||
| sudo: false | ||||
| addons: | ||||
|   apt: | ||||
|     packages: | ||||
|     # packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise | ||||
|     - libconfuse-dev | ||||
|     - libncurses5-dev | ||||
|     - libnl-3-dev | ||||
|     - libnl-route-3-dev | ||||
|   coverity_scan: | ||||
|     project: | ||||
|       name: "tgraf/bmon" | ||||
|       description: "bandwidth monitor" | ||||
|     notification_email: tgraf@suug.ch | ||||
|     build_command_prepend: "./autogen.sh && ./configure" | ||||
|     build_command: "make -j2" | ||||
|     branch_pattern: coverity_scan | ||||
|  | ||||
|  | ||||
| install: | ||||
|   - if [ "$TRAVIS_BRANCH" = "coverity_scan" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$CC" = "gcc" ]; then exit ; fi | ||||
|   - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update > /dev/null && brew install confuse ; fi | ||||
|  | ||||
| script: | ||||
|   - ./.travis/run.sh | ||||
|  | ||||
							
								
								
									
										24
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								NEWS
									
									
									
									
									
								
							| @ -1,34 +1,46 @@ | ||||
| HEAD | ||||
|  | ||||
| v4.0 - Dec 13, 2016 | ||||
|  * Use monotonic clock instead of realtime clock | ||||
|  * Pick default selected interface based on policy | ||||
|  * Collect RX NoHandler statistics if available (Linux) | ||||
|  * CentOS installation instructions | ||||
|  * Proper stdout flush in ASCII mode | ||||
|  * Bugfixes | ||||
|  | ||||
| v3.9 - Jul 19, 2016 | ||||
|  * Color support | ||||
|  * Add ability to reset statistics from curses UI | ||||
|  * NetBSD compile fix | ||||
|  * Option to enable info display by default | ||||
|  * Additional IPv6 statistics | ||||
|  * Various fixes | ||||
|  | ||||
| v3.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 | ||||
|  | ||||
							
								
								
									
										60
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								README.md
									
									
									
									
									
								
							| @ -18,7 +18,47 @@ interface and a programmable text output for scripting. | ||||
| ``` | ||||
| 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 | ||||
| apt-get install build-essential make libconfuse-dev libnl-3-dev libnl-route-3-dev libncurses-dev pkg-config dh-autoreconf | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| make install | ||||
| bmon | ||||
| ``` | ||||
| ## CentOS (6) Installation | ||||
|  | ||||
| ``` | ||||
| git clone https://github.com/tgraf/bmon.git | ||||
| cd bmon | ||||
| yum install make libconfuse-devel libnl3-devel libnl-route3-devel ncurses-devel | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| make install | ||||
| bmon | ||||
| ``` | ||||
|  | ||||
| ## OSX Installation | ||||
|  | ||||
| ### Brew | ||||
| ``` | ||||
| brew install bmon | ||||
| ``` | ||||
|  | ||||
| ### Compile yourself | ||||
| Install libconfuse | ||||
| ``` | ||||
| wget https://github.com/martinh/libconfuse/releases/download/v2.8/confuse-2.8.zip | ||||
| unzip confuse-2.8.zip && cd confuse-2.8 | ||||
| PATH=/usr/local/opt/gettext/bin:$PATH ./configure | ||||
| make | ||||
| make install | ||||
| ``` | ||||
|  | ||||
| Install bmon | ||||
| ``` | ||||
| git clone https://github.com/tgraf/bmon.git | ||||
| cd bmon | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| @ -27,8 +67,13 @@ bmon | ||||
| ``` | ||||
|  | ||||
| ------------- | ||||
| ## New in 3.8 | ||||
|  * Don't disable Netlink if TC stats are unavailable | ||||
| ## New in 4.0 | ||||
|  * Use monotonic clock instead of realtime clock | ||||
|  * Pick default selected interface based on policy | ||||
|  * Collect RX NoHandler statistics if available (Linux) | ||||
|  * CentOS installation instructions | ||||
|  * Proper stdout flush in ASCII mode | ||||
|  * Bugfixes | ||||
|  | ||||
| ------------- | ||||
| ### Usage | ||||
| @ -44,12 +89,15 @@ provided via: | ||||
|  | ||||
| ## Screenshots | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Copyright | ||||
|  | ||||
| > *Copyright (c) 2001-2014 Thomas Graf <tgraf@suug.ch>* | ||||
| Various authors, see git commit log. | ||||
|  | ||||
| > *Copyright (c) 2001-2016 Thomas Graf <tgraf@suug.ch>* | ||||
| > *Copyright (c) 2013 Red Hat, Inc.* | ||||
|  | ||||
| Please see the [LICENSE.BSD](https://github.com/tgraf/bmon/blob/master/LICENSE.BSD) | ||||
|  | ||||
							
								
								
									
										19
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								configure.ac
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| # | ||||
| # configure.in      Configure Script | ||||
| # | ||||
| # Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch> | ||||
| # Copyright (c) 2001-2016 Thomas Graf <tgraf@suug.ch> | ||||
| # | ||||
| # Permission is hereby granted, free of charge, to any person obtaining a | ||||
| # copy of this software and associated documentation files (the "Software"), | ||||
| @ -21,7 +21,7 @@ | ||||
| # 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_INIT(bmon, 4.0, [], [], [https://github.com/tgraf/bmon]) | ||||
| AC_CONFIG_HEADERS(include/bmon/defs.h) | ||||
| AC_CONFIG_AUX_DIR([build-aux]) | ||||
| AC_CONFIG_MACRO_DIR([m4]) | ||||
| @ -58,10 +58,18 @@ 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(atexit clock_gettime memset pow socket strcasecmp) | ||||
| AC_CHECK_FUNCS(strchr strdup strerror strncasecmp strstr strtol) | ||||
| AC_CHECK_FUNCS(uname getdate) | ||||
|  | ||||
| AC_PATH_PROG([PKG_CONFIG], [pkg-config], [no]) | ||||
| AS_IF([test "x$PKG_CONFIG" = "xno"],[ | ||||
|    AC_MSG_ERROR([ | ||||
|       *** The pkg-config script could not be found. Make sure it is | ||||
|       *** in your path, or set the PKG_CONFIG environment variable | ||||
|       *** to the full path to pkg-config.]) | ||||
|    ]) | ||||
|  | ||||
| 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]) | ||||
| @ -78,6 +86,9 @@ esac | ||||
|  | ||||
| AC_CHECK_LIB(m, pow, [], AC_MSG_ERROR([requires libm])) | ||||
|  | ||||
| # Don't fail if not found (for instance, OS X does not have clock_gettime) | ||||
| AC_CHECK_LIB(rt, clock_gettime, [], []) | ||||
|  | ||||
| BMON_LIB="" | ||||
|  | ||||
| ##################################################################### | ||||
| @ -164,7 +175,7 @@ case ${target_os} in | ||||
| 	AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system]) | ||||
|     ;; | ||||
|  | ||||
|     *bsd*) | ||||
|     *bsd*|dragonfly*) | ||||
| 	AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) | ||||
|     ;; | ||||
|  | ||||
|  | ||||
| @ -11,10 +11,10 @@ | ||||
|  | ||||
| /*  | ||||
|  * element eth0 { | ||||
|  * 	description	= { "My description" } | ||||
|  * 	rxmax		= { 10000 } | ||||
|  * 	txmax		= { 10000 } | ||||
|  * 	max		= { 12500000 } | ||||
|  * 	description	= "My description" | ||||
|  * 	rxmax		= 10000 | ||||
|  * 	txmax		= 10000 | ||||
|  * 	max		= 12500000 | ||||
|  * } | ||||
|  */ | ||||
|  | ||||
| @ -86,3 +86,27 @@ history day { | ||||
| 	interval	= 86400. | ||||
| 	size		= 60 | ||||
| } | ||||
|  | ||||
| layout colors { | ||||
|     color default { | ||||
|        color_pair  = {"white", "black"} | ||||
|     } | ||||
|     color statusbar { | ||||
|         color_pair = {"blue", "white", "reverse"} | ||||
|     } | ||||
|     color header { | ||||
|         color_pair = {"yellow", "black"} | ||||
|     } | ||||
|     color list { | ||||
|         color_pair = {"white", "black"} | ||||
|     } | ||||
|     color selected { | ||||
|         color_pair = {"white", "black", "reverse"} | ||||
|     } | ||||
|     color RX_graph { | ||||
|         color_pair = {"green", "black"} | ||||
|     } | ||||
|     color TX_graph { | ||||
|         color_pair = {"red", "black"} | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -16,4 +16,5 @@ noinst_HEADERS = \ | ||||
| 	bmon/module.h \ | ||||
| 	bmon/output.h \ | ||||
| 	bmon/unit.h \ | ||||
| 	bmon/layout.h \ | ||||
| 	bmon/utils.h | ||||
|  | ||||
| @ -42,6 +42,9 @@ struct rate | ||||
| 	/* Value of r_current at last read */ | ||||
| 	uint64_t		r_prev; | ||||
|  | ||||
| 	/* Reset value to substract to emulate statistics reset */ | ||||
| 	uint64_t		r_reset; | ||||
|  | ||||
| 	/* Rate per second calculated every `rate_interval' */ | ||||
| 	float			r_rate; | ||||
|  | ||||
| @ -49,6 +52,8 @@ struct rate | ||||
| 	timestamp_t		r_last_calc; | ||||
| }; | ||||
|  | ||||
| extern uint64_t			rate_get_total(struct rate *); | ||||
|  | ||||
| enum { | ||||
| 	ATTR_TYPE_UNSPEC, | ||||
| 	ATTR_TYPE_COUNTER, | ||||
| @ -134,5 +139,6 @@ extern struct attr *		attr_select_prev(void); | ||||
| extern struct attr *		attr_current(void); | ||||
|  | ||||
| extern void			attr_start_collecting_history(struct attr *); | ||||
| extern void			attr_reset_counter(struct attr *a); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| @ -74,6 +74,8 @@ enum { | ||||
| 	LAYOUT_HEADER, | ||||
| 	LAYOUT_LIST, | ||||
| 	LAYOUT_SELECTED, | ||||
|     LAYOUT_RX_GRAPH, | ||||
|     LAYOUT_TX_GRAPH, | ||||
| 	__LAYOUT_MAX | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -48,7 +48,7 @@ | ||||
| #include <dirent.h> | ||||
| #ifdef SYS_BSD | ||||
| # include <float.h> | ||||
| #else | ||||
| #elif !defined(__ANDROID__) | ||||
| # include <values.h> | ||||
| #endif | ||||
|  | ||||
|  | ||||
| @ -9,6 +9,9 @@ | ||||
| /* Define to 1 if you have the `atexit' function. */ | ||||
| #undef HAVE_ATEXIT | ||||
|  | ||||
| /* Define to 1 if you have the `clock_gettime' function. */ | ||||
| #undef HAVE_CLOCK_GETTIME | ||||
|  | ||||
| /* have curses */ | ||||
| #undef HAVE_CURSES | ||||
|  | ||||
| @ -39,15 +42,15 @@ | ||||
| /* Define to 1 if you have the <getopt.h> header file. */ | ||||
| #undef HAVE_GETOPT_H | ||||
|  | ||||
| /* Define to 1 if you have the `gettimeofday' function. */ | ||||
| #undef HAVE_GETTIMEOFDAY | ||||
|  | ||||
| /* Define to 1 if you have the <inttypes.h> header file. */ | ||||
| #undef HAVE_INTTYPES_H | ||||
|  | ||||
| /* Define to 1 if you have the `m' library (-lm). */ | ||||
| #undef HAVE_LIBM | ||||
|  | ||||
| /* Define to 1 if you have the `rt' library (-lrt). */ | ||||
| #undef HAVE_LIBRT | ||||
|  | ||||
| /* Define to 1 if you have the <memory.h> header file. */ | ||||
| #undef HAVE_MEMORY_H | ||||
|  | ||||
|  | ||||
							
								
								
									
										130
									
								
								include/bmon/layout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								include/bmon/layout.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
|  | ||||
| #ifndef __BMON_LAYOUT_H_ | ||||
| #define __BMON_LAYOUT_H_ | ||||
|  | ||||
| #include <bmon/bmon.h> | ||||
| #include <bmon/conf.h> | ||||
| #include <bmon/unit.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
|  | ||||
| static int parse_color(const char* color) | ||||
| { | ||||
|     int color_code = -1; | ||||
|  | ||||
|     if ((strcasestr(color, "red") != NULL)) | ||||
|         color_code = COLOR_RED; | ||||
|     else if ((strcasestr(color, "green") != NULL)) | ||||
|         color_code = COLOR_GREEN; | ||||
|     else if ((strcasestr(color, "white") != NULL)) | ||||
|         color_code = COLOR_WHITE; | ||||
|     else if ((strcasestr(color, "black") != NULL)) | ||||
|         color_code = COLOR_BLACK; | ||||
|     else if ((strcasestr(color, "blue") != NULL)) | ||||
|         color_code = COLOR_BLUE; | ||||
|     else if ((strcasestr(color, "yellow") != NULL)) | ||||
|         color_code = COLOR_YELLOW; | ||||
|     else if ((strcasestr(color, "magenta") != NULL)) | ||||
|         color_code = COLOR_MAGENTA; | ||||
|     else if ((strcasestr(color, "cyan") != NULL)) | ||||
|         color_code = COLOR_CYAN; | ||||
|     else if ((atoi(color) >= 0)) | ||||
|         color_code = atoi(color); | ||||
|  | ||||
|     return color_code; | ||||
| } | ||||
|  | ||||
| /* | ||||
|     A_NORMAL        Normal display (no highlight) | ||||
|     A_STANDOUT      Best highlighting mode of the terminal. | ||||
|     A_UNDERLINE     Underlining | ||||
|     A_REVERSE       Reverse video | ||||
|     A_BLINK         Blinking | ||||
|     A_DIM           Half bright | ||||
|     A_BOLD          Extra bright or bold | ||||
|     A_PROTECT       Protected mode | ||||
|     A_INVIS         Invisible or blank mode | ||||
|     A_ALTCHARSET    Alternate character set | ||||
|     A_CHARTEXT      Bit-mask to extract a character | ||||
| */ | ||||
|  | ||||
| static int parse_attribute(const char* attr) | ||||
| { | ||||
|     /* no attribute is valid, so we have nothing to do */ | ||||
|     if (attr == NULL) | ||||
|         return 0; | ||||
|  | ||||
|     if ((strcasestr(attr, "normal") != NULL)) | ||||
|         return A_NORMAL; | ||||
|     else if ((strcasestr(attr, "standout") != NULL)) | ||||
|         return A_STANDOUT; | ||||
|     else if ((strcasestr(attr, "underline") != NULL)) | ||||
|         return A_UNDERLINE; | ||||
|     else if ((strcasestr(attr, "reverse") != NULL)) | ||||
|         return A_REVERSE; | ||||
|     else if ((strcasestr(attr, "blink") != NULL)) | ||||
|         return A_BLINK; | ||||
|     else if ((strcasestr(attr, "dim") != NULL)) | ||||
|         return A_DIM; | ||||
|     else if ((strcasestr(attr, "bold") != NULL)) | ||||
|         return A_BOLD; | ||||
|     else if ((strcasestr(attr, "protect") != NULL)) | ||||
|         return A_PROTECT; | ||||
|     else if ((strcasestr(attr, "invis") != NULL)) | ||||
|         return A_INVIS; | ||||
|     else if ((strcasestr(attr, "altcharset") != NULL)) | ||||
|         return A_ALTCHARSET; | ||||
|     else if ((strcasestr(attr, "chartext") != NULL)) | ||||
|         return A_CHARTEXT; | ||||
|  | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void add_layout(const char *layout_name, cfg_t *color_cfg) | ||||
| { | ||||
|     const char *fg, *bg, *attr_str = NULL; | ||||
|     int size = -1, fg_code, bg_code, attr_mask, layout_idx = 0; | ||||
|  | ||||
|     size = cfg_size(color_cfg, "color_pair"); | ||||
|     fg = cfg_getnstr(color_cfg, "color_pair", 0); | ||||
|     bg = cfg_getnstr(color_cfg, "color_pair", 1); | ||||
|     if (size > 2) | ||||
|         attr_str = cfg_getnstr(color_cfg, "color_pair", 2); | ||||
|  | ||||
|     fg_code = parse_color(fg); | ||||
|     bg_code = parse_color(bg); | ||||
|     if (fg_code == -1 || bg_code == -1) { | ||||
|         quit("Unknown color [%s]: %s\n", (fg_code == -1) ? "fg" : "bg", | ||||
|                 (fg_code == -1) ? fg : bg); | ||||
|     } | ||||
|     attr_mask = parse_attribute(attr_str); | ||||
|     if (attr_mask == -1) { | ||||
|         quit("Unknown attribute: '%s'\n", attr_str); | ||||
|     } | ||||
|  | ||||
|     DBG("%s:\tfg: %s bg: %s attr: %s\n", layout_name, fg, bg, attr_str); | ||||
|  | ||||
|     if ((strcasecmp(layout_name, "default") == 0)) | ||||
|         layout_idx = LAYOUT_DEFAULT; | ||||
|     else if ((strcasecmp(layout_name, "statusbar") == 0)) | ||||
|         layout_idx = LAYOUT_STATUSBAR; | ||||
|     else if ((strcasecmp(layout_name, "header") == 0)) | ||||
|         layout_idx = LAYOUT_HEADER; | ||||
|     else if ((strcasecmp(layout_name, "list") == 0)) | ||||
|         layout_idx = LAYOUT_LIST; | ||||
|     else if ((strcasecmp(layout_name, "selected") == 0)) | ||||
|         layout_idx = LAYOUT_SELECTED; | ||||
|     else if ((strcasecmp(layout_name, "rx_graph") == 0)) | ||||
|         layout_idx = LAYOUT_RX_GRAPH; | ||||
|     else if ((strcasecmp(layout_name, "tx_graph") == 0)) | ||||
|         layout_idx = LAYOUT_TX_GRAPH; | ||||
|     else { | ||||
|         quit("Unknown layout name: '%s'\n", layout_name); | ||||
|     } | ||||
|  | ||||
|     struct layout l = { fg_code, bg_code, attr_mask}; | ||||
|     cfg_layout[layout_idx] = l; | ||||
| } | ||||
|  | ||||
| #endif /* __BMON_LAYOUT_H_ */ | ||||
							
								
								
									
										14
									
								
								man/bmon.8
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								man/bmon.8
									
									
									
									
									
								
							| @ -34,7 +34,7 @@ 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\-\-output\fRMODULE[:OPTIONS][,MODULE...] | ||||
| \fB \-o\fR, \fB\-\-output=\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 | ||||
| @ -58,7 +58,7 @@ Set policy defining which network interfaces to display. See | ||||
| INTERFACE SELECTION for more details. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-a\fR, \fB\-\-show\-all=\fR | ||||
| \fB \-a\fR, \fB\-\-show\-all\fR | ||||
| .RS 4 | ||||
| Display all interfaces, even interface that are administratively down. | ||||
| .RE | ||||
| @ -137,7 +137,7 @@ 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 '?' | ||||
| estimations and a graphical representation of each attribute. Press '?' | ||||
| to display the quick reference guide. This is the default output mode. | ||||
|  | ||||
| .TP | ||||
| @ -220,6 +220,14 @@ and eth1: | ||||
| .RS 4 | ||||
| \fBbmon \-p eth0,eth1 \-o curses\fP | ||||
| .RE | ||||
| .PP | ||||
| To run bmon in format mode, monitoring any eth* interfaces, with a specified | ||||
| format string: | ||||
| .PP | ||||
| .RS 4 | ||||
| \fBbmon \-p \(aqeth*\(aq \-o format:fmt=\(aq$(element:name) $(attr:rxrate:packets)\en\(aq\fP | ||||
| .RE | ||||
| .PP | ||||
|  | ||||
| .SH "FILES" | ||||
| /etc/bmon.conf | ||||
|  | ||||
							
								
								
									
										13
									
								
								src/attr.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/attr.c
									
									
									
									
									
								
							| @ -524,6 +524,11 @@ static float __calc_usage(double rate, uint64_t max) | ||||
| 	return 100.0f / ((double) max / (rate * cfg_rate_interval)); | ||||
| } | ||||
|  | ||||
| uint64_t rate_get_total(struct rate *r) | ||||
| { | ||||
| 	return r->r_total - r->r_reset; | ||||
| } | ||||
|  | ||||
| void attr_calc_usage(struct attr *a, float *rx, float *tx, | ||||
| 		     uint64_t rxmax, uint64_t txmax) | ||||
| { | ||||
| @ -626,6 +631,14 @@ void attr_notify_update(struct attr *a, timestamp_t *ts) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void attr_reset_counter(struct attr *a) | ||||
| { | ||||
| 	if (a->a_def->ad_type == ATTR_TYPE_COUNTER) { | ||||
| 		a->a_rx_rate.r_reset = a->a_rx_rate.r_total; | ||||
| 		a->a_tx_rate.r_reset = a->a_tx_rate.r_total; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void __exit attr_exit(void) | ||||
| { | ||||
| 	struct attr_def *ad, *n; | ||||
|  | ||||
| @ -67,14 +67,14 @@ static char *usage_text = | ||||
| "   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" \ | ||||
| "       -o curses:help     # Shows a help text for curses 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"; | ||||
| "Please see the bmon(8) man pages for full documentation.\n"; | ||||
|  | ||||
| static void do_shutdown(void) | ||||
| { | ||||
|  | ||||
							
								
								
									
										100
									
								
								src/conf.c
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								src/conf.c
									
									
									
									
									
								
							| @ -30,6 +30,7 @@ | ||||
| #include <bmon/element.h> | ||||
| #include <bmon/element_cfg.h> | ||||
| #include <bmon/history.h> | ||||
| #include <bmon/layout.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
| cfg_t *cfg; | ||||
| @ -69,6 +70,16 @@ static cfg_opt_t unit_opts[] = { | ||||
| 	CFG_END() | ||||
| }; | ||||
|  | ||||
| static cfg_opt_t color_opts[] = { | ||||
|     CFG_STR_LIST("color_pair", "", CFGF_NONE), | ||||
|     CFG_END() | ||||
| }; | ||||
|  | ||||
| static cfg_opt_t layout_opts[] = { | ||||
|     CFG_SEC("color", color_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), | ||||
| @ -87,6 +98,7 @@ static cfg_opt_t global_opts[] = { | ||||
| 	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_SEC("layout", layout_opts, CFGF_MULTI | CFGF_TITLE), | ||||
| 	CFG_END() | ||||
| }; | ||||
|  | ||||
| @ -103,22 +115,26 @@ static char *		configfile		= NULL; | ||||
| #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 */ | ||||
|     {-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 */ | ||||
|     {-1, -1, 0},            /* RX graph */ | ||||
|     {-1, -1, 0},            /* TX graph */ | ||||
| }; | ||||
| #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 */ | ||||
| 	{0, 0, 0},                               /* dummy, not used */ | ||||
| 	{COLOR_WHITE, COLOR_BLACK, 0},           /* default */ | ||||
| 	{COLOR_BLUE,   COLOR_GREEN, A_REVERSE},  /* statusbar */ | ||||
| 	{COLOR_GREEN,  COLOR_BLACK, 0},          /* header */ | ||||
| 	{COLOR_WHITE,  COLOR_BLACK, 0},          /* list */ | ||||
| 	{COLOR_YELLOW, COLOR_BLACK, A_REVERSE},  /* selected */ | ||||
|     {COLOR_GREEN,  COLOR_BLACK, 0},          /* RX graph */ | ||||
|     {COLOR_RED,    COLOR_BLACK, 0},          /* TX graph */ | ||||
| }; | ||||
| #endif | ||||
| #endif | ||||
| @ -423,6 +439,41 @@ static void configfile_read_attrs(void) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void configfile_read_layout_cfg(void) | ||||
| { | ||||
|     int i, nlayouts; | ||||
|     cfg_t *lout; | ||||
|     nlayouts = cfg_size(cfg, "layout"); | ||||
|     for (i = 0; i < nlayouts; i++) | ||||
|     { | ||||
|         int c, ncolors; | ||||
|         const char *name; | ||||
|         if (!(lout = cfg_getnsec(cfg, "layout", i))) | ||||
|             BUG(); | ||||
|  | ||||
|         if (!(name = cfg_title(lout))) | ||||
|             BUG(); | ||||
|  | ||||
|         ncolors = cfg_size(lout, "color"); | ||||
|         if (ncolors > LAYOUT_MAX) { | ||||
|             fprintf(stderr, "Warning excceeded maximum number of layouts\n"); | ||||
|             ncolors = LAYOUT_MAX; | ||||
|         } | ||||
|  | ||||
|         for (c = 0; c < ncolors; c++) { | ||||
|             cfg_t *color_pair; | ||||
|  | ||||
|             if (!(color_pair = cfg_getnsec(lout, "color", c))) | ||||
|                 BUG(); | ||||
|  | ||||
|             if (!(name = cfg_title(color_pair))) | ||||
|                 BUG(); | ||||
|  | ||||
|             add_layout(name, color_pair); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void conf_read(const char *path, int must) | ||||
| { | ||||
| 	int err; | ||||
| @ -450,6 +501,7 @@ static void conf_read(const char *path, int must) | ||||
| 	configfile_read_history(); | ||||
| 	configfile_read_attrs(); | ||||
| 	configfile_read_element_cfg(); | ||||
|     configfile_read_layout_cfg(); | ||||
| } | ||||
|  | ||||
| static const char default_config[] = \ | ||||
| @ -508,6 +560,29 @@ static const char default_config[] = \ | ||||
| "history day {" \ | ||||
| "	interval	= 86400.0" \ | ||||
| "	size		= 60" \ | ||||
| "}" | ||||
| "layout colors {" \ | ||||
| "   color default {" \ | ||||
| "       color_pair = { \"white\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color statusbar{" \ | ||||
| "       color_pair = { \"blue\", \"white\", \"reverse\" }" \ | ||||
| "   }" \ | ||||
| "   color header {" \ | ||||
| "       color_pair = { \"yellow\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color list {" \ | ||||
| "       color_pair = { \"white\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color selected {" \ | ||||
| "       color_pair = { \"yellow\", \"black\", \"reverse\" }" \ | ||||
| "   }" \ | ||||
| "   color rx_graph {" \ | ||||
| "       color_pair = { \"green\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color tx_graph {" \ | ||||
| "       color_pair = { \"red\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "}"; | ||||
|  | ||||
| static void conf_read_default(void) | ||||
| @ -524,6 +599,7 @@ static void conf_read_default(void) | ||||
| 	configfile_read_history(); | ||||
| 	configfile_read_attrs(); | ||||
| 	configfile_read_element_cfg(); | ||||
|     configfile_read_layout_cfg(); | ||||
| } | ||||
|  | ||||
| void configfile_read(void) | ||||
|  | ||||
| @ -201,12 +201,6 @@ void element_free(struct element *e) | ||||
| 	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); | ||||
|  | ||||
| @ -221,6 +215,12 @@ void element_free(struct element *e) | ||||
| 		list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list) | ||||
| 			attr_free(a); | ||||
|  | ||||
| 	if (e->e_group->g_current == e) { | ||||
| 		element_select_prev(); | ||||
| 		if (e->e_group->g_current == e) | ||||
| 			e->e_group->g_current = NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_del(&e->e_list); | ||||
| 	e->e_group->g_nelements--; | ||||
|  | ||||
| @ -358,6 +358,26 @@ int element_set_usage_attr(struct element *e, const char *usage) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void element_pick_from_policy(struct element_group *g) | ||||
| { | ||||
| 	if (!list_empty(&allowed)) { | ||||
| 		struct policy *p; | ||||
|  | ||||
| 		list_for_each_entry(p, &allowed, p_list) { | ||||
| 			struct element *e; | ||||
|  | ||||
| 			list_for_each_entry(e, &g->g_elements, e_list) { | ||||
| 				if (match_mask(p, e->e_name)) { | ||||
| 					g->g_current = e; | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	element_select_first(); | ||||
| } | ||||
|  | ||||
| struct element *element_current(void) | ||||
| { | ||||
| 	struct element_group *g; | ||||
| @ -365,8 +385,12 @@ struct element *element_current(void) | ||||
| 	if (!(g = group_current())) | ||||
| 		return NULL; | ||||
|  | ||||
| 	/* | ||||
| 	 * If no element is picked yet, pick a default interface according to | ||||
| 	 * the selection policy. | ||||
| 	 */ | ||||
| 	if (!g->g_current) | ||||
| 		element_select_first(); | ||||
| 		element_pick_from_policy(g); | ||||
|  | ||||
| 	return g->g_current; | ||||
| } | ||||
|  | ||||
| @ -261,7 +261,7 @@ static void __init group_init(void) | ||||
| { | ||||
| 	DBG("init"); | ||||
|  | ||||
| 	group_new_hdr("intf", "Interfaces", | ||||
| 	group_new_hdr(DEFAULT_GROUP, "Interfaces", | ||||
| 		      "RX bps", "pps", "TX bps", "pps"); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -89,7 +89,11 @@ static void dummy_read(void) | ||||
| 		char gname[32]; | ||||
| 		struct element_group *group; | ||||
|  | ||||
| 		snprintf(gname, sizeof(gname), "group%02d", gidx); | ||||
| 		if (gidx == 0) | ||||
| 			snprintf(gname, sizeof(gname), "%s", DEFAULT_GROUP); | ||||
| 		else | ||||
| 			snprintf(gname, sizeof(gname), "group%02d", gidx); | ||||
|  | ||||
| 		group = group_lookup(gname, GROUP_CREATE); | ||||
|  | ||||
| 		for (n = 0; n < c_numdev; n++) { | ||||
|  | ||||
| @ -60,6 +60,11 @@ static struct bmon_module netlink_ops; | ||||
| # define RTNL_LINK_IP6_CEPKTS		-1 | ||||
| #endif | ||||
|  | ||||
| /* Not available prior to libnl 3.2.29 */ | ||||
| #if LIBNL_CURRENT < 224 | ||||
| # define RTNL_LINK_RX_NOHANDLER		-1 | ||||
| #endif | ||||
|  | ||||
| static struct attr_map link_attrs[] = { | ||||
| { | ||||
| 	.name		= "bytes", | ||||
| @ -101,6 +106,14 @@ static struct attr_map link_attrs[] = { | ||||
| 	.rxid		= RTNL_LINK_RX_COMPRESSED, | ||||
| 	.txid		= RTNL_LINK_TX_COMPRESSED, | ||||
| }, | ||||
| { | ||||
| 	.name		= "nohandler", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "No Handler", | ||||
| 	.rxid		= RTNL_LINK_RX_NOHANDLER, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "fifoerr", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
|  | ||||
| @ -226,17 +226,19 @@ sysctl_read(void) | ||||
| 			attr_update(e, m->attrid, rx, tx, flags); | ||||
| 		} | ||||
|  | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_mtu); | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%ju", (uintmax_t)ifm->ifm_data.ifi_mtu); | ||||
| 		element_update_info(e, "MTU", info_buf); | ||||
|  | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_metric); | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%ju", (uintmax_t)ifm->ifm_data.ifi_metric); | ||||
| 		element_update_info(e, "Metric", info_buf); | ||||
|  | ||||
| #if !(defined(__NetBSD__) || defined(__FreeBSD__)) | ||||
| 		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); | ||||
| #endif | ||||
|  | ||||
| 		element_notify_update(e, NULL); | ||||
| 		element_lifesign(e, 1); | ||||
|  | ||||
| @ -101,10 +101,10 @@ 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, | ||||
| 	double rx = unit_value2str(rate_get_total(&a->a_rx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &rx_u, &rxprec); | ||||
| 	double tx = unit_value2str(a->a_tx_rate.r_total, | ||||
| 	double tx = unit_value2str(rate_get_total(&a->a_tx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &tx_u, &txprec); | ||||
|  | ||||
| @ -212,6 +212,7 @@ static void ascii_draw_group(struct element_group *g, void *arg) | ||||
| static void ascii_draw(void) | ||||
| { | ||||
| 	group_foreach(ascii_draw_group, NULL); | ||||
| 	fflush(stdout); | ||||
|  | ||||
| 	if (c_quit_after > 0) | ||||
| 		if (--c_quit_after == 0) | ||||
|  | ||||
| @ -45,6 +45,8 @@ enum { | ||||
| 	KEY_TOGGLE_DETAILS	= 'd', | ||||
| 	KEY_TOGGLE_INFO		= 'i', | ||||
| 	KEY_COLLECT_HISTORY	= 'h', | ||||
| 	KEY_CTRL_N	= 14, | ||||
| 	KEY_CTRL_P	= 16, | ||||
| }; | ||||
|  | ||||
| #define DETAILS_COLS		40 | ||||
| @ -147,22 +149,24 @@ static char *float2str(double value, int width, int prec, char *buf, size_t len) | ||||
| static void put_line(const char *fmt, ...) | ||||
| { | ||||
| 	va_list args; | ||||
| 	char buf[2048]; | ||||
| 	char *buf; | ||||
| 	int len; | ||||
| 	int x, y __unused__; | ||||
|  | ||||
| 	memset(buf, 0, sizeof(buf)); | ||||
| 	getyx(stdscr, y, x); | ||||
|  | ||||
| 	len = cols - x; | ||||
| 	buf = xcalloc(len+1, 1); | ||||
|  | ||||
| 	va_start(args, fmt); | ||||
| 	vsnprintf(buf, sizeof(buf), fmt, args); | ||||
| 	vsnprintf(buf, len+1, fmt, args); | ||||
| 	va_end(args); | ||||
|  | ||||
| 	if (strlen(buf) > cols-x) | ||||
| 		buf[cols - x] = '\0'; | ||||
| 	else | ||||
| 		memset(&buf[strlen(buf)], ' ', cols - strlen(buf)-x); | ||||
| 	if (strlen(buf) < len) | ||||
| 		memset(&buf[strlen(buf)], ' ', len - strlen(buf)); | ||||
|  | ||||
| 	addstr(buf); | ||||
| 	xfree(buf); | ||||
| } | ||||
|  | ||||
| static void center_text(const char *fmt, ...) | ||||
| @ -241,10 +245,10 @@ static void draw_attr_detail(struct element *e, struct attr *a, void *arg) | ||||
| 	int rxprec, txprec, ncol; | ||||
| 	struct detail_arg *da = arg; | ||||
|  | ||||
| 	double rx = unit_value2str(a->a_rx_rate.r_total, | ||||
| 	double rx = unit_value2str(rate_get_total(&a->a_rx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &rx_u, &rxprec); | ||||
| 	double tx = unit_value2str(a->a_tx_rate.r_total, | ||||
| 	double tx = unit_value2str(rate_get_total(&a->a_tx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &tx_u, &txprec); | ||||
|  | ||||
| @ -258,7 +262,7 @@ static void draw_attr_detail(struct element *e, struct attr *a, void *arg) | ||||
| 	if (ncol > 0) | ||||
| 		addch(ACS_VLINE); | ||||
|  | ||||
| 	put_line(" %-14.14s %8s%-3s %8s%-3s\n", | ||||
| 	put_line(" %-14.14s %8s%-3s %8s%-3s", | ||||
| 		 a->a_def->ad_description, | ||||
| 		 (a->a_flags & ATTR_RX_ENABLED) ? | ||||
| 		 float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u, | ||||
| @ -392,6 +396,7 @@ static void draw_help(void) | ||||
| 	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); | ||||
| 	mvaddnstr(y+18, x+3, "r             Reset counter of element", -1); | ||||
|  | ||||
| 	attroff(A_STANDOUT); | ||||
|  | ||||
| @ -419,6 +424,7 @@ static void draw_header(void) | ||||
| 	move(row, COLS - strlen(PACKAGE_STRING) - 1); | ||||
| 	put_line("%s", PACKAGE_STRING); | ||||
| 	move(row, 0); | ||||
| 	apply_layout(LAYOUT_LIST); | ||||
| } | ||||
|  | ||||
| static int lines_required_for_statusbar(void) | ||||
| @ -631,6 +637,7 @@ static void draw_element(struct element_group *g, struct element *e, | ||||
|  | ||||
| static void draw_group(struct element_group *g, void *arg) | ||||
| { | ||||
| 	apply_layout(LAYOUT_HEADER); | ||||
| 	int *line = arg; | ||||
|  | ||||
| 	if (line_visible(*line)) { | ||||
| @ -683,7 +690,7 @@ static void draw_graph_centered(struct graph *g, int row, int ncol, | ||||
|  | ||||
| static void draw_table(struct graph *g, struct graph_table *tbl, | ||||
| 		       struct attr *a, struct history *h, | ||||
| 		       const char *hdr, int ncol) | ||||
| 		       const char *hdr, int ncol, int layout) | ||||
| { | ||||
| 	int i, save_row; | ||||
| 	char buf[32]; | ||||
| @ -708,11 +715,14 @@ static void draw_table(struct graph *g, struct graph_table *tbl, | ||||
| 	//move(row, ncol + g->g_cfg.gc_width - 3); | ||||
| 	//put_line("[err %.2f%%]", rtiming.rt_variance.v_error); | ||||
|  | ||||
|     memset(buf, 0, strlen(buf)); | ||||
| 	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))); | ||||
|         sprintf(buf, "%'8.2f ", tbl->gt_scale[i]); | ||||
|         addstr(buf); | ||||
|         apply_layout(layout); | ||||
|         put_line("%s", tbl->gt_table + (i * graph_row_size(&g->g_cfg))); | ||||
|         apply_layout(LAYOUT_LIST); | ||||
| 	} | ||||
|  | ||||
| 	move(++row, ncol); | ||||
| @ -746,14 +756,14 @@ static void draw_history_graph(struct attr *a, struct history *h) | ||||
| 	graph_refill(g, h); | ||||
|  | ||||
| 	save_row = row; | ||||
| 	draw_table(g, &g->g_rx, a, h, "RX", ncol); | ||||
| 	draw_table(g, &g->g_rx, a, h, "RX", ncol, LAYOUT_RX_GRAPH); | ||||
|  | ||||
| 	if (graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE) { | ||||
| 		ncol = cols / 2; | ||||
| 		row = save_row; | ||||
| 	} | ||||
|  | ||||
| 	draw_table(g, &g->g_tx, a, h, "TX", ncol); | ||||
| 	draw_table(g, &g->g_tx, a, h, "TX", ncol, LAYOUT_TX_GRAPH); | ||||
|  | ||||
| 	graph_free(g); | ||||
| } | ||||
| @ -973,8 +983,10 @@ draw: | ||||
| 	 */ | ||||
| 	NEXT_ROW(); | ||||
| 	hline(ACS_HLINE, cols); | ||||
| 	mvaddch(row, LIST_COL_1, ACS_BTEE); | ||||
| 	mvaddch(row, LIST_COL_2, ACS_BTEE); | ||||
| 	if (c_show_list) { | ||||
| 		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 ", | ||||
| @ -1016,6 +1028,12 @@ draw: | ||||
| 	NEXT_ROW(); | ||||
| 	hline(ACS_HLINE, cols); | ||||
|  | ||||
| 	if (c_show_details) { | ||||
| 		int i; | ||||
| 		for (i = 1; i < detail_cols; i++) | ||||
| 			mvaddch(row, (i * DETAILS_COLS) - 1, ACS_BTEE); | ||||
| 	} | ||||
|  | ||||
| 	if (!c_show_info) | ||||
| 		center_text(" Press %c to enable additional information ", | ||||
| 			    KEY_TOGGLE_INFO); | ||||
| @ -1079,6 +1097,16 @@ out: | ||||
| 	refresh(); | ||||
| } | ||||
|  | ||||
| static void __reset_attr_counter(struct element *e, struct attr *a, void *arg) | ||||
| { | ||||
| 	attr_reset_counter(a); | ||||
| } | ||||
|  | ||||
| static void reset_counters(void) | ||||
| { | ||||
| 	element_foreach_attr(current_element, __reset_attr_counter, NULL); | ||||
| } | ||||
|  | ||||
| static int handle_input(int ch) | ||||
| { | ||||
| 	switch (ch)  | ||||
| @ -1160,10 +1188,12 @@ static int handle_input(int ch) | ||||
| 			return 1; | ||||
|  | ||||
| 		case KEY_DOWN: | ||||
| 		case KEY_CTRL_N: | ||||
| 			element_select_next(); | ||||
| 			return 1; | ||||
|  | ||||
| 		case KEY_UP: | ||||
| 		case KEY_CTRL_P: | ||||
| 			element_select_prev(); | ||||
| 			return 1; | ||||
|  | ||||
| @ -1198,6 +1228,10 @@ static int handle_input(int ch) | ||||
| 		case '\t': | ||||
| 			history_select_next(); | ||||
| 			return 1; | ||||
|  | ||||
| 		case 'r': | ||||
| 			reset_counters(); | ||||
| 			return 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| @ -1232,7 +1266,7 @@ static void print_module_help(void) | ||||
| 	"  Author: Thomas Graf <tgraf@suug.ch>\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Options:\n" \ | ||||
| 	"    fgchar=CHAR    Foreground character (default: '*')\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" \ | ||||
| @ -1242,6 +1276,7 @@ static void print_module_help(void) | ||||
| 	"    nocolors       Do not use colors\n" \ | ||||
| 	"    graph          Show graphical stats by default\n" \ | ||||
| 	"    details        Show detailed stats by default\n" \ | ||||
| 	"    info           Show additional info screen by default\n" \ | ||||
| 	"    minlist=INT    Minimum item list length\n"); | ||||
| } | ||||
|  | ||||
| @ -1264,6 +1299,8 @@ static void curses_parse_opt(const char *type, const char *value) | ||||
| 		c_show_graph = !!c_ngraph; | ||||
| 	} else if (!strcasecmp(type, "details")) | ||||
| 		c_show_details = 1; | ||||
| 	else if (!strcasecmp(type, "info")) | ||||
| 		c_show_info = 1; | ||||
| 	else if (!strcasecmp(type, "nocolors")) | ||||
| 		c_use_colors = 0; | ||||
| 	else if (!strcasecmp(type, "minlist") && value) | ||||
|  | ||||
| @ -123,17 +123,18 @@ static char *get_token(struct element_group *g, struct element *e, | ||||
| 			goto out; | ||||
|  | ||||
| 		if (!strncasecmp(type, "rx:", 3)) { | ||||
| 			snprintf(buf, len, "%" PRIu64, a->a_rx_rate.r_total); | ||||
| 			snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_rx_rate)); | ||||
| 			return buf; | ||||
| 		} else if (!strncasecmp(type, "tx:", 3)) { | ||||
| 			snprintf(buf, len, "%" PRIu64, a->a_tx_rate.r_total); | ||||
| 			snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_tx_rate)); | ||||
| 			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)) | ||||
| 		} else if (!strncasecmp(type, "txrate:", 7)) { | ||||
| 			snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate); | ||||
| 			return buf; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fprintf(stderr, "Unknown field \"%s\"\n", token); | ||||
| @ -165,6 +166,7 @@ static void draw_element(struct element_group *g, struct element *e, void *arg) | ||||
| static void format_draw(void) | ||||
| { | ||||
| 	group_foreach_recursive(draw_element, NULL); | ||||
| 	fflush(stdout); | ||||
|  | ||||
| 	if (c_quit_after > 0) | ||||
| 		if (--c_quit_after == 0) | ||||
| @ -319,15 +321,15 @@ static void print_help(void) | ||||
| 	"  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" \ | ||||
| 	"    '$(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" \ | ||||
| 	"    '$(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: $(element:name)\\nBytes Rate: $(attr:rxrate:bytes)/" \ | ||||
| 	"$(attr:txrate:bytes)\\nPackets Rate: $(attr:rxrate:packets)/" \ | ||||
| 	"$(attr:txrate:packets)\\n'\n" \ | ||||
| 	"    Item: eth0\n" \ | ||||
| 	"    Bytes Rate: 49130/2119\n" \ | ||||
| 	"    Packets Rate: 40/11\n" \ | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							| @ -27,6 +27,11 @@ | ||||
| #include <bmon/conf.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
| #ifdef __MACH__ | ||||
| #include <mach/clock.h> | ||||
| #include <mach/mach.h> | ||||
| #endif | ||||
|  | ||||
| void *xcalloc(size_t n, size_t s) | ||||
| { | ||||
| 	void *d = calloc(n, s); | ||||
| @ -112,12 +117,21 @@ int timestamp_is_negative(timestamp_t *ts) | ||||
|  | ||||
| void update_timestamp(timestamp_t *dst) | ||||
| { | ||||
| 	struct timeval tv; | ||||
| #ifdef __MACH__ | ||||
| 	clock_serv_t cclock; | ||||
| 	mach_timespec_t tp; | ||||
|  | ||||
| 	gettimeofday(&tv, NULL); | ||||
| 	host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); | ||||
| 	clock_get_time(cclock, &tp); | ||||
| 	mach_port_deallocate(mach_task_self(), cclock); | ||||
| #else | ||||
| 	struct timespec tp; | ||||
|  | ||||
| 	dst->tv_sec = tv.tv_sec; | ||||
| 	dst->tv_usec = tv.tv_usec; | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &tp); | ||||
| #endif | ||||
|  | ||||
| 	dst->tv_sec = tp.tv_sec; | ||||
| 	dst->tv_usec = tp.tv_nsec / 1000; | ||||
| } | ||||
|  | ||||
| void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	