92 Commits
test ... master

Author SHA1 Message Date
969cebd4ae Fix build in FreeBSD/DragonflyBSD 2018-11-11 21:40:17 +03:30
5677863e61 curses: Add CTRL-N/CTRL-P for next/previous element 2018-01-03 10:35:42 +01:00
ed8528cf9c curses: Fix seperator lines
when section above or below is collapsed
2018-01-03 10:35:29 +01:00
737c642819 Fix typographical errors 2018-01-03 10:35:15 +01:00
b44d0152c4 Allow numeric colors in bmonrc 2017-10-03 11:22:24 +02:00
fdd139ada2 Fix configuration syntax in examples/bmon.conf
Fixes: #53

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2017-02-10 06:14:05 -08:00
49ce252ec5 OSX: Add brew usage instructions
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2017-02-10 06:11:19 -08:00
14db0bff4c Avoid trying to include <values.h> on Android
The <values.h> header file is not present on Android, and the project
builds there without it.
2017-02-09 07:15:05 -08:00
3413751795 out_curses: use xcalloc instead of a fixed buffer
In put_line(), replace the fixed onstack buffer with a xcalloc-ed buffer.
This fixes a bmon crash with terminal size larger than 2048 bytes. The crash
be reproduced with
   $ stty cols 2100
   $ bmon ....

Signed-off-by: Nachiketa Prachanda <nchkta@gmail.com>
2017-02-02 20:56:59 +01:00
1b3f11bde3 4.0 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-12-13 11:56:40 +01:00
af8923b779 netlink: Add rx_nohandler link stat counter
Hook up the device rx nohandler stat counter available in the upcoming
libnl 3.2.29, added in libnl commit 5040fc8a4994 ("lib/route: add
rx_nohandler link stats field").

Also add a compatibility define, so older libnl version will still work
fine.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2016-12-13 11:50:49 +01:00
3e4970485d Merge pull request #51 from L00Cyph3r/patch-1
Added CentOS installation steps
2016-11-28 17:17:38 +01:00
f312679738 Added CentOS installation steps
Works on my CentOS 6.8 box
2016-11-28 16:02:11 +01:00
2efc2f4a60 Merge pull request #46 from zorun/monotonic_clock
Use a monotonic clock instead of a realtime clock
2016-11-25 15:24:20 +04:00
a3d894000b Use a monotonic clock instead of a realtime clock
Using a realtime clock is a bad idea: it is affected by any kind of time
change, which can happen when the administrator modifies the system time,
or more simply when a laptop suspends to RAM and then wakes up from sleep.

With the current approach of using a realtime clock:

- if the system time jumps forward (e.g. when resuming after a
  suspend-to-RAM), bmon would take 100% CPU and display random graph data
  extremely fast, until it "catches up" with the new time.

- if the system time jumps backwards, bmon would freeze until *time*
  "catches up" to the point it was before.  bmon then (incorrectly)
  displays a spike in the graph, because lots of packets have been
  sent/received since the last update.

Instead of using gettimeofday(), switch to clock_gettime() with
CLOCK_MONOTONIC on systems that support it.  OS X does not provide
clock_gettime(), so this commit also adds a Mach-specific implementation.

This change has been tested on Linux 4.1 with glibc and musl, and on
FreeBSD 10.0-RELEASE-p12.
2016-11-12 19:29:39 +01:00
8b2638c349 Merge pull request #49 from DoctorSher/master
Flushed stdout after every group is printed in an iteration.
2016-10-18 13:01:06 +02:00
a5301347f6 Flushed stdout after every group is printed in an iteration. This allows us to redirect ascii based output to a file. 2016-10-17 18:54:46 -05:00
29fb4317d7 Merge pull request #48 from DoctorSher/master
Added example to man page, switched format strings to single quotes.
2016-10-07 21:27:49 +02:00
32d8c76b18 Changed the long format string example to be one continuous string. While this is less pretty than it was before, it allows the user to actually paste the format string directly into their bmon command to try it out. Before this change, the way the string was formatted you could not simply paste it in and run it (whether it had single or double quotes). 2016-10-07 11:49:39 -05:00
577112870d Replaced format string double quotes with single quotes to prevent the shell from running our provided format placeholders. 2016-10-07 11:42:14 -05:00
5b938e05c7 Added a format string example to the man page. While the documentation is clear, it is nice to see an example to get started. Single quotes are used to prevent the shell from running our bmon patterns as commands, and to prevent it from doing wildcard expansion for the interface string. 2016-10-07 11:37:13 -05:00
5cd24ffd6a Merge pull request #44 from blastmaster/master
Fix issue #43
2016-08-05 02:00:36 +02:00
702df3c0a1 Fix issue #43
* Remove newline from put_line formatstring while drawing details.
2016-08-04 22:57:33 +02:00
7317715e15 Fix item selection after element subgroups have been removed
If the element currently selected is removed due to inactivity, the
selection is fixed up to the previous element in the list. This step
must be done after the entire element subgroup has been removed.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-08-02 12:05:29 +02:00
86f6da0703 Use DEFAULT_GROUP instead of hardcoded string
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-08-02 11:38:07 +02:00
723f6a5b47 dummy: Use default group as first group name
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-08-02 11:37:50 +02:00
ddcd5e7d24 Derive initial interface selection based on policy
So far, any output module with a selection capability defaulted to
the first interface in the list as first pick. This uses the policy
configuration instead and thus allows to select which interface to
display first:

Examples:
 bmon -p 'em1,*'
 bmon -p 'eth*,lo,*'

The first rule that finds a matching interface is used and will
trigger initial selection.

Note that this is *ONLY* evaluated after the first read of the
statistics so if a more preferred interface appears later, the
selection will not be changed.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-08-02 10:14:24 +02:00
df271c43a4 3.9 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-07-19 23:16:10 +02:00
8f39217bd7 Merge branch 'blastmaster-master' 2016-07-19 22:58:00 +02:00
e47a376f70 fix make distcheck error
* add layout.h in include/Makefile.am
2016-07-19 22:57:53 +02:00
828b5b5368 enabling colors for bmon
This commit enables colors in bmon. It adds configuration options to
let the user decide, which colors should be used. Therefor the graph_rx and graph_tx
layouts are introduced and applied respectively.

* Add graph_rx, graph_tx and layout_cfg fields.
* Setting default colors if colorized output is enabled.
* draw_table accept additional layout parameter and apply the given layout for
  the table graph.
* Apply layouts for rx, tx graph and header and statusbar.
* Add include/layout.h, which provides functions to parse, color and attribute
  strings and set the layout.
* Adding a default layout-config example in examples/bmon.conf.

[Edit: Based on original work by eri!, #PR23]
2016-07-19 22:57:37 +02:00
1c25eacc95 Merge pull request #39 from tklauser/gcc-6
format: Add missing braces around 'if' clause
2016-04-28 23:10:39 +02:00
f177718f24 format: Add missing braces around 'if' clause
When compiling bmon with gcc 6.1 it complains with the following
warning:

out_format.c: In function ‘get_token’:
out_format.c:134:10: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
   } else if (!strncasecmp(token+5, "txrate:", 7))
          ^~
out_format.c:136:4: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘if’
    return buf;
    ^~~~~~

Indeed, the 'return buf' should only be executed if it was snprintf()'ed
to. Otherwise "unknown" should be returned. Fix this by adding braces.
Also use the 'type' variable in strncasecmp() as in the other checks.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2016-04-28 16:11:30 +02:00
cc22e4e35d Merge pull request #38 from yamadapc/master
Add OSX install instructions
2016-04-20 09:12:35 -07:00
19c35e4990 Add OSX install instructions
I'm not sure if this is universal, but this worked for installing on El
Capitan here.
2016-04-20 10:36:06 -03:00
70e6f97b65 Merge pull request #37 from Berzerker/patch-1
Update Readme to include additional dependencies
2016-03-30 11:31:13 +02:00
a6c635dc96 Update Readme to include additional dependencies
pkg-config and dh-autoreconf are required packages for proper configuration
2016-03-29 17:28:24 -04:00
f78c0e5b98 Add 'info' option to show additional info screen by default
Suggested-by: @Berzerker
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-03-29 12:22:56 +02:00
0e08ec1b79 Merge pull request #36 from bsiegert/master
NetBSD fixes (from pkgsrc)
2016-03-28 23:47:33 +02:00
74770b8806 Use uintmax_t cast for some printfs.
Some of the BSDs have 32-bit, some 64-bit vars for this.
2016-03-26 21:42:05 +01:00
fa6abf3a80 NetBSD does not have send or receive quotas. 2016-03-26 21:40:07 +01:00
0103671f1f Check for presence of pkg-config in configure
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-01-29 18:15:47 +01:00
4efaa8ce9e curses: Add ability to reset statistics
Press 'r' in curses mode to reset a statistic counter to
start counting from 0 again. This does NOT reset the
counter from the source itself but merely emulates a
counter reset. If you restart bmon, the counter will be
back to its total value.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2016-01-29 12:11:44 +01:00
1f79ea4396 Merge pull request #32 from Chocobo1/travis
Fix TravisCI script
2016-01-25 23:40:55 +01:00
67b6ee3bd6 TravisCI: merge config for coverity scan 2016-01-26 02:29:03 +08:00
cbcdab6669 TravisCI: fix script, add OSX builds 2016-01-26 01:27:59 +08:00
8dcd666db6 travis: Switch to trusty ubuntu distro
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 15:55:20 +01:00
a0eea59519 netlink: BUG() if we don't have parent information
This would indicate that we hang a TC object to the tree root.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 15:40:58 +01:00
f9c714fa15 netlink: Use ifindex of parent TC object when searching leaf qdiscs
The qdisc cache is host wide, the parent classid is not unique
so the ifindex of the parent tc object must be set in the filter
otherwise a leaf qdisc with an identical parent id in another
device can be mistaken.

This also converts the class_cache to be passed up through the
stack to make clear it is not system wide but specific to the
ifindex we are currently handling.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 15:36:03 +01:00
892bdac762 bmon: Mark attr_def_free() and __lookup_element() static
Fixes sparse warnings:
attr.c:114:6: warning: symbol 'attr_def_free' was not declared. Should it be static?
element.c:116:16: warning: symbol '__lookup_element' was not declared. Should it be static?

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 14:10:43 +01:00
4488cd03f9 bmon: Properly pass NULL pointers instead of 0
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 14:09:35 +01:00
753a9e09dd bmon: Remove dead code and make sig_exit() static
Fixes sparse warnings:
bmon.c:36:5: warning: symbol 'do_quit' was not declared. Should it be static?
bmon.c:37:5: warning: symbol 'is_daemon' was not declared. Should it be static?
bmon.c:91:12: warning: symbol 'sig_int' was not declared. Should it be static?
bmon.c:98:6: warning: symbol 'sig_exit' was not declared. Should it be static?

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 14:04:14 +01:00
0641291ad5 curses: Pass in proper NULL pointer
Fix sparse warning:
out_curses.c:433:25: warning: Using plain integer as NULL pointer

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 14:01:51 +01:00
f666ffd0b7 curses: Make float2str static
Fix sparse message:
out_curses.c:140:6: warning: symbol 'float2str' was not declared. Should it be static?

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-12-16 14:00:39 +01:00
559e31e62f Merge pull request #30 from tklauser/ip6-link-stats
Add additional IPv6 link stats
2015-11-15 18:09:42 -08:00
9a69cb6d59 man: Fix --ouptut typo
Reported-by: xiaohuichan@gmail.com
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-08-09 18:05:56 +02:00
665c63d4e7 Add additional IPv6 link stats
Hook up additional IPv6 link statistics counters available since libnl
v3.2.25. Also add compatibility defines, so bmon can still be compiled
against older libnl versions.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2015-08-06 15:20:07 +02:00
964f48465a 3.8 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-07-25 11:10:41 +02:00
e31a860af6 Update copyright
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-07-25 11:05:01 +02:00
2027a634a7 netlink: Only disable TC stats if QoS is not available in kernel
Up to now, the entire Netlink module was disable if QoS statistics were
not available. Merely disable TC stats themselves but continue using
the input module.

Reported-by: Wen Chiu <Wen.Chiu@brocade.com>
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-07-25 10:51:47 +02:00
30946f2d78 bmon 3.7 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-06-30 12:09:54 +02:00
47547eb29f man: Also mention --use-bit option
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-06-30 12:05:53 +02:00
21ec49ed67 format: Don't print error message for unavailable attributes
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-06-30 11:59:48 +02:00
29172c819c Document -b option
Reported-by: Ross Patterson
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-06-30 11:50:40 +02:00
2ccea2c56e Merge pull request #25 from Chocobo1/bits
Fix wrong unit displayed when using "--use-bit" option
2015-05-31 18:04:27 +02:00
51a24c315b Fix wrong unit displayed when using "--use-bit" option 2015-05-31 21:27:52 +08:00
5cecc86856 Fix inconsistency in format module example 2015-05-31 18:53:35 +08:00
5e61c5c0e4 man page: add explaination of SI uints 2015-05-31 16:15:51 +08:00
4645116a57 Merge pull request #24 from tklauser/cross-compile-fix
[v2] Explicitly include linux/if.h to fix cross-compile error
2015-04-30 09:45:18 -07:00
c80554be16 Explicitly include linux/if.h to fix cross-compile error
When compiling bmon with the Linaro 2014.01 ARM toolchain
(gcc-linaro-arm-linux-gnueabihf-4.8-2014.01_linux) the following compile error occurs:

  in_netlink.c: In function ‘do_link’:
  in_netlink.c:688:53: error: ‘IFF_UP’ undeclared (first use in this function)

Fix it by explicitly including linux/if.h, where IFF_UP is defined.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
2015-04-30 12:00:35 +02:00
2a410be36f README: Mention that ./autogen.sh must be run after git clone
Reported-by: DavidRChristensen
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-04-29 17:30:22 +02:00
c1ae292c95 README: Mention ncurses-devel dependency in installation notes
Reported-by: DavidRChristensen
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2015-04-29 17:28:31 +02:00
234efb85f6 Merge pull request #20 from Chocobo1/dev
assertion failed in libConfuse
2015-04-29 08:25:47 -07:00
229d58c975 using cfg_setint is triggering an assertion in confuse library, should use cfg_setbool instead 2015-01-19 20:02:14 +08:00
8fc5a55da4 Merge pull request #19 from halid/master
Debian / Ubuntu Installation Procedures
2015-01-08 16:18:53 +01:00
3ecdad6f56 Update README.md
make and build-essential package
2015-01-08 14:14:02 +02:00
511e0196e1 Update README.md
debian installation procedures
2015-01-08 14:11:38 +02:00
0100916a95 BSD: Provide minimal interface information
Including:
 - MTU
 - Metric
 - RX/TX IRQ Quota

Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-12-16 18:31:27 +01:00
ea065c5619 Provide download link in README.md
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-11-22 13:40:10 +01:00
baabc8b729 3.6 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-11-22 13:33:24 +01:00
88548ccf96 Merge pull request #18 from gustavoz/master
build: uclinux is also linux
2014-11-13 12:13:03 +01:00
c4ed01f272 build: uclinux is also linux 2014-11-11 20:37:21 -03:00
c1d0bb41c7 Fix LICENSE links in README.md
Reported-by: Eric Leblond
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-09-05 09:39:24 +02:00
7f8d60f40f 3.5 release
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-30 13:36:46 +02:00
6920af805c travis: Run make distcheck
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-30 13:32:49 +02:00
8b4ce86cc9 Makefile: Fix README.md distribution inclusion
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-30 13:30:30 +02:00
17a4adb0f2 build: fail CI builds if a new warning is introduced
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
4492ab547c build: Enable -Wall
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
a36136ec4d Annotate unused variables
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
e3d208905d Initialize t to silence uninit warning
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
68bd14ffd1 Remove unused write_column() function
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
e2df502abc Remove unused variables
Signed-off-by: Thomas Graf <tgraf@suug.ch>
2014-08-25 01:07:19 +02:00
32 changed files with 753 additions and 190 deletions

View File

@ -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

View File

@ -6,4 +6,4 @@ if [ $CC = "clang" ]; then
FLAGS="$FLAGS -Wno-error=unused-command-line-argument"
fi
./autogen.sh && ./configure && make CFLAGS="$FLAGS"
./autogen.sh && ./configure && make CFLAGS="$FLAGS" && make distcheck

View File

@ -4,4 +4,4 @@ ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src man include examples
EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.adoc
EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.md

38
NEWS
View File

@ -1,12 +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

View File

@ -8,20 +8,74 @@ 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.
## Changes
## Download
### New in 3.4
* [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 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
make install
bmon
```
-------------
## 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
* blank screen with config file
* quick-help toggle with '?' in curses
* Better bmon.conf example
## New in 3.3
* MacOS X port
* Only initialize curses module if actually used
* Assorted bug and spelling fixes
* Various build fixes
-------------
### Usage
To run bmon in the default curses mode:
@ -35,14 +89,18 @@ provided via:
## 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)
![Screenshot 1](https://github.com/tgraf/bmon/raw/gh-pages/images/shot3.png)
![Screenshot 2](https://github.com/tgraf/bmon/raw/gh-pages/images/shot1.png)
![Screenshot 3](https://github.com/tgraf/bmon/raw/gh-pages/images/shot2.png)
## Copyright
> *Copyright (c) 2001-2014 Thomas Graf <tgraf@suug.ch>
> Copyright (c) 2013 Red Hat, Inc.*
Various authors, see git commit log.
Please see the [LICENSE](https://github.com/tgraf/bmon/blob/master/LICENSE)
file for additional details.
> *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)
and [LICENSE.MIT](https://github.com/tgraf/bmon/blob/master/LICENSE.MIT) files for
additional details.

View File

@ -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.4, [], [], [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])
@ -70,7 +78,7 @@ fi
PKG_CHECK_MODULES([CONFUSE], [libconfuse], [], AC_MSG_ERROR([requires libconfuse]))
case ${target_os} in
linux*)
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]))
;;
@ -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])
;;

View File

@ -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"}
}
}

View File

@ -16,4 +16,5 @@ noinst_HEADERS = \
bmon/module.h \
bmon/output.h \
bmon/unit.h \
bmon/layout.h \
bmon/utils.h

View File

@ -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

View File

@ -60,9 +60,11 @@ enum {
#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

View File

@ -74,6 +74,8 @@ enum {
LAYOUT_HEADER,
LAYOUT_LIST,
LAYOUT_SELECTED,
LAYOUT_RX_GRAPH,
LAYOUT_TX_GRAPH,
__LAYOUT_MAX
};

View File

@ -48,7 +48,7 @@
#include <dirent.h>
#ifdef SYS_BSD
# include <float.h>
#else
#elif !defined(__ANDROID__)
# include <values.h>
#endif

View File

@ -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
View 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_ */

View File

@ -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\-\-ouptut\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
@ -44,7 +44,7 @@ text mode. See OUTPUT MODULES for more details.
.PP
\fB \-U\fR, \fB\-\-use\-si\fR
.RS 4
Use SI unit system instead of 1KB = 1'024 bytes.
Use SI unit system (1KB = 1'000 bytes) instead of 1KB = 1'024 bytes.
.RE
.PP
\fB \-f\fR, \fB\-\-configfile=\fRFILE
@ -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
@ -75,6 +75,11 @@ 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
@ -132,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
@ -215,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

View File

@ -7,6 +7,7 @@ bmon_CFLAGS = \
-I${top_builddir}/include \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-D_GNU_SOURCE \
-Wall \
$(CURSES_CFLAGS) \
$(CONFUSE_CFLAGS) \
$(LIBNL_CFLAGS) \

View File

@ -111,7 +111,7 @@ int attr_def_add(const char *name, const char *desc, struct unit *unit,
return def->ad_id;
}
void attr_def_free(struct attr_def *def)
static void attr_def_free(struct attr_def *def)
{
if (!def)
return;
@ -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;

View File

@ -33,8 +33,6 @@
#include <bmon/group.h>
int start_time;
int do_quit = 0;
int is_daemon = 0;
struct reader_timing rtiming;
@ -69,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)
{
@ -88,14 +86,7 @@ static void do_shutdown(void)
}
}
RETSIGTYPE sig_int(int unused)
{
if (do_quit)
exit(-1);
do_quit = 1;
}
void sig_exit(void)
static void sig_exit(void)
{
do_shutdown();
}
@ -120,7 +111,7 @@ void quit(const char *fmt, ...)
static inline void print_version(void)
{
printf("bmon %s\n", PACKAGE_VERSION);
printf("Copyright (C) 2001-2013 by Thomas Graf <tgraf@suug.ch>\n");
printf("Copyright (C) 2001-2015 by Thomas Graf <tgraf@suug.ch>\n");
printf("Copyright (C) 2013 Red Hat, Inc.\n");
printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \
"software, and you\nare welcome to redistribute it under " \
@ -136,10 +127,10 @@ static void parse_args_pre(int argc, char *argv[])
char *gostr = "+:hvVf:";
struct option long_opts[] = {
{"help", 0, 0, 'h'},
{"version", 0, 0, 'v'},
{"configfile", 1, 0, 'f'},
{0, 0, 0, 0},
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'v'},
{"configfile", 1, NULL, 'f'},
{NULL, 0, NULL, 0},
};
int c = getopt_long(argc, argv, gostr, long_opts, NULL);
if (c == -1)
@ -175,17 +166,17 @@ static int parse_args_post(int argc, char *argv[])
"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},
{"input", 1, NULL, 'i'},
{"output", 1, NULL, 'o'},
{"policy", 1, NULL, 'p'},
{"read-interval", 1, NULL, 'r'},
{"rate-interval", 1, NULL, 'R'},
{"sleep-interval", 1, NULL, 's'},
{"show-all", 0, NULL, 'a'},
{"use-si", 0, NULL, 'U'},
{"use-bit", 0, NULL, 'b'},
{"lifetime", 1, NULL, 'L'},
{NULL, 0, NULL, 0},
};
int c = getopt_long(argc, argv, gostr, long_opts, NULL);
if (c == -1)
@ -220,7 +211,7 @@ static int parse_args_post(int argc, char *argv[])
break;
case 'a':
cfg_setint(cfg, "show_all", 1);
cfg_setbool(cfg, "show_all", cfg_true);
break;
case 'U':
@ -269,9 +260,8 @@ int main(int argc, char *argv[])
{
unsigned long sleep_time;
double read_interval;
int unused;
start_time = time(0);
start_time = time(NULL);
memset(&rtiming, 0, sizeof(rtiming));
rtiming.rt_variance.v_min = FLT_MAX;
@ -362,9 +352,6 @@ int main(int argc, char *argv[])
output_post();
}
if (do_quit)
exit(0);
/*
* ST := Configured ST
*/
@ -400,5 +387,4 @@ int main(int argc, char *argv[])
static void __init bmon_init(void)
{
atexit(&sig_exit);
//signal(SIGINT, &sig_int);
}

View File

@ -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
@ -371,7 +387,7 @@ static void configfile_read_units(void)
static void configfile_read_attrs(void)
{
int i, nattrs, t;
int i, nattrs, t = 0;
nattrs = cfg_size(cfg, "attr");
@ -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)

View File

@ -113,8 +113,9 @@ void element_parse_policy(const char *policy)
xfree(copy);
}
struct element *__lookup_element(struct element_group *group, const char *name,
uint32_t id, struct element *parent)
static struct element *__lookup_element(struct element_group *group,
const char *name, uint32_t id,
struct element *parent)
{
struct list_head *list;
struct element *e;
@ -200,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);
@ -220,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--;
@ -357,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;
@ -364,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;
}

View File

@ -58,26 +58,6 @@ static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol
return at_col(at_row(cfg, tbl, nrow), ncol);
}
static void write_column(struct graph_cfg *cfg, struct graph_table *tbl, int ncol,
uint64_t value, double *scale, double half_step)
{
char *col = at_col(tbl->gt_table, ncol);
int i;
#if 0
if (value == UNK_DATA) {
for (i = 0; i < height; i++)
*(at_row(g, col, i)) = unk_char;
#endif
if (value) {
*(at_row(cfg, col, 0)) = ':';
for (i = 0; i < cfg->gc_height; i++)
if (value >= (scale[i] - half_step))
*(at_row(cfg, col, i)) = cfg->gc_foreground;
}
}
static void fill_table(struct graph *g, struct graph_table *tbl,
struct history *h, struct history_store *data)
{

View File

@ -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");
}

View File

@ -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++) {
@ -185,7 +189,7 @@ static void dummy_parse_opt(const char *type, const char *value)
c_numdev = strtol(value, NULL, 0);
else if (!strcasecmp(type, "randomize")) {
c_randomize = 1;
srand(time(0));
srand(time(NULL));
} else if (!strcasecmp(type, "seed") && value)
srand(strtol(value, NULL, 0));
else if (!strcasecmp(type, "mtu") && value)

View File

@ -37,6 +37,8 @@ static int c_notc = 0;
static struct element_group *grp;
static struct bmon_module netlink_ops;
#include <linux/if.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
@ -47,6 +49,22 @@ static struct bmon_module netlink_ops;
#include <netlink/route/classifier.h>
#include <netlink/route/qdisc/htb.h>
/* These counters are not available prior to libnl 3.2.25. Set them to -1 so
* rtnl_link_get_stat() won't be called for them. */
#if LIBNL_CURRENT < 220
# define RTNL_LINK_ICMP6_CSUMERRORS -1
# define RTNL_LINK_IP6_CSUMERRORS -1
# define RTNL_LINK_IP6_NOECTPKTS -1
# define RTNL_LINK_IP6_ECT1PKTS -1
# define RTNL_LINK_IP6_ECT0PKTS -1
# 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",
@ -88,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,
@ -280,6 +306,14 @@ static struct attr_map link_attrs[] = {
.rxid = RTNL_LINK_ICMP6_INERRORS,
.txid = RTNL_LINK_ICMP6_OUTERRORS,
},
{
.name = "icmp6csumerr",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "ICMPv6 Checksum Errors",
.rxid = RTNL_LINK_ICMP6_CSUMERRORS,
.txid = -1,
},
{
.name = "ip6inhdrerr",
.type = ATTR_TYPE_COUNTER,
@ -320,6 +354,14 @@ static struct attr_map link_attrs[] = {
.rxid = RTNL_LINK_IP6_INADDRERRORS,
.txid = -1,
},
{
.name = "ip6csumerr",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "Ip6 Checksum Error",
.rxid = RTNL_LINK_IP6_CSUMERRORS,
.txid = -1,
},
{
.name = "ip6reasmtimeo",
.type = ATTR_TYPE_COUNTER,
@ -351,6 +393,38 @@ static struct attr_map link_attrs[] = {
.description = "Ip6 Reasm/Frag Requests",
.rxid = RTNL_LINK_IP6_REASMREQDS,
.txid = RTNL_LINK_IP6_FRAGCREATES,
},
{
.name = "ip6noectpkts",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "Ip6 Non-ECT Packets",
.rxid = RTNL_LINK_IP6_NOECTPKTS,
.txid = -1,
},
{
.name = "ip6ect1pkts",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "Ip6 ECT(1) Packets",
.rxid = RTNL_LINK_IP6_ECT1PKTS,
.txid = -1,
},
{
.name = "ip6ect0pkts",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "Ip6 ECT(0) Packets",
.rxid = RTNL_LINK_IP6_ECT0PKTS,
.txid = -1,
},
{
.name = "ip6cepkts",
.type = ATTR_TYPE_COUNTER,
.unit = UNIT_NUMBER,
.description = "Ip6 CE Packets",
.rxid = RTNL_LINK_IP6_CEPKTS,
.txid = -1,
}
};
@ -430,12 +504,13 @@ static struct attr_map tc_attrs[] = {
};
struct rdata {
struct nl_cache * class_cache;
struct element * parent;
int level;
};
static struct nl_sock *sock;
static struct nl_cache *link_cache, *qdisc_cache, *class_cache;
static struct nl_cache *link_cache, *qdisc_cache;
static void update_tc_attrs(struct element *e, struct rtnl_tc *tc)
{
@ -470,10 +545,10 @@ static void update_tc_infos(struct element *e, struct rtnl_tc *tc)
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 void find_qdiscs(int, uint32_t, struct rdata *);
static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
struct rdata *rdata)
const struct rdata *rdata)
{
char buf[IFNAME_MAX], name[IFNAME_MAX];
uint32_t id = rtnl_tc_get_handle(tc);
@ -483,11 +558,14 @@ static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix,
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)))
if (!rdata || !rdata->parent)
BUG();
if (!(e = element_lookup(grp, name, id, rdata->parent, ELEMENT_CREAT)))
return NULL;
if (e->e_flags & ELEMENT_FLAG_CREATED) {
e->e_level = rdata ? rdata->level : 0;
e->e_level = rdata->level;
if (element_set_key_attr(e, "tc_bytes", "tc_packets") ||
element_set_usage_attr(e, "tc_bytes"))
@ -518,8 +596,9 @@ 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;
const struct rdata *rdata = arg;
struct rdata ndata = {
.class_cache = rdata->class_cache,
.level = rdata->level + 1,
};
@ -532,10 +611,10 @@ static void handle_class(struct nl_object *obj, void *arg)
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);
find_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata);
}
static void find_qdiscs(uint32_t parent, struct rdata *rdata)
static void find_qdiscs(int ifindex, uint32_t parent, struct rdata *rdata)
{
struct rtnl_qdisc *filter;
@ -543,6 +622,7 @@ static void find_qdiscs(uint32_t parent, struct rdata *rdata)
return;
rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex);
nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter),
handle_qdisc, rdata);
@ -571,7 +651,7 @@ static void find_classes(uint32_t parent, struct rdata *rdata)
rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
nl_cache_foreach_filter(class_cache, OBJ_CAST(filter),
nl_cache_foreach_filter(rdata->class_cache, OBJ_CAST(filter),
handle_class, rdata);
rtnl_class_put(filter);
@ -581,8 +661,9 @@ 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;
const struct rdata *rdata = arg;
struct rdata ndata = {
.class_cache = rdata->class_cache,
.level = rdata->level + 1,
};
@ -604,6 +685,7 @@ static void handle_qdisc(struct nl_object *obj, void *arg)
static void handle_tc(struct element *e, struct rtnl_link *link)
{
struct rtnl_qdisc *qdisc;
struct nl_cache *class_cache;
int ifindex = rtnl_link_get_ifindex(link);
struct rdata rdata = {
.level = 1,
@ -613,6 +695,8 @@ static void handle_tc(struct element *e, struct rtnl_link *link)
if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
return;
rdata.class_cache = class_cache;
qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
if (qdisc) {
handle_qdisc(OBJ_CAST(qdisc), &rdata);
@ -736,7 +820,7 @@ static void do_link(struct nl_object *obj, void *arg)
attr_update(e, m->attrid, c_rx, c_tx, flags);
}
if (!c_notc)
if (!c_notc && qdisc_cache)
handle_tc(e, link);
element_notify_update(e, NULL);
@ -752,7 +836,8 @@ static void netlink_read(void)
goto disable;
}
if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) {
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;
}
@ -772,9 +857,20 @@ static void netlink_shutdown(void)
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, i;
int err;
if (!(sock = nl_socket_alloc())) {
fprintf(stderr, "Unable to allocate netlink socket\n");
@ -792,10 +888,13 @@ static int netlink_do_init(void)
}
if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) {
fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err));
goto disable;
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();
@ -817,17 +916,17 @@ static int netlink_probe(void)
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;
}

View File

@ -101,7 +101,7 @@ static void proc_read(void)
{
struct element *e;
FILE *fd;
char buf[512], *p, *s, *unused;
char buf[512], *p, *s, *unused __unused__;
int w;
if (!(fd = fopen(c_path, "r")))

View File

@ -163,6 +163,7 @@ sysctl_read(void)
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)
@ -225,6 +226,20 @@ sysctl_read(void)
attr_update(e, m->attrid, rx, tx, flags);
}
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), "%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);
}

View File

@ -130,7 +130,6 @@ static void __auto_load(struct bmon_module *m)
int module_set(struct bmon_subsys *ss, const char *name)
{
struct bmon_module *mod;
struct list_head *list;
LIST_HEAD(tmp_list);
module_conf_t *m;

View File

@ -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)

View File

@ -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
@ -137,7 +139,7 @@ static void apply_layout(int layout)
attrset(cfg_layout[layout].l_attr);
}
char *float2str(double value, int width, int prec, char *buf, size_t len)
static char *float2str(double value, int width, int prec, char *buf, size_t len)
{
snprintf(buf, len, "%'*.*f", width, value == 0.0f ? 0 : prec, value);
@ -147,22 +149,24 @@ 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];
int x, y;
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)
@ -430,7 +436,7 @@ static void draw_statusbar(void)
{
static const char *help_text = "Press ? for help";
char s[27];
time_t t = time(0);
time_t t = time(NULL);
apply_layout(LAYOUT_STATUSBAR);
@ -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)

View File

@ -119,24 +119,22 @@ static char *get_token(struct element_group *g, struct element *e,
goto out;
}
if (!(a = attr_lookup(e, def->ad_id))) {
fprintf(stderr, "Unable to find attribute %u (%s)\n",
def->ad_id, name);
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);
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);
@ -168,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)
@ -189,8 +188,8 @@ static inline void add_token(int type, char *data)
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++;
@ -250,7 +249,7 @@ static int format_probe(void)
}
goto out;
finish_escape:
*p = '\0';
add_token(OT_STRING, s);
@ -259,7 +258,7 @@ finish_escape:
continue;
}
out:
out:
if (new_one) {
add_token(OT_STRING, p);
new_one = 0;
@ -322,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" \
" \"Element: $(element:name)\\nBytes Rate: \" \\\n" \
" \"$(attr:rxrate:bytes)/$(attr:txrate:bytes)\\nPackets Rate: \" \\\n" \
" \"$(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" \

View File

@ -28,7 +28,7 @@
#include <bmon/utils.h>
#include <bmon/unit.h>
static struct unit *byte_unit, *bit_unit, *number_unit;
static struct unit *byte_unit, *bit_unit;
static LIST_HEAD(units);

View File

@ -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)