pax_global_header00006660000000000000000000000064152522774710014526gustar00rootroot0000000000000052 comment=f713731c1a5df48a64cfb361ad6ed5fd059c0a54 bmon-5.0/000077500000000000000000000000001525227747100123255ustar00rootroot00000000000000bmon-5.0/.github/000077500000000000000000000000001525227747100136655ustar00rootroot00000000000000bmon-5.0/.github/workflows/000077500000000000000000000000001525227747100157225ustar00rootroot00000000000000bmon-5.0/.github/workflows/build.yml000066400000000000000000000160331525227747100175470ustar00rootroot00000000000000name: Build # Controls when the action will run. on: push: branches: - master - ci - ci-werror paths-ignore: - 'README.md' - 'NEWS' - 'ChangeLog' - '**/*.md' - 'LICENSE.*' pull_request: branches: - master - ci - ci-werror paths-ignore: - 'README.md' - 'NEWS' - 'ChangeLog' - '**/*.md' - 'LICENSE.*' # Allow running this workflow manually from the Actions tab. workflow_dispatch: concurrency: group: build-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Quiets Node 20 deprecation annotations for actions/* until they ship Node 24 builds. env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: Linux: runs-on: ubuntu-latest name: ${{ matrix.cfg.name }} container: ${{ matrix.cfg.os }} timeout-minutes: 30 strategy: fail-fast: false matrix: cfg: - { os: 'ubuntu:22.04', name: 'Ubuntu 22.04' } - { os: 'ubuntu:24.04', name: 'Ubuntu 24.04' } - { os: 'ubuntu:26.04', name: 'Ubuntu 26.04' } - { os: 'debian:12', name: 'Debian 12' } - { os: 'debian:13', name: 'Debian 13' } - { os: 'fedora:44', name: 'Fedora 44' } - { os: 'rockylinux:8', name: 'Rocky Linux 8' } - { os: 'rockylinux:9', name: 'Rocky Linux 9' } - { os: 'rockylinux/rockylinux:10', name: 'Rocky Linux 10' } - { os: 'alpine:latest', name: 'Alpine x86_64' } steps: - name: Install git for checkout run: | case "${{ matrix.cfg.os }}" in ubuntu*|debian*) apt-get update -q -y DEBIAN_FRONTEND=noninteractive apt-get install -q -y git ca-certificates ;; rocky*|fedora*) dnf -y install git ;; alpine*) apk update apk add git ;; esac - name: Checkout uses: actions/checkout@v6 - name: Install dependencies run: | case "${{ matrix.cfg.os }}" in ubuntu*|debian*) apt-get update -q -y DEBIAN_FRONTEND=noninteractive apt-get install -q -y \ build-essential autoconf automake libtool pkg-config \ libconfuse-dev libncurses-dev \ libnl-3-dev libnl-route-3-dev ;; fedora*) dnf -y install \ gcc make autoconf automake libtool pkgconf \ libconfuse-devel ncurses-devel libnl3-devel ;; rocky*) dnf -y install epel-release dnf-plugins-core dnf config-manager --set-enabled powertools \ || dnf config-manager --set-enabled crb dnf -y install \ gcc make autoconf automake libtool pkgconf \ libconfuse-devel ncurses-devel libnl3-devel ;; alpine*) apk add \ build-base autoconf automake libtool pkgconf \ linux-headers confuse-dev ncurses-dev libnl3-dev ;; esac - name: Configure run: | ./autogen.sh ./configure --enable-werror - name: Make id: build run: make -j$(nproc) - name: Install run: make install - name: Smoke test run: ./src/bmon -o 'ascii:quitafter=1' - name: Distcheck if: contains(matrix.cfg.os, 'ubuntu:24.04') run: make distcheck DISTCHECK_CONFIGURE_FLAGS=--enable-werror macOS: runs-on: ${{ matrix.cfg.os }} name: ${{ matrix.cfg.name }} timeout-minutes: 30 strategy: fail-fast: false matrix: cfg: - { os: macos-15-intel, name: 'macOS intel' } - { os: macos-latest, name: 'macOS arm' } steps: - name: Checkout uses: actions/checkout@v6 - name: Install dependencies run: | brew install autoconf automake libtool pkg-config confuse - name: Configure run: | eval "$(brew shellenv)" export PATH="$(brew --prefix)/opt/gettext/bin:$PATH" export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:${PKG_CONFIG_PATH:-}" ./autogen.sh ./configure --enable-werror \ CPPFLAGS="-I$(brew --prefix)/include" \ LDFLAGS="-L$(brew --prefix)/lib" - name: Make id: build run: make -j$(sysctl -n hw.ncpu) - name: Install run: sudo make install - name: Smoke test run: ./src/bmon -o 'ascii:quitafter=1' Alpine: runs-on: ubuntu-latest name: Alpine ${{ matrix.platform.arch }} timeout-minutes: 60 strategy: fail-fast: false matrix: platform: - { arch: riscv64 } # emulated - { arch: x86 } steps: - name: Install binfmt support run: | sudo apt-get update -q -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -q -y binfmt-support - name: Setup Alpine uses: jirutka/setup-alpine@ae3b3ddba35054804fc4a3507b519fa7e8152050 with: arch: ${{ matrix.platform.arch }} branch: v3.20 packages: > build-base autoconf automake libtool pkgconf linux-headers confuse-dev ncurses-dev libnl3-dev - name: Checkout uses: actions/checkout@v6 - name: Configure shell: alpine.sh {0} run: | ./autogen.sh ./configure --enable-werror - name: Make id: build shell: alpine.sh {0} run: make -j$(nproc) - name: Smoke test shell: alpine.sh {0} run: ./src/bmon -o 'ascii:quitafter=1' FreeBSD: runs-on: ubuntu-latest name: FreeBSD timeout-minutes: 45 steps: - uses: actions/checkout@v6 - name: Build on FreeBSD id: build uses: vmactions/freebsd-vm@v1 with: usesh: true prepare: | pkg install -y autoconf automake libtool pkgconf libconfuse gmake git run: | set -e cd "$GITHUB_WORKSPACE" git config --global --add safe.directory "$GITHUB_WORKSPACE" ./autogen.sh ./configure --enable-werror gmake -j"$(sysctl -n hw.ncpu)" ./src/bmon -o 'ascii:quitafter=1' Clang: runs-on: ubuntu-latest name: Clang timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@v6 - name: Install dependencies run: | sudo apt-get update -q -y sudo DEBIAN_FRONTEND=noninteractive apt-get install -q -y \ build-essential clang autoconf automake libtool pkg-config \ libconfuse-dev libncurses-dev \ libnl-3-dev libnl-route-3-dev - name: Configure run: | ./autogen.sh ./configure --enable-werror CC=clang - name: Make id: build run: make -j$(nproc) - name: Smoke test run: ./src/bmon -o 'ascii:quitafter=1' bmon-5.0/.gitignore000066400000000000000000000001741525227747100143170ustar00rootroot00000000000000*.o *.a *.so *.so.* *.swp .deps Makefile.in Makefile /autom4te.cache /cscope.* /build-aux/ /aclocal.m4 /configure /config.* bmon-5.0/.travis.yml000066400000000000000000000015541525227747100144430ustar00rootroot00000000000000language: c os: - linux - osx env: global: - secure: "C87Pgf5AVDoyQfm9MIv81g" compiler: - gcc - clang # 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 bmon-5.0/.travis/000077500000000000000000000000001525227747100137135ustar00rootroot00000000000000bmon-5.0/.travis/run.sh000077500000000000000000000002731525227747100150600ustar00rootroot00000000000000#!/bin/bash FLAGS="-Werror" if [ $CC = "clang" ]; then FLAGS="$FLAGS -Wno-error=unused-command-line-argument" fi ./autogen.sh && ./configure && make CFLAGS="$FLAGS" && make distcheck bmon-5.0/ChangeLog000066400000000000000000000000001525227747100140650ustar00rootroot00000000000000bmon-5.0/LICENSE.BSD000066400000000000000000000022501525227747100137400ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bmon-5.0/LICENSE.MIT000066400000000000000000000017771525227747100137760ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bmon-5.0/Makefile.am000066400000000000000000000002171525227747100143610ustar00rootroot00000000000000# -*- Makefile -*- ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src man include examples EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.md bmon-5.0/NEWS000066400000000000000000000052171525227747100130310ustar00rootroot00000000000000HEAD v5.0 - September 15, 2026 * out_curses: use xcalloc instead of a fixed buffer by @NachiP in #54 * Avoid trying to include on Android by @fornwall in #55 * Allow numeric colors in bmonrc by @afh in #62 * Fix typographical errors by @afh in #63 * curses: Fix seperator lines by @afh in #64 * curses: Add CTRL-N/CTRL-P for next/previous element by @afh in #65 * Add package installation instructions for Fedora/CentOS by @carlwgeorge in #78 * Fix build in FreeBSD/DragonflyBSD by @farrokhi in #76 * Update to autoconf of the common era by @Jafaral in #116 * fix segfault on element removal by @dcaratti in #102 * ci: add GitHub Actions builds for Linux, macOS, and FreeBSD by @Jafaral in #118 * ci: enable -Werror for compiler warnings by @Jafaral in #119 * feat: Add IPv4/IPv6 addresses to additional info by @csiltala in #117 * feat: Add configure option to disable IPv6 in netlink module by @csiltala in #121 * fix: Fix memory leaks in module_set() by @csiltala in #122 * fix: Convert usage of strdup/free to xstrdup/xfree by @csiltala in #124 * feat: Add ability to toggle TC elements by @csiltala in #120 * curses: render graphs with Braille cells by @crgr in #114 * display filters for TC ingress and egress by @dcaratti in #100 * Fix compile issue in OpenBSD by @FlyingHacker in #92 * Fix spelling and grammar in docs and comments by @Jafaral in #125 * Add support for JSON output by @Jafaral in #126 * Remove the 'Really quit' dialog and just exit cleanly by @graysky2 in #113 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 * Various build fixes bmon-5.0/README.md000066400000000000000000000076751525227747100136230ustar00rootroot00000000000000# bmon - Bandwidth Monitor [![Build](https://github.com/Jafaral/bmon/actions/workflows/build.yml/badge.svg)](https://github.com/Jafaral/bmon/actions/workflows/build.yml) [![Coverity Status](https://scan.coverity.com/projects/2864/badge.svg)](https://scan.coverity.com/projects/2864) bmon is a monitoring and debugging tool to capture networking related statistics and prepare them visually in a human friendly way. It features various output methods including an interactive curses user interface and a programmable text output for scripting. ## Download * [Latest Release](https://github.com/Jafaral/bmon/releases/latest) * [Older Releases](https://github.com/Jafaral/bmon/releases) ## Debian/Ubuntu Installation ``` git clone https://github.com/Jafaral/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/Jafaral/bmon.git cd bmon yum install make libconfuse-devel libnl3-devel libnl-route3-devel ncurses-devel ./autogen.sh ./configure make make install bmon ``` ## CentOS 7 Installation ``` yum install bmon ``` ## Fedora Installation ``` dnf 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/Jafaral/bmon.git cd bmon ./autogen.sh ./configure make make install bmon ``` ------------- ## New in 5.0 * out_curses: use xcalloc instead of a fixed buffer by @NachiP in #54 * Avoid trying to include on Android by @fornwall in #55 * Allow numeric colors in bmonrc by @afh in #62 * Fix typographical errors by @afh in #63 * curses: Fix seperator lines by @afh in #64 * curses: Add CTRL-N/CTRL-P for next/previous element by @afh in #65 * Add package installation instructions for Fedora/CentOS by @carlwgeorge in #78 * Fix build in FreeBSD/DragonflyBSD by @farrokhi in #76 * Update to autoconf of the common era by @Jafaral in #116 * fix segfault on element removal by @dcaratti in #102 * ci: add GitHub Actions builds for Linux, macOS, and FreeBSD by @Jafaral in #118 * ci: enable -Werror for compiler warnings by @Jafaral in #119 * feat: Add IPv4/IPv6 addresses to additional info by @csiltala in #117 * feat: Add configure option to disable IPv6 in netlink module by @csiltala in #121 * fix: Fix memory leaks in module_set() by @csiltala in #122 * fix: Convert usage of strdup/free to xstrdup/xfree by @csiltala in #124 * feat: Add ability to toggle TC elements by @csiltala in #120 * curses: render graphs with Braille cells by @crgr in #114 * display filters for TC ingress and egress by @dcaratti in #100 * Fix compile issue in OpenBSD by @FlyingHacker in #92 * Fix spelling and grammar in docs and comments by @Jafaral in #125 * Add support for JSON output by @Jafaral in #126 * Remove the 'Really quit' dialog and just exit cleanly by @graysky2 in #113 ------------- ### Usage To run bmon in the default curses mode: > bmon There are many other options available and full help is provided via: > bmon --help ## Screenshots ![Screenshot 1](https://github.com/Jafaral/bmon/raw/gh-pages/images/shot3.png) ![Screenshot 2](https://github.com/Jafaral/bmon/raw/gh-pages/images/shot1.png) ![Screenshot 3](https://github.com/Jafaral/bmon/raw/gh-pages/images/shot2.png) ## Copyright Various authors, see git commit log. > *Copyright (c) 2001-2016 Thomas Graf * > > *Copyright (c) 2013 Red Hat, Inc.* > > *Copyright (c) 2026 Architecture Technology Corporation* Please see the [LICENSE.BSD](https://github.com/Jafaral/bmon/blob/master/LICENSE.BSD) and [LICENSE.MIT](https://github.com/Jafaral/bmon/blob/master/LICENSE.MIT) files for additional details. bmon-5.0/autogen.sh000077500000000000000000000000601525227747100143220ustar00rootroot00000000000000#!/bin/sh autoreconf -fi rm -Rf autom4te.cache bmon-5.0/configure.ac000066400000000000000000000147431525227747100146240ustar00rootroot00000000000000# # configure.ac Configure Script # # Copyright (c) 2001-2016 Thomas Graf # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. AC_INIT([bmon], [5.0], [], [], [https://github.com/Jafaral/bmon]) AC_CONFIG_HEADERS([include/bmon/defs.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)], []) AC_PROG_CC AC_PROG_CPP AC_PROG_MAKE_SET AC_PROG_INSTALL AC_C_CONST AC_C_INLINE AC_CHECK_HEADERS([sys/time.h]) AC_HEADER_DIRENT AC_TYPE_SIZE_T AC_TYPE_PID_T AC_DEFINE([RETSIGTYPE], [void], [Define as the return type of signal handlers (void).]) AC_FUNC_FORK AC_CHECK_HEADERS(getopt.h ncurses/ncurses.h ncurses.h curses.h) AC_CHECK_HEADERS(dirent.h sys/utsname.h sys/sockio.h netinet6/in6.h) AC_CHECK_HEADERS(fcntl.h netdb.h netinet/in.h sysctl/ioctl.h) AC_CHECK_HEADERS(sys/param.h sys/socket.h) AC_CHECK_TYPES(suseconds_t) AC_CHECK_FUNCS(atexit 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]) fi PKG_CHECK_MODULES([CONFUSE], [libconfuse], [], AC_MSG_ERROR([requires libconfuse])) case ${target_os} in linux*|uclinux*) PKG_CHECK_MODULES([LIBNL], [libnl-3.0], [], AC_MSG_ERROR([requires libnl3-dev])) PKG_CHECK_MODULES([LIBNL_ROUTE], [libnl-route-3.0], [], AC_MSG_ERROR([requires libnl3-route])) ;; esac AC_CHECK_LIB(m, pow, [], AC_MSG_ERROR([requires libm])) # Don't fail if not found (for instance, OS X does not have clock_gettime) AC_CHECK_LIB(rt, clock_gettime, [], []) BMON_LIB="" ##################################################################### ## ## libcurses check ## ##################################################################### CURSES="No " AC_CHECK_LIB(ncurses, initscr, [ AC_DEFINE_UNQUOTED(HAVE_NCURSES, "1", [have ncurses]) LCURSES="ncurses" CURSES="Yes" ],[ AC_CHECK_LIB(curses,initscr, [ AC_DEFINE_UNQUOTED(HAVE_CURSES, "1", [have curses]) LCURSES="curses" CURSES="Yes" ],[ echo echo "*** Warning: Building bmon w/o curses support ***" echo ]) ]) LIBCURSES="-l$LCURSES" AC_CHECK_LIB($LCURSES, redrawwin, [ AC_DEFINE_UNQUOTED(HAVE_REDRAWWIN, "1", [have redrawwin]) ]) AC_CHECK_LIB($LCURSES, use_default_colors, [ AC_DEFINE_UNQUOTED(HAVE_USE_DEFAULT_COLORS, "1", [have udc]) ]) ##################################################################### ## ## interface counter overflow workaround ## ##################################################################### AC_ARG_ENABLE(cnt-workaround, [ --disable-cnt-workaround Disables interface counter overflow workaround],[ if test x$enableval = xno; then AC_DEFINE_UNQUOTED(DISABLE_OVERFLOW_WORKAROUND,"1",[no overflow workaround]) fi ]) ##################################################################### ## ## curses ## ##################################################################### AC_ARG_ENABLE(curses, [ --disable-curses Disables curses output],[ if test x$enableval = xno; then CURSES="No " fi ]) ##################################################################### ## ## IPv6 check ## ##################################################################### AC_ARG_ENABLE(netlink-ipv6, [ --disable-netlink-ipv6 Disable IPv6 elements (default enabled)],[ if test x$enableval = xno; then AC_DEFINE_UNQUOTED(NETLINK_IPV6_DISABLED, "1", [disable IPv6]) fi ]) ##################################################################### ## ## debug check ## ##################################################################### DEBUG=0 AC_ARG_ENABLE(debug, [ --enable-debug Enable debug mode (default disabled)],[ if test x$enableval = xyes; then AC_DEFINE_UNQUOTED(DEBUG, "1", [enable debugging]) DEBUG=1; fi ]) ##################################################################### ## ## -Werror ## ##################################################################### AC_ARG_ENABLE([werror], [AS_HELP_STRING([--enable-werror], [treat compiler warnings as errors (default: disabled)])], [], [enable_werror=no]) AS_IF([test "x$enable_werror" = "xyes"], [WERROR="-Werror"], [WERROR=""]) ##################################################################### ## ## target os eval ## ##################################################################### case ${target_os} in linux*) AC_DEFINE_UNQUOTED(SYS_LINUX, "1", [operating system]) ;; *solaris*) AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system]) ;; *bsd*|dragonfly*) AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) ;; *darwin*) AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) ;; *) AC_DEFINE_UNQUOTED(SYS_OTHER, "1", [operating system]) ;; esac ##################################################################### ## ## export variables ## ##################################################################### AC_SUBST(DEBUG) AC_SUBST(STATIC) AC_SUBST(SYS) AC_SUBST(ARCH) AC_SUBST(WERROR) AC_SUBST(CURSES) AC_CONFIG_FILES([ Makefile include/Makefile src/Makefile man/Makefile examples/Makefile ]) AC_OUTPUT bmon-5.0/examples/000077500000000000000000000000001525227747100141435ustar00rootroot00000000000000bmon-5.0/examples/Makefile.am000066400000000000000000000001761525227747100162030ustar00rootroot00000000000000# -*- Makefile -*- exampledir = $(datarootdir)/doc/@PACKAGE@/examples example_DATA = bmon.conf EXTRA_DIST = $(example_DATA) bmon-5.0/examples/bmon.conf000066400000000000000000000037471525227747100157600ustar00rootroot00000000000000/* * read_interval = 1.0 * rate_interval = 1.0 * variance = 0.1 * history_variance = 0.1 * sleep_time = 20000 * lifetime = 30.0 * show_all = true * policy = "" */ /* * element eth0 { * description = "My description" * rxmax = 10000 * txmax = 10000 * max = 12500000 * } */ /* * Default configuration * * The following definitions is what is compiled into bmon and used * by default. */ unit byte { variant default { div = { 1, 1024, 1048576, 1073741824, 1099511627776} txt = { "B", "KiB", "MiB", "GiB", "TiB" } } variant si { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "B", "KB", "MB", "GB", "TB" } } variant bit { div = { 0.125, 125, 125000, 125000000, 125000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } } unit bit { variant default { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } variant si { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } variant bit { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "b", "Kb", "Mb", "Gb", "Tb" } } } unit number { variant default { div = { 1, 1000, 1000000, 1000000000, 1000000000000 } txt = { "", "K", "M", "G", "T" } } } unit percent { variant default { div = 1. txt = "%" } } history second { interval = 1. size = 60 } history minute { interval = 60. size = 60 } history hour { interval = 3600. size = 60 } history day { interval = 86400. size = 60 } 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"} } } bmon-5.0/include/000077500000000000000000000000001525227747100137505ustar00rootroot00000000000000bmon-5.0/include/Makefile.am000066400000000000000000000005201525227747100160010ustar00rootroot00000000000000noinst_HEADERS = \ bmon/attr.h \ bmon/bmon.h \ bmon/compile-fixes.h \ bmon/conf.h \ bmon/config.h \ bmon/defs.h \ bmon/element_cfg.h \ bmon/element.h \ bmon/graph.h \ bmon/group.h \ bmon/history.h \ bmon/info.h \ bmon/input.h \ bmon/list.h \ bmon/module.h \ bmon/output.h \ bmon/unit.h \ bmon/layout.h \ bmon/utils.h bmon-5.0/include/bmon/000077500000000000000000000000001525227747100147035ustar00rootroot00000000000000bmon-5.0/include/bmon/.gitignore000066400000000000000000000000211525227747100166640ustar00rootroot00000000000000defs.h* stamp-h1 bmon-5.0/include/bmon/attr.h000066400000000000000000000074731525227747100160410ustar00rootroot00000000000000/* * bmon/attr.h Attributes * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_ATTR_H_ #define __BMON_ATTR_H_ #include #include struct element; struct rate { /* Total value of attribute with eventual overflows accumulated. */ uint64_t r_total; /* Current value of counter */ uint64_t r_current; /* Value of r_current at last read */ uint64_t r_prev; /* Reset value to subtract to emulate statistics reset */ uint64_t r_reset; /* Rate per second calculated every `rate_interval' */ float r_rate; /* Time of last calculation */ timestamp_t r_last_calc; }; extern uint64_t rate_get_total(struct rate *); enum { ATTR_TYPE_UNSPEC, ATTR_TYPE_COUNTER, ATTR_TYPE_RATE, ATTR_TYPE_PERCENT, }; struct attr_def { int ad_id; char * ad_name; char * ad_description; int ad_type; int ad_flags; struct unit * ad_unit; struct list_head ad_list; }; struct attr_map { const char * name; const char * description; const char * unit; int attrid, type, rxid, txid, flags; }; extern int attr_def_add(const char *, const char *, struct unit *, int, int); extern struct attr_def * attr_def_lookup(const char *); extern struct attr_def * attr_def_lookup_id(int); extern int attr_map_load(struct attr_map *map, size_t size); #define ATTR_FORCE_HISTORY 0x01 /* collect history */ #define ATTR_IGNORE_OVERFLOWS 0x02 #define ATTR_TRUE_64BIT 0x04 #define ATTR_RX_ENABLED 0x08 /* has RX counter */ #define ATTR_TX_ENABLED 0x10 /* has TX counter */ #define ATTR_DOING_HISTORY 0x20 /* history collected */ struct attr { struct rate a_rx_rate, a_tx_rate; uint8_t a_flags; struct attr_def * a_def; timestamp_t a_last_update; struct list_head a_history_list; struct list_head a_list; struct list_head a_sort_list; }; extern struct attr * attr_lookup(const struct element *, int); extern void attr_update(struct element *, int, uint64_t, uint64_t , int ); extern void attr_notify_update(struct attr *, timestamp_t *); extern void attr_free(struct attr *); extern void attr_rate2float(struct attr *, double *, char **, int *, double *, char **, int *); extern void attr_calc_usage(struct attr *, float *, float *, uint64_t, uint64_t); #define ATTR_HASH_SIZE 32 #define UPDATE_FLAG_RX 0x01 #define UPDATE_FLAG_TX 0x02 #define UPDATE_FLAG_64BIT 0x04 extern struct attr * attr_select_first(void); extern struct attr * attr_select_last(void); extern struct attr * attr_select_next(void); extern struct attr * attr_select_prev(void); extern struct attr * attr_current(void); extern void attr_start_collecting_history(struct attr *); extern void attr_reset_counter(struct attr *a); #endif bmon-5.0/include/bmon/bmon.h000066400000000000000000000044321525227747100160120ustar00rootroot00000000000000/* * bmon.h All-include Header * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_BMON_H_ #define __BMON_BMON_H_ #include #include extern int start_time; typedef struct timestamp_s { int64_t tv_sec; int64_t tv_usec; } timestamp_t; typedef struct xdate_s { struct tm d_tm; unsigned int d_usec; } xdate_t; enum { EMPTY_LIST = 1, END_OF_LIST = 2 }; #define BUG() \ do { \ fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__); \ assert(0); \ exit(EINVAL); \ } while (0); #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) #if defined __GNUC__ #define __init __attribute__ ((constructor)) #define __exit __attribute__ ((destructor)) /* Do not use a __* name: reserved and clashes with macOS system headers. */ #define BMON_UNUSED __attribute__ ((__unused__)) #else #define __init #define __exit #define BMON_UNUSED #endif #ifdef DEBUG #define DBG(FMT, ARG...) \ do { \ fprintf(stderr, \ "[DBG] %20s:%-4u %s: " FMT "\n", \ __FILE__, __LINE__, \ __PRETTY_FUNCTION__, ##ARG); \ } while (0) #else #define DBG(FMT, ARG...) \ do { \ } while (0) #endif #endif bmon-5.0/include/bmon/compile-fixes.h000066400000000000000000000025071525227747100176240ustar00rootroot00000000000000/* * compile_fixes.h * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_COMPILE_FIXES_H_ #define __BMON_COMPILE_FIXES_H_ #include #ifndef HAVE_SUSECONDS_T typedef long suseconds_t; #endif #endif bmon-5.0/include/bmon/conf.h000066400000000000000000000050321525227747100160010ustar00rootroot00000000000000/* * conf.h Config Crap * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_CONF_H_ #define __BMON_CONF_H_ #include extern cfg_t *cfg; extern float cfg_read_interval; extern float cfg_rate_interval; extern float cfg_rate_variance; extern float cfg_history_variance; extern int cfg_show_all; extern int cfg_unit_exp; extern void conf_init_pre(void); extern void conf_init_post(void); extern void configfile_read(void); extern void set_configfile(const char *); extern unsigned int get_lifecycles(void); extern void conf_set_float(const char *, double); extern double conf_get_float(const char *); extern void conf_set_int(const char *, long); extern long conf_get_int(const char *); extern void conf_set_string(const char *, const char *); extern const char * conf_get_string(const char *); typedef struct tv_s { char * tv_type; char * tv_value; struct list_head tv_list; } tv_t; typedef struct module_conf_s { char * m_name; struct list_head m_attrs; struct list_head m_list; } module_conf_t; extern int parse_module_param(const char *, struct list_head *); enum { LAYOUT_UNSPEC, LAYOUT_DEFAULT, LAYOUT_STATUSBAR, LAYOUT_HEADER, LAYOUT_LIST, LAYOUT_SELECTED, LAYOUT_RX_GRAPH, LAYOUT_TX_GRAPH, __LAYOUT_MAX }; #define LAYOUT_MAX (__LAYOUT_MAX - 1) struct layout { int l_fg, l_bg, l_attr; }; extern struct layout cfg_layout[]; #endif bmon-5.0/include/bmon/config.h000066400000000000000000000064111525227747100163230ustar00rootroot00000000000000/* * config.h Global Config * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_CONFIG_H_ #define __BMON_CONFIG_H_ #include #include #if STDC_HEADERS != 1 #error "*** ERROR: ANSI C headers required for compilation ***" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SYS_BSD # include #elif !defined(__ANDROID__) # include #endif #include #ifdef HAVE_SYS_TIME_H # include #endif #ifdef HAVE_VFORK_H #include #endif #if !HAVE_WORKING_VFORK #define vfork fork #endif #if defined HAVE_STRING_H #include #elif defined HAVE_STRINGS_H #include #else #error "*** ERROR: No string header file found ***" #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INITTYPES_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #if defined HAVE_GETOPT_H #include #endif #include #include #include #include #if defined HAVE_SYS_UTSNAME_H #include #endif #if defined HAVE_NCURSESW_CURSES_H # include #elif defined HAVE_NCURSESW_H # include #elif defined HAVE_NCURSES_CURSES_H # include #elif defined HAVE_NCURSES_H # include #elif defined HAVE_CURSES_H # include #else # error "SysV or X/Open-compatible Curses header file required" #endif #include #if defined HAVE_NETINET6_IN6_H #include #endif #include #include #include #ifndef IFNAMSIZ #define IFNAMSIZ 16 #endif #ifndef SCNu64 #define SCNu64 "llu" #endif #ifndef PRIu64 #define PRIu64 "llu" #endif #ifndef PRId64 #define PRId64 "lld" #endif #ifndef PRIX64 #define PRIX64 "X" #endif #define DEFAULT_GROUP "intf" #endif bmon-5.0/include/bmon/defs.h.in000066400000000000000000000143541525227747100164110ustar00rootroot00000000000000/* include/bmon/defs.h.in. Generated from configure.ac by autoheader. */ /* enable debugging */ #undef DEBUG /* no overflow workaround */ #undef DISABLE_OVERFLOW_WORKAROUND /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* have curses */ #undef HAVE_CURSES /* Define to 1 if library supports color (enhanced functions) */ #undef HAVE_CURSES_COLOR /* Define to 1 if library supports X/Open Enhanced functions */ #undef HAVE_CURSES_ENHANCED /* Define to 1 if is present */ #undef HAVE_CURSES_H /* Define to 1 if library supports certain obsolete features */ #undef HAVE_CURSES_OBSOLETE /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `getdate' function. */ #undef HAVE_GETDATE /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the 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 `memset' function. */ #undef HAVE_MEMSET /* have ncurses */ #undef HAVE_NCURSES /* Define to 1 if the NcursesW library is present */ #undef HAVE_NCURSESW /* Define to 1 if is present */ #undef HAVE_NCURSESW_CURSES_H /* Define to 1 if is present */ #undef HAVE_NCURSESW_H /* Define to 1 if is present */ #undef HAVE_NCURSES_CURSES_H /* Define to 1 if is present */ #undef HAVE_NCURSES_H /* Define to 1 if you have the header file. */ #undef HAVE_NCURSES_NCURSES_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET6_IN6_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* have redrawwin */ #undef HAVE_REDRAWWIN /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if the system has the type `suseconds_t'. */ #undef HAVE_SUSECONDS_T /* Define to 1 if you have the header file. */ #undef HAVE_SYSCTL_IOCTL_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UTSNAME_H /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* have udc */ #undef HAVE_USE_DEFAULT_COLORS /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define as the return type of signal handlers (void). */ #undef RETSIGTYPE /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* operating system */ #undef SYS_BSD /* operating system */ #undef SYS_LINUX /* operating system */ #undef SYS_OTHER /* operating system */ #undef SYS_SUNOS /* Version number of package */ #undef VERSION /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define as `fork' if `vfork' does not work. */ #undef vfork bmon-5.0/include/bmon/element.h000066400000000000000000000074171525227747100165160ustar00rootroot00000000000000/* * bmon/element.h Elements * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_ELEMENT_H_ #define __BMON_ELEMENT_H_ #include #include #include #define MAX_GRAPHS 32 #define IFNAME_MAX 32 struct policy { char * p_rule; struct list_head p_list; }; struct element_cfg; struct info { char * i_name; char * i_value; struct list_head i_list; }; struct element { char * e_name; char * e_description; uint32_t e_id; uint32_t e_flags; unsigned int e_lifecycles; unsigned int e_level; /* recursion level */ struct element * e_parent; struct element_group * e_group; struct list_head e_list; struct list_head e_childs; unsigned int e_nattrs; struct list_head e_attrhash[ATTR_HASH_SIZE]; struct list_head e_attr_sorted; unsigned int e_ninfo; struct list_head e_info_list; struct attr_def * e_key_attr[__GT_MAX]; struct attr_def * e_usage_attr; float e_rx_usage, e_tx_usage; struct element_cfg * e_cfg; struct attr * e_current_attr; }; #define ELEMENT_CREAT (1 << 0) extern struct element * element_lookup(struct element_group *, const char *, uint32_t, struct element *, int); extern void element_free(struct element *); extern void element_reset_update_flag(struct element_group *, struct element *, void *); extern void element_notify_update(struct element *, timestamp_t *); extern void element_lifesign(struct element *, int); extern void element_check_if_dead(struct element_group *, struct element *, void *); extern int element_set_key_attr(struct element *, const char *, const char *); extern int element_set_usage_attr(struct element *, const char *); #define ELEMENT_FLAG_FOLDED (1 << 0) #define ELEMENT_FLAG_UPDATED (1 << 1) #define ELEMENT_FLAG_EXCLUDE (1 << 2) #define ELEMENT_FLAG_CREATED (1 << 3) extern void element_foreach_attr(struct element *, void (*cb)(struct element *, struct attr *, void *), void *); extern struct element * element_current(void); extern struct element * element_select_first(void); extern struct element * element_select_last(void); extern struct element * element_select_next(void); extern struct element * element_select_prev(void); extern int element_allowed(const char *, struct element_cfg *); extern void element_parse_policy(const char *); extern void element_update_info(struct element *, const char *, const char *); extern void element_delete_info(struct element *, const char *); extern void element_set_txmax(struct element *, uint64_t); extern void element_set_rxmax(struct element *, uint64_t); #endif bmon-5.0/include/bmon/element_cfg.h000066400000000000000000000040201525227747100173200ustar00rootroot00000000000000/* * element_cfg.h Element Configuration * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_ELEMENT_CFG_H_ #define __BMON_ELEMENT_CFG_H_ #include #include #define ELEMENT_CFG_SHOW (1 << 0) #define ELEMENT_CFG_HIDE (1 << 1) struct element_cfg { char * ec_name; /* Name of element config */ char * ec_parent; /* Name of parent */ char * ec_description; /* Human readable description */ uint64_t ec_rxmax; /* Maximum RX value expected */ uint64_t ec_txmax; /* Minimum TX value expected */ unsigned int ec_flags; /* Flags */ struct list_head ec_list; /* Internal, do not modify */ int ec_refcnt; /* Internal, do not modify */ }; extern struct element_cfg * element_cfg_alloc(const char *); extern struct element_cfg * element_cfg_create(const char *); extern void element_cfg_free(struct element_cfg *); extern struct element_cfg * element_cfg_lookup(const char *); #endif bmon-5.0/include/bmon/graph.h000066400000000000000000000041201525227747100161520ustar00rootroot00000000000000/* * bmon/graph.h Graph creation utility * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_GRAPH_H_ #define __BMON_GRAPH_H_ #include #include struct history; #define GRAPH_CFG_BRAILLE 0x01 #define GRAPH_BRAILLE_CELL_BYTES 3 struct graph_cfg { int gc_height, gc_width, gc_flags; char gc_background, gc_foreground, gc_noise, gc_unknown; struct unit * gc_unit; }; struct graph_table { char * gt_table; char * gt_y_unit; float * gt_scale; }; struct graph { struct graph_cfg g_cfg; struct graph_table g_rx, g_tx; struct list_head g_list; }; extern void graph_free(struct graph *); extern struct graph * graph_alloc(struct history *, struct graph_cfg *); extern void graph_refill(struct graph *, struct history *); extern size_t graph_row_size(struct graph_cfg *); extern void new_graph(void); extern void del_graph(void); extern int next_graph(void); extern int prev_graph(void); #endif bmon-5.0/include/bmon/group.h000066400000000000000000000055671525227747100162250ustar00rootroot00000000000000/* * bmon/group.h Group Management * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_GROUP_H_ #define __BMON_GROUP_H_ #include struct element; enum { GT_MAJOR, GT_MINOR, __GT_MAX, }; #define GT_MAX (__GT_MAX - 1) #define GROUP_COL_MAX (__GT_MAX * 2) struct group_hdr { char * gh_name; char * gh_title; char * gh_column[GROUP_COL_MAX]; struct list_head gh_list; }; extern struct group_hdr * group_lookup_hdr(const char *); extern int group_new_hdr(const char *, const char *, const char *, const char *, const char *, const char *); extern int group_new_derived_hdr(const char *, const char *, const char *); struct element_group { char * g_name; struct group_hdr * g_hdr; struct list_head g_elements; unsigned int g_nelements; /* Currently selected element in this group */ struct element * g_current; struct list_head g_list; }; #define GROUP_CREATE 1 extern struct element_group * group_lookup(const char *, int); extern void reset_update_flags(void); extern void free_unused_elements(void); extern void calc_rates(void); extern void group_foreach( void (*cb)(struct element_group *, void *), void *); extern void group_foreach_recursive( void (*cb)(struct element_group *, struct element *, void *), void *); extern void group_foreach_element(struct element_group *, void (*cb)(struct element_group *, struct element *, void *), void *); extern struct element_group * group_current(void); extern struct element_group * group_select_first(void); extern struct element_group * group_select_last(void); extern struct element_group * group_select_next(void); extern struct element_group * group_select_prev(void); #endif bmon-5.0/include/bmon/history.h000066400000000000000000000052651525227747100165650ustar00rootroot00000000000000/* * bmon/history.h History Management * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_HISTORY_H_ #define __BMON_HISTORY_H_ #include #include #define HISTORY_UNKNOWN ((uint64_t) -1) #define HBEAT_TRIGGER 60.0f enum { HISTORY_TYPE_8 = 1, HISTORY_TYPE_16 = 2, HISTORY_TYPE_32 = 4, HISTORY_TYPE_64 = 8, }; struct history_def { char * hd_name; int hd_size, hd_type; float hd_interval; struct list_head hd_list; }; struct history_store { /* TODO? store error ratio? */ void * hs_data; uint64_t hs_prev_total; }; struct history { /* index to current entry in data array */ int h_index; struct history_def * h_definition; /* time of last history update */ timestamp_t h_last_update; struct list_head h_list; float h_min_interval, h_max_interval; struct history_store h_rx, h_tx; }; extern struct history_def * history_def_lookup(const char *); extern struct history_def * history_def_alloc(const char *); extern uint64_t history_data(struct history *, struct history_store *, int); extern void history_update(struct attr *, struct history *, timestamp_t *); extern struct history * history_alloc(struct history_def *); extern void history_free(struct history *); extern void history_attach(struct attr *); extern struct history_def * history_select_first(void); extern struct history_def * history_select_last(void); extern struct history_def * history_select_next(void); extern struct history_def * history_select_prev(void); extern struct history_def * history_current(void); #endif bmon-5.0/include/bmon/info.h000066400000000000000000000026011525227747100160060ustar00rootroot00000000000000/* * bmon/info.h Info Attributes * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_INFO_H_ #define __BMON_INFO_H_ #include #include struct element; struct info { char * i_name; char * i_value; struct list_head i_list; }; #endif bmon-5.0/include/bmon/input.h000066400000000000000000000034661525227747100162240ustar00rootroot00000000000000/* * input.h Input API * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_INPUT_H_ #define __BMON_INPUT_H_ #include #include #include extern int input_set(const char *, bool update); extern void input_register(struct bmon_module *); extern void input_read(void); extern int input_is_enabled(const char *name); extern int input_get_opt(const char *name, const char *opt); struct reader_timing { timestamp_t rt_last_read; /* timestamp taken before read */ timestamp_t rt_next_read; /* estimated next read */ struct { float v_error; float v_max; float v_min; float v_total; } rt_variance; }; extern struct reader_timing rtiming; #endif bmon-5.0/include/bmon/layout.h000066400000000000000000000100371525227747100163720ustar00rootroot00000000000000 #ifndef __BMON_LAYOUT_H_ #define __BMON_LAYOUT_H_ #include #include #include #include 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_ */ bmon-5.0/include/bmon/list.h000066400000000000000000000050511525227747100160300ustar00rootroot00000000000000/* * bmon/list.h Kernel List Implementation * * Copied and adapted from the kernel sources * */ #ifndef BMON_LIST_H_ #define BMON_LIST_H_ #ifdef __APPLE__ /* Apple systems define these macros in system headers, so we undef * them prior to inclusion of this file */ #undef LIST_HEAD #undef LIST_HEAD_INIT #undef INIT_LIST_HEAD #endif struct list_head { struct list_head * next; struct list_head * prev; }; static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } static inline void __list_add(struct list_head *obj, struct list_head *prev, struct list_head *next) { prev->next = obj; obj->prev = prev; next->prev = obj; obj->next = next; } static inline void list_add_tail(struct list_head *obj, struct list_head *head) { __list_add(obj, head->prev, head); } static inline void list_add_head(struct list_head *obj, struct list_head *head) { __list_add(obj, head, head->next); } static inline void list_del(struct list_head *obj) { obj->next->prev = obj->prev; obj->prev->next = obj->next; } static inline int list_empty(struct list_head *head) { return head->next == head; } #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));}) #define list_entry(ptr, type, member) \ container_of(ptr, type, member) #define list_at_tail(pos, head, member) \ ((pos)->member.next == (head)) #define list_at_head(pos, head, member) \ ((pos)->member.prev == (head)) #define LIST_SELF(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = { &(name), &(name) } #define list_first_entry(head, type, member) \ list_entry((head)->next, type, member) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &(pos)->member != (head); \ (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &(pos)->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #define init_list_head(head) \ do { (head)->next = (head); (head)->prev = (head); } while (0) #endif bmon-5.0/include/bmon/module.h000066400000000000000000000050711525227747100163440ustar00rootroot00000000000000/* * module.h Module API * * Copyright (c) 2001-2013 Thomas Graf * Copyright 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_MODULE_H_ #define __BMON_MODULE_H_ #include #include #define BMON_MODULE_ENABLED (1 << 0) /* Enabled */ #define BMON_MODULE_DEFAULT (1 << 1) /* Suitable as default */ #define BMON_MODULE_AUTO (1 << 2) /* Auto enable */ struct bmon_subsys; struct bmon_module { char * m_name; int (*m_init)(void); int (*m_probe)(void); void (*m_shutdown)(void); void (*m_parse_opt)(const char *, const char *); int (*m_get_opt)(const char *); void (*m_pre)(void); void (*m_do)(void); void (*m_post)(void); int m_flags; struct list_head m_list; struct bmon_subsys *m_subsys; }; struct bmon_subsys { char * s_name; int s_nmod; struct list_head s_mod_list; void (*s_activate_default)(void); struct list_head s_list; }; extern void module_foreach_run_enabled_pre(struct bmon_subsys *); extern void module_foreach_run_enabled(struct bmon_subsys *); extern void module_foreach_run_enabled_post(struct bmon_subsys *); extern int module_register(struct bmon_subsys *, struct bmon_module *); extern int module_set(struct bmon_subsys *, const char *, bool update); extern int module_get_opt(struct bmon_subsys *, const char *, const char *); extern void module_init(void); extern void module_shutdown(void); extern void module_register_subsys(struct bmon_subsys *); #endif bmon-5.0/include/bmon/output.h000066400000000000000000000027721525227747100164240ustar00rootroot00000000000000/* * output.h Output API * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_OUTPUT_H_ #define __BMON_OUTPUT_H_ #include #include #include extern void output_register(struct bmon_module *); extern int output_set(const char *); extern void output_pre(void); extern void output_draw(void); extern void output_post(void); #endif bmon-5.0/include/bmon/unit.h000066400000000000000000000040761525227747100160420ustar00rootroot00000000000000/* * bmon/unit.h Units * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_UNIT_H_ #define __BMON_UNIT_H_ #include #define DYNAMIC_EXP (-1) enum { UNIT_DEFAULT, UNIT_SI, UNIT_BIT, __UNIT_MAX, }; #define UNIT_MAX (__UNIT_MAX - 1) #define UNIT_BYTE "byte" #define UNIT_NUMBER "number" struct fraction { float f_divisor; char * f_name; struct list_head f_list; }; struct unit { char * u_name; struct list_head u_div[__UNIT_MAX]; struct list_head u_list; }; extern struct unit * unit_lookup(const char *); extern struct unit * unit_add(const char *name); extern void unit_add_div(struct unit *, int, const char *, float); extern double unit_divisor(uint64_t, struct unit *, char **, int *); extern double unit_value2str(uint64_t, struct unit *, char **, int *); extern void fraction_free(struct fraction *); extern char * unit_bytes2str(uint64_t, char *, size_t); extern char * unit_bit2str(uint64_t, char *, size_t); #endif bmon-5.0/include/bmon/utils.h000066400000000000000000000057731525227747100162300ustar00rootroot00000000000000/* * utils.h General purpose utilities * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef __BMON_UTILS_H_ #define __BMON_UTILS_H_ #include extern void * xcalloc(size_t, size_t); extern void * xrealloc(void *, size_t); extern char * xstrdup(const char *); extern void xfree(void *); extern void quit (const char *, ...); extern float timestamp_to_float(timestamp_t *); extern int64_t timestamp_to_int(timestamp_t *); extern void float_to_timestamp(timestamp_t *, float); extern void int_to_timestamp(timestamp_t *, int); extern void timestamp_add(timestamp_t *, timestamp_t *, timestamp_t *); extern void timestamp_sub(timestamp_t *, timestamp_t *, timestamp_t *); extern int timestamp_le(timestamp_t *, timestamp_t *); extern int timestamp_is_negative(timestamp_t *ts); extern void update_timestamp(timestamp_t *); extern void copy_timestamp(timestamp_t *, timestamp_t *); extern float timestamp_diff(timestamp_t *, timestamp_t *); #if 0 #if __BYTE_ORDER == __BIG_ENDIAN #define xntohll(N) (N) #define xhtonll(N) (N) #else #define xntohll(N) ((((uint64_t) ntohl(N)) << 32) + ntohl((N) >> 32)) #define xhtonll(N) ((((uint64_t) htonl(N)) << 32) + htonl((N) >> 32)) #endif enum { U_NUMBER, U_BYTES, U_BITS }; extern float read_delta; const char * xinet_ntop(struct sockaddr *, char *, socklen_t); extern float time_diff(timestamp_t *, timestamp_t *); extern float diff_now(timestamp_t *); extern uint64_t parse_size(const char *); extern int parse_date(const char *str, xdate_t *dst); #ifndef HAVE_STRDUP extern char *strdup(const char *); #endif extern char * timestamp2str(timestamp_t *ts, char *buf, size_t len); static inline char *xstrncat(char *dest, const char *src, size_t n) { return strncat(dest, src, n - strlen(dest) - 1); } static inline void xdate_to_ts(timestamp_t *dst, xdate_t *src) { dst->tv_sec = mktime(&src->d_tm); dst->tv_usec = src->d_usec; }; #endif #endif bmon-5.0/m4/000077500000000000000000000000001525227747100126455ustar00rootroot00000000000000bmon-5.0/m4/ax_with_curses.m4000066400000000000000000000607331525227747100161470ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_with_curses.html # =========================================================================== # # SYNOPSIS # # AX_WITH_CURSES # # DESCRIPTION # # This macro checks whether a SysV or X/Open-compatible Curses library is # present, along with the associated header file. The NcursesW # (wide-character) library is searched for first, followed by Ncurses, # then the system-default plain Curses. The first library found is the # one returned. # # The following options are understood: --with-ncursesw, --with-ncurses, # --without-ncursesw, --without-ncurses. The "--with" options force the # macro to use that particular library, terminating with an error if not # found. The "--without" options simply skip the check for that library. # The effect on the search pattern is: # # (no options) - NcursesW, Ncurses, Curses # --with-ncurses --with-ncursesw - NcursesW only [*] # --without-ncurses --with-ncursesw - NcursesW only [*] # --with-ncursesw - NcursesW only [*] # --with-ncurses --without-ncursesw - Ncurses only [*] # --with-ncurses - NcursesW, Ncurses [**] # --without-ncurses --without-ncursesw - Curses only # --without-ncursesw - Ncurses, Curses # --without-ncurses - NcursesW, Curses # # [*] If the library is not found, abort the configure script. # # [**] If the second library (Ncurses) is not found, abort configure. # # The following preprocessor symbols may be defined by this macro if the # appropriate conditions are met: # # HAVE_CURSES - if any SysV or X/Open Curses library found # HAVE_CURSES_ENHANCED - if library supports X/Open Enhanced functions # HAVE_CURSES_COLOR - if library supports color (enhanced functions) # HAVE_CURSES_OBSOLETE - if library supports certain obsolete features # HAVE_NCURSESW - if NcursesW (wide char) library is to be used # HAVE_NCURSES - if the Ncurses library is to be used # # HAVE_CURSES_H - if is present and should be used # HAVE_NCURSESW_H - if should be used # HAVE_NCURSES_H - if should be used # HAVE_NCURSESW_CURSES_H - if should be used # HAVE_NCURSES_CURSES_H - if should be used # # (These preprocessor symbols are discussed later in this document.) # # The following output variable is defined by this macro; it is precious # and may be overridden on the ./configure command line: # # CURSES_LIB - library to add to xxx_LDADD # # The library listed in CURSES_LIB is NOT added to LIBS by default. You # need to add CURSES_LIB to the appropriate xxx_LDADD line in your # Makefile.am. For example: # # prog_LDADD = @CURSES_LIB@ # # If CURSES_LIB is set on the configure command line (such as by running # "./configure CURSES_LIB=-lmycurses"), then the only header searched for # is . The user may use the CPPFLAGS precious variable to # override the standard #include search path. If the user needs to # specify an alternative path for a library (such as for a non-standard # NcurseW), the user should use the LDFLAGS variable. # # The following shell variables may be defined by this macro: # # ax_cv_curses - set to "yes" if any Curses library found # ax_cv_curses_enhanced - set to "yes" if Enhanced functions present # ax_cv_curses_color - set to "yes" if color functions present # ax_cv_curses_obsolete - set to "yes" if obsolete features present # # ax_cv_ncursesw - set to "yes" if NcursesW library found # ax_cv_ncurses - set to "yes" if Ncurses library found # ax_cv_plaincurses - set to "yes" if plain Curses library found # ax_cv_curses_which - set to "ncursesw", "ncurses", "plaincurses" or "no" # # These variables can be used in your configure.ac to determine the level # of support you need from the Curses library. For example, if you must # have either Ncurses or NcursesW, you could include: # # AX_WITH_CURSES # if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then # AX_MSG_ERROR([requires either NcursesW or Ncurses library]) # fi # # If any Curses library will do (but one must be present and must support # color), you could use: # # AX_WITH_CURSES # if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then # AC_MSG_ERROR([requires an X/Open-compatible Curses library with color]) # fi # # Certain preprocessor symbols and shell variables defined by this macro # can be used to determine various features of the Curses library. In # particular, HAVE_CURSES and ax_cv_curses are defined if the Curses # library found conforms to the traditional SysV and/or X/Open Base Curses # definition. Any working Curses library conforms to this level. # # HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the # library supports the X/Open Enhanced Curses definition. In particular, # the wide-character types attr_t, cchar_t and wint_t, the functions # wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES # are checked. The Ncurses library does NOT conform to this definition, # although NcursesW does. # # HAVE_CURSES_COLOR and ax_cv_curses_color are defined if the library # supports color functions and macros such as COLOR_PAIR, A_COLOR, # COLOR_WHITE, COLOR_RED and init_pair(). These are NOT part of the # X/Open Base Curses definition, but are part of the Enhanced set of # functions. The Ncurses library DOES support these functions, as does # NcursesW. # # HAVE_CURSES_OBSOLETE and ax_cv_curses_obsolete are defined if the # library supports certain features present in SysV and BSD Curses but not # defined in the X/Open definition. In particular, the functions # getattrs(), getcurx() and getmaxx() are checked. # # To use the HAVE_xxx_H preprocessor symbols, insert the following into # your system.h (or equivalent) header file: # # #if defined HAVE_NCURSESW_CURSES_H # # include # #elif defined HAVE_NCURSESW_H # # include # #elif defined HAVE_NCURSES_CURSES_H # # include # #elif defined HAVE_NCURSES_H # # include # #elif defined HAVE_CURSES_H # # include # #else # # error "SysV or X/Open-compatible Curses header file required" # #endif # # For previous users of this macro: you should not need to change anything # in your configure.ac or Makefile.am, as the previous (serial 10) # semantics are still valid. However, you should update your system.h (or # equivalent) header file to the fragment shown above. You are encouraged # also to make use of the extended functionality provided by this version # of AX_WITH_CURSES, as well as in the additional macros # AX_WITH_CURSES_PANEL, AX_WITH_CURSES_MENU and AX_WITH_CURSES_FORM. # # LICENSE # # Copyright (c) 2009 Mark Pulford # Copyright (c) 2009 Damian Pietras # Copyright (c) 2012 Reuben Thomas # Copyright (c) 2011 John Zaitseff # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 13 AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES]) AC_DEFUN([AX_WITH_CURSES], [ AC_ARG_VAR([CURSES_LIB], [linker library for Curses, e.g. -lcurses]) AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses], [force the use of Ncurses or NcursesW])], [], [with_ncurses=check]) AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw], [do not use NcursesW (wide character support)])], [], [with_ncursesw=check]) ax_saved_LIBS=$LIBS AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes], [ax_with_plaincurses=no], [ax_with_plaincurses=check]) ax_cv_curses_which=no # Test for NcursesW AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncursesw" != xno], [ LIBS="$ax_saved_LIBS -lncursesw" AC_CACHE_CHECK([for NcursesW wide-character library], [ax_cv_ncursesw], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_ncursesw=yes], [ax_cv_ncursesw=no]) ]) AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [ AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library]) ]) AS_IF([test "x$ax_cv_ncursesw" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=ncursesw CURSES_LIB="-lncursesw" AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) AC_CACHE_CHECK([for working ncursesw/curses.h], [ax_cv_header_ncursesw_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncursesw_curses_h=yes], [ax_cv_header_ncursesw_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSESW_CURSES_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncursesw.h], [ax_cv_header_ncursesw_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncursesw_h=yes], [ax_cv_header_ncursesw_h=no]) ]) AS_IF([test "x$ax_cv_header_ncursesw_h" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSESW_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h_with_ncursesw], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_header_ncurses_h_with_ncursesw=yes], [ax_cv_header_ncurses_h_with_ncursesw=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_h_with_ncursesw" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) ]) AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [ AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h]) ]) ]) ]) # Test for Ncurses AS_IF([test "x$CURSES_LIB" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [ LIBS="$ax_saved_LIBS -lncurses" AC_CACHE_CHECK([for Ncurses library], [ax_cv_ncurses], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_ncurses=yes], [ax_cv_ncurses=no]) ]) AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [ AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library]) ]) AS_IF([test "x$ax_cv_ncurses" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=ncurses CURSES_LIB="-lncurses" AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) AC_CACHE_CHECK([for working ncurses/curses.h], [ax_cv_header_ncurses_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_header_ncurses_curses_h=yes], [ax_cv_header_ncurses_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xyes], [ ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_CURSES_H], [1], [Define to 1 if is present]) ]) AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_header_ncurses_h=yes], [ax_cv_header_ncurses_h=no]) ]) AS_IF([test "x$ax_cv_header_ncurses_h" = xyes], [ ax_cv_curses_color=yes ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) ]) AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xno && test "x$ax_cv_header_ncurses_h" = xno], [ AC_MSG_WARN([could not find a working ncurses/curses.h or ncurses.h]) ]) ]) ]) # Test for plain Curses (or if CURSES_LIB was set by user) AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [ AS_IF([test "x$CURSES_LIB" != x], [ LIBS="$ax_saved_LIBS $CURSES_LIB" ], [ LIBS="$ax_saved_LIBS -lcurses" ]) AC_CACHE_CHECK([for Curses library], [ax_cv_plaincurses], [ AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], [ax_cv_plaincurses=yes], [ax_cv_plaincurses=no]) ]) AS_IF([test "x$ax_cv_plaincurses" = xyes], [ ax_cv_curses=yes ax_cv_curses_which=plaincurses AS_IF([test "x$CURSES_LIB" = x], [ CURSES_LIB="-lcurses" ]) AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) # Check for base conformance (and header file) AC_CACHE_CHECK([for working curses.h], [ax_cv_header_curses_h], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; initscr(); ]])], [ax_cv_header_curses_h=yes], [ax_cv_header_curses_h=no]) ]) AS_IF([test "x$ax_cv_header_curses_h" = xyes], [ AC_DEFINE([HAVE_CURSES_H], [1], [Define to 1 if is present]) # Check for X/Open Enhanced conformance AC_CACHE_CHECK([for X/Open Enhanced Curses conformance], [ax_cv_plaincurses_enhanced], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include @%:@ifndef _XOPEN_CURSES @%:@error "this Curses library is not enhanced" "this Curses library is not enhanced" @%:@endif ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; attr_t d = WA_NORMAL; cchar_t e; wint_t f; initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); wattr_set(stdscr, d, 0, NULL); wget_wch(stdscr, &f); ]])], [ax_cv_plaincurses_enhanced=yes], [ax_cv_plaincurses_enhanced=no]) ]) AS_IF([test "x$ax_cv_plaincurses_enhanced" = xyes], [ ax_cv_curses_enhanced=yes ax_cv_curses_color=yes AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) ]) # Check for color functions AC_CACHE_CHECK([for Curses color functions], [ax_cv_plaincurses_color], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@define _XOPEN_SOURCE_EXTENDED 1 @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; chtype c = COLOR_PAIR(1) & A_COLOR; initscr(); init_pair(1, COLOR_WHITE, COLOR_RED); ]])], [ax_cv_plaincurses_color=yes], [ax_cv_plaincurses_color=no]) ]) AS_IF([test "x$ax_cv_plaincurses_color" = xyes], [ ax_cv_curses_color=yes AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) ]) # Check for obsolete functions AC_CACHE_CHECK([for obsolete Curses functions], [ax_cv_plaincurses_obsolete], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ @%:@include ]], [[ chtype a = A_BOLD; int b = KEY_LEFT; int g = getattrs(stdscr); int h = getcurx(stdscr) + getmaxx(stdscr); initscr(); ]])], [ax_cv_plaincurses_obsolete=yes], [ax_cv_plaincurses_obsolete=no]) ]) AS_IF([test "x$ax_cv_plaincurses_obsolete" = xyes], [ ax_cv_curses_obsolete=yes AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) ]) ]) AS_IF([test "x$ax_cv_header_curses_h" = xno], [ AC_MSG_WARN([could not find a working curses.h]) ]) ]) ]) AS_IF([test "x$ax_cv_curses" != xyes], [ax_cv_curses=no]) AS_IF([test "x$ax_cv_curses_enhanced" != xyes], [ax_cv_curses_enhanced=no]) AS_IF([test "x$ax_cv_curses_color" != xyes], [ax_cv_curses_color=no]) AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no]) LIBS=$ax_saved_LIBS ])dnl bmon-5.0/man/000077500000000000000000000000001525227747100131005ustar00rootroot00000000000000bmon-5.0/man/Makefile.am000066400000000000000000000000541525227747100151330ustar00rootroot00000000000000# -*- Makefile -*- dist_man8_MANS = bmon.8 bmon-5.0/man/bmon.8000066400000000000000000000146371525227747100141370ustar00rootroot00000000000000.TH "bmon" "8" "" "Bandwidth Monitor" "bmon" .SH "NAME" bmon \- bandwidth monitor and rate estimator .SH "SYNOPSIS" .B bmon [\fB\-\-show\-all\fR] [\fB\-\-use\-si\fR] [\fB\-\-input\fR=\fIMODULE\fR] [\fB\-\-output\fR=\fIMODULE\fR] [OPTIONS...] .SH "DESCRIPTION" bmon is a monitoring and debugging tool to capture networking related statistics and prepare them visually in a human friendly way. It features various output methods including an interactive curses user interface and a programmable text output for scripting. .SH "OPTIONS" .PP \fB \-h\fR, \fB\-\-help\fR .RS 4 Prints a short help text and exits\&. .RE .PP \fB \-V\fR, \fB\-\-version\fR .RS 4 Prints the versioning identifier and exits\&. .RE .PP \fB \-i\fR, \fB\-\-input=\fRMODULE[:OPTIONS][,MODULE...] .RS 4 Set list of input modules to load and use. Multiple modules can be used in parallel. bmon automatically loads a useful and working input module by default. See INPUT MODULES for more details. .RE .PP \fB \-o\fR, \fB\-\-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 not available due to an incompatible console it will fall back to a simple text mode. See OUTPUT MODULES for more details. .RE .PP \fB \-U\fR, \fB\-\-use\-si\fR .RS 4 Use SI unit system (1KB = 1'000 bytes) instead of 1KB = 1'024 bytes. .RE .PP \fB \-f\fR, \fB\-\-configfile=\fRFILE .RS 4 Set alternative path to configuration file. .RE .PP \fB \-p\fR, \fB\-\-policy=\fRPOLICY .RS 4 Set policy defining which network interfaces to display. See INTERFACE SELECTION for more details. .RE .PP \fB \-a\fR, \fB\-\-show\-all\fR .RS 4 Display all interfaces, even interfaces that are administratively down. .RE .PP \fB \-r\fR, \fB\-\-read\-interval=\fRFLOAT .RS 4 Set interval in seconds in which input modules read statistics from their source. The default is 1.0 seconds. .RE .PP \fB \-R\fR, \fB\-\-rate\-interval=\fRFLOAT .RS 4 Set interval in seconds in which the rate per counter is calculated. The default is 1.0 seconds. .RE .PP \fB \-b\fR, \fB\-\-use\-bit\fR .RS 4 Show rates in bits per second instead of bytes per second. .RE .PP \fB \-L\fR, \fB\-\-lifetime=\fRFLOAT .RS 4 Set lifetime of an element in seconds before it is no longer displayed without receiving any statistical updates. The default is 30 seconds. .RE .SH "INPUT MODULES" .PP Input modules provide statistical data about elements. Each element consists of attributes which represent a counter, a rate, or a percentage. Elements may carry additional child elements to represent a hierarchy. Each element is assigned to a group defined by the input module. Input modules are polled in the frequency of the configured read interval. .PP The following input modules are available: .TP \fBnetlink\fR Uses the Netlink protocol to collect interface and traffic control statistics from the kernel. This is the default input module. .TP \fBproc\fR Reads interface statistics from the /proc/net/dev file. This is considered a legacy interface and provided for backwards compatibility reasons. This is a fallback module if the Netlink interface is not available. .TP \fBdummy\fR Programmable input module for debugging and testing purposes. .TP \fBnull\fR No data collected. .PP To receive additional information about a module, run the module with the "help" option set like this: .PP .RS 4 bmon \-i netlink:help .RE See MODULE CONFIGURATION for more details. .SH "OUTPUT MODULES" .PP Output modules display or export the statistical data collected by input modules. Multiple output modules can be run at the same time. bmon will not prevent possible conflicts such as multiple output modules writing to the console. .PP The following output modules exist: .TP \fBcurses\fR Interactive curses based text user interface providing real time rate estimations and a graphical representation of each attribute. Press '?' to display the quick reference guide. Additional interface information (including IPv4/IPv6 addresses when using the netlink input) can be toggled with '\fBi\fR'; use '\fB4\fR' and '\fB6\fR' to show or hide IPv4 and IPv6 addresses. This is the default output mode. .TP \fBascii\fR Simple programmable text output intended for human consumption. Capable of printing list of interfaces, detailed counters and graphs to the console. This is the default fallback output mode if curses is not available. .TP \fBformat\fR Fully scriptable output mode intended for consumption by other programs. See the module help text for additional information. .TP \fBjson\fR JSON output mode intended for consumption by other programs. Prints one JSON object per update with a Unix timestamp plus groups, elements, and attribute totals and rates. See the module help text for additional information. .TP \fBnull\fR Disable output. .PP To receive additional information about a module, run the module with the "help" option set like this: .PP .RS 4 bmon \-o curses:help .RE See MODULE CONFIGURATION for more details. .SH "MODULE CONFIGURATION" .PP The syntax to configure modules is as follows: .PP .RS 4 ARGUMENT ::= mod1[:OPTS][,mod2[:OPTS]...] .br OPTS ::= OPTION[;OPTION...] .br OPTION ::= option[=value] .RE .PP Run the module with option "help" to receive the list of options for each module: .PP .RS 4 bmon \-i module:help .RE .SH "INTERFACE SELECTION" .PP The following syntax is used to define the interface selection policy: .PP .RS 4 SELECTION ::= NAME[,NAME[,...]] .br NAME ::= [!]interface .RE .PP The interface name may contain the character '*' which will act as a wildcard and represents any number of any character type, e.g. eth*, h*0, ... .PP Examples: .PP .RS 4 lo,eth0,eth1 .br eth*,!eth0 .RE .SH "EXAMPLES" .PP To run bmon in curses mode monitoring the interfaces eth0 and eth1: .PP .RS 4 \fBbmon \-p eth0,eth1 \-o curses\fP .RE .PP To start curses with the additional info panel and IPv6 addresses hidden: .PP .RS 4 \fBbmon \-o curses:info;ipv6=0\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 To run bmon in JSON mode for a single sample on eth0: .PP .RS 4 \fBbmon \-p eth0 \-o json:quitafter=1\fP .RE .PP .SH "FILES" /etc/bmon.conf .br $HOME/.bmonrc .SH "SEE ALSO" .PP \fBip\fR(8), \fBnetstat\fR(8), \fBifconfig\fR(8), \fBnetlink\fR(7), .SH "AUTHOR" Thomas Graf among others bmon-5.0/src/000077500000000000000000000000001525227747100131145ustar00rootroot00000000000000bmon-5.0/src/.gitignore000066400000000000000000000000111525227747100150740ustar00rootroot00000000000000*.o bmon bmon-5.0/src/Makefile.am000066400000000000000000000012401525227747100151450ustar00rootroot00000000000000# -*- Makefile -*- bin_PROGRAMS = bmon bmon_CFLAGS = \ -I${top_srcdir}/include \ -I${top_builddir}/include \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -D_GNU_SOURCE \ -Wall \ $(WERROR) \ $(CURSES_CFLAGS) \ $(CONFUSE_CFLAGS) \ $(LIBNL_CFLAGS) \ $(LIBNL_ROUTE_CFLAGS) bmon_LDADD = \ $(CURSES_LIB) \ $(CONFUSE_LIBS) \ $(LIBNL_LIBS) \ $(LIBNL_ROUTE_LIBS) bmon_SOURCES = \ utils.c \ unit.c \ conf.c \ input.c \ output.c \ group.c \ element.c \ attr.c \ element_cfg.c \ history.c \ graph.c \ bmon.c \ module.c \ in_netlink.c \ in_null.c \ in_dummy.c \ in_proc.c \ in_sysctl.c \ out_null.c \ out_format.c \ out_ascii.c \ out_json.c \ out_curses.c bmon-5.0/src/attr.c000066400000000000000000000322551525227747100142410ustar00rootroot00000000000000/* * attr.c Attributes * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #if 0 #define MAX_POLICY 255 static char * allowed_attrs[MAX_POLICY]; static char * denied_attrs[MAX_POLICY]; static int allow_all_attrs; #endif static LIST_HEAD(attr_def_list); static int attr_id_gen = 1; struct attr_def *attr_def_lookup(const char *name) { struct attr_def *def; list_for_each_entry(def, &attr_def_list, ad_list) if (!strcmp(name, def->ad_name)) return def; return NULL; } struct attr_def *attr_def_lookup_id(int id) { struct attr_def *def; list_for_each_entry(def, &attr_def_list, ad_list) if (def->ad_id == id) return def; return NULL; } #if 0 int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg) { int i, err = 0; for (i = 0; i < NAME_HASHSIZ; i++) { struct attr_type *t; for (t = attr_ht_name[i]; t; t = t->at_next_name) { err = cb(t, arg); if (err < 0) break; } } return err; } #endif int attr_def_add(const char *name, const char *desc, struct unit *unit, int type, int flags) { struct attr_def *def; if ((def = attr_def_lookup(name))) return def->ad_id; def = xcalloc(1, sizeof(*def)); def->ad_id = attr_id_gen++; def->ad_name = xstrdup(name); def->ad_description = xstrdup(desc ? : ""); def->ad_type = type; def->ad_unit = unit; def->ad_flags = flags; list_add_tail(&def->ad_list, &attr_def_list); DBG("New attribute %s desc=\"%s\" unit=%s type=%d", def->ad_name, def->ad_description, def->ad_unit->u_name, type); return def->ad_id; } static void attr_def_free(struct attr_def *def) { if (!def) return; xfree(def->ad_name); xfree(def->ad_description); xfree(def); } int attr_map_load(struct attr_map *map, size_t size) { int i, nfailed = 0; for (i = 0; i < size; i++) { struct attr_map *m = &map[i]; struct unit *u; if (!(u = unit_lookup(m->unit))) { nfailed++; continue; } m->attrid = attr_def_add(m->name, m->description, u, m->type, m->flags); } return nfailed; } static inline unsigned int attr_hash(int id) { return id % ATTR_HASH_SIZE; } struct attr *attr_lookup(const struct element *e, int id) { unsigned int hash = attr_hash(id); struct attr *attr; list_for_each_entry(attr, &e->e_attrhash[hash], a_list) if (attr->a_def->ad_id == id) return attr; return NULL; } static int collect_history(struct element *e, struct attr_def *def) { int n; if (def->ad_flags & ATTR_FORCE_HISTORY) return 1; for (n = 0; n <= GT_MAX; n++) if (e->e_key_attr[n] == def) return 1; return 0; #if 0 if (!allowed_attrs[0] && !denied_attrs[0]) { if (!strcmp(ad->ad_name, "bytes") || !strcmp(ad->ad_name, "packets")) return 1; else return 0; } if (!allowed_attrs[0]) { for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++) if (!strcasecmp(denied_attrs[n], ad->ad_name)) return 0; return 1; } for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++) if (!strcasecmp(denied_attrs[n], ad->ad_name)) return 0; for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++) if (!strcasecmp(allowed_attrs[n], ad->ad_name)) return 1; #endif } #if 0 void attr_parse_policy(const char *policy) { static int set = 0; int i, a = 0, d = 0, f = 0; char *p, *s; if (set) return; set = 1; if (!strcasecmp(policy, "all")) { allow_all_attrs = 1; return ; } s = xstrdup(policy); for (i = 0, p = s; ; i++) { if (s[i] == ',' || s[i] == '\0') { f = s[i] == '\0' ? 1 : 0; s[i] = '\0'; if ('!' == *p) { if (d > (MAX_POLICY - 1)) break; denied_attrs[d++] = xstrdup(++p); } else { if(a > (MAX_POLICY - 1)) break; allowed_attrs[a++] = xstrdup(p); } if (f) break; p = &s[i+1]; } } xfree(s); } #endif void attr_start_collecting_history(struct attr *attr) { if (attr->a_flags & ATTR_DOING_HISTORY) return; DBG("Starting to collect history for attribute %s", attr->a_def->ad_name); history_attach(attr); attr->a_flags |= ATTR_DOING_HISTORY; } static int attrcmp(struct element *e, struct attr *a, struct attr *b) { /* major key attribute is always first */ if (e->e_key_attr[GT_MAJOR] == b->a_def) return 1; /* minor key attribte is always second */ if (e->e_key_attr[GT_MINOR] == b->a_def) return (e->e_key_attr[GT_MAJOR] == a->a_def) ? -1 : 1; /* otherwise sort by alphabet */ return strcasecmp(a->a_def->ad_description, b->a_def->ad_description); } void attr_update(struct element *e, int id, uint64_t rx, uint64_t tx, int flags) { struct attr *attr, *n; int update_ts = 0; if (!(attr = attr_lookup(e, id))) { unsigned int hash = attr_hash(id); struct attr_def *def; if (!(def = attr_def_lookup_id(id))) return; DBG("Tracking new attribute %d (\"%s\") of element %s", def->ad_id, def->ad_name, e->e_name); attr = xcalloc(1, sizeof(*attr)); attr->a_def = def; attr->a_flags = def->ad_flags; init_list_head(&attr->a_history_list); if (collect_history(e, def)) attr_start_collecting_history(attr); list_add_tail(&attr->a_list, &e->e_attrhash[hash]); e->e_nattrs++; list_for_each_entry(n, &e->e_attr_sorted, a_sort_list) { if (attrcmp(e, attr, n) < 0) { list_add_tail(&attr->a_sort_list, &n->a_sort_list); goto inserted; } } list_add_tail(&attr->a_sort_list, &e->e_attr_sorted); } inserted: if (flags & UPDATE_FLAG_RX) { attr->a_rx_rate.r_current = rx; attr->a_flags |= ATTR_RX_ENABLED; update_ts = 1; } if (flags & UPDATE_FLAG_TX) { attr->a_tx_rate.r_current = tx; attr->a_flags |= ATTR_TX_ENABLED; update_ts = 1; } if (update_ts) update_timestamp(&attr->a_last_update); DBG("Updated attribute %d (\"%s\") of element %s", id, attr->a_def->ad_name, e->e_name); } void attr_free(struct attr *a) { struct history *h, *n; list_for_each_entry_safe(h, n, &a->a_history_list, h_list) history_free(h); list_del(&a->a_list); xfree(a); } void attr_rate2float(struct attr *a, double *rx, char **rxu, int *rxprec, double *tx, char **txu, int *txprec) { struct unit *u = a->a_def->ad_unit; *rx = unit_value2str(a->a_rx_rate.r_rate, u, rxu, rxprec); *tx = unit_value2str(a->a_tx_rate.r_rate, u, txu, txprec); } struct attr *attr_select_first(void) { struct element *e; if (!(e = element_current())) return NULL; if (list_empty(&e->e_attr_sorted)) e->e_current_attr = NULL; else e->e_current_attr = list_first_entry(&e->e_attr_sorted, struct attr, a_sort_list); return e->e_current_attr; } struct attr *attr_select_last(void) { struct element *e; if (!(e = element_current())) return NULL; if (list_empty(&e->e_attr_sorted)) e->e_current_attr = NULL; else e->e_current_attr = list_entry(&e->e_attr_sorted, struct attr, a_sort_list); return e->e_current_attr; } struct attr *attr_select_next(void) { struct element *e; struct attr *a; if (!(e = element_current())) return NULL; if (!(a = e->e_current_attr)) return attr_select_first(); if (a->a_sort_list.next != &e->e_attr_sorted) e->e_current_attr = list_entry(a->a_sort_list.next, struct attr, a_sort_list); else return attr_select_first(); return e->e_current_attr; } struct attr *attr_select_prev(void) { struct element *e; struct attr *a; if (!(e = element_current())) return NULL; if (!(a = e->e_current_attr)) return attr_select_last(); if (a->a_sort_list.prev != &e->e_attr_sorted) e->e_current_attr = list_entry(a->a_sort_list.prev, struct attr, a_sort_list); else return attr_select_last(); return e->e_current_attr; } struct attr *attr_current(void) { struct element *e; if (!(e = element_current())) return NULL; if (!e->e_current_attr) return attr_select_first(); return e->e_current_attr; } #if 0 int __first_attr(struct item *item, int graph) { int i; struct attr *a; for (i = 0; i < ATTR_HASH_MAX; i++) { for (a = item->i_attrs[i]; a; a = a->a_next) { if (a->a_flags & ATTR_FLAG_HISTORY) { item->i_attr_sel[graph] = a; return 0; } } } return EMPTY_LIST; } int __next_attr(struct item *item, int graph) { int hash; struct attr *attr, *next; if (item->i_attr_sel[graph] == NULL) return __first_attr(item, graph); attr = item->i_attr_sel[graph]; hash = attr_hash(attr->a_def->ad_id); next = attr->a_next; if (next == NULL) hash++; for (; hash < ATTR_HASH_MAX; hash++) { if (next) { attr = next; next = NULL; } else attr = item->i_attrs[hash]; for (; attr; attr = attr->a_next) { if (!(attr->a_flags & ATTR_FLAG_HISTORY)) continue; item->i_attr_sel[graph] = attr; return 0; } } return __first_attr(item, graph); } struct attr *attr_current(struct item *item, int graph) { if (item->i_attr_sel[graph] == NULL) __first_attr(item, graph); return item->i_attr_sel[graph]; } int attr_first(void) { struct item *item = item_current(); if (item == NULL) return EMPTY_LIST; return __first_attr(item, item->i_graph_sel); } int attr_next(void) { struct item *item = item_current(); if (item == NULL) return EMPTY_LIST; return __next_attr(item, item->i_graph_sel); } #endif static float __calc_usage(double rate, uint64_t max) { if (!max) return FLT_MAX; if (!rate) return 0.0f; return 100.0f / ((double) max / (rate * cfg_rate_interval)); } 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) { if (a->a_def->ad_type == ATTR_TYPE_PERCENT) { *rx = a->a_rx_rate.r_total; *tx = a->a_tx_rate.r_total; } else { *rx = __calc_usage(a->a_rx_rate.r_rate, rxmax); *tx = __calc_usage(a->a_tx_rate.r_rate, txmax); } } static void calc_counter_rate(struct attr *a, struct rate *rate, timestamp_t *ts) { uint64_t delta, prev_total; float diff, old_rate; if (rate->r_current < rate->r_prev) { /* Overflow detected */ if (a->a_flags & ATTR_IGNORE_OVERFLOWS) delta = rate->r_current; else { if (a->a_flags & ATTR_TRUE_64BIT) delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev; else delta = 0xFFFFFFFFULL - rate->r_prev; delta += rate->r_current + 1; } } else delta = rate->r_current - rate->r_prev; prev_total = rate->r_total; rate->r_total += delta; rate->r_prev = rate->r_current; if (!prev_total) { /* * No previous records exists, reset time to now to * avoid doing unnecessary calculation, this behaviour * continues as long as the counter stays 0. */ goto out; } diff = timestamp_diff(&rate->r_last_calc, ts); if (diff < (cfg_rate_interval - cfg_rate_variance)) return; old_rate = rate->r_rate; if (rate->r_total < prev_total) { /* overflow */ delta = 0xFFFFFFFFFFFFFFFFULL - prev_total; delta += rate->r_total + 1; } else delta = rate->r_total - prev_total; rate->r_rate = delta / diff; if (old_rate) rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f; out: copy_timestamp(&rate->r_last_calc, ts); } static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts) { rate->r_prev = rate->r_rate = rate->r_total = rate->r_current; copy_timestamp(&rate->r_last_calc, ts); } void attr_notify_update(struct attr *a, timestamp_t *ts) { switch (a->a_def->ad_type) { case ATTR_TYPE_RATE: case ATTR_TYPE_PERCENT: calc_rate_total(a, &a->a_rx_rate, ts); calc_rate_total(a, &a->a_tx_rate, ts); break; case ATTR_TYPE_COUNTER: calc_counter_rate(a, &a->a_rx_rate, ts); calc_counter_rate(a, &a->a_tx_rate, ts); break; default: DBG("Attribute update of unknown type"); break; } if (a->a_flags & ATTR_DOING_HISTORY) { struct history *h; DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name); list_for_each_entry(h, &a->a_history_list, h_list) history_update(a, h, ts); } } 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; list_for_each_entry_safe(ad, n, &attr_def_list, ad_list) attr_def_free(ad); } bmon-5.0/src/bmon.c000066400000000000000000000205121525227747100142130ustar00rootroot00000000000000/* * src/bmon.c Bandwidth Monitor * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include int start_time; struct reader_timing rtiming; static char *usage_text = "Usage: bmon [OPTION]...\n" \ "\n" \ "Options:\n" \ "Startup:\n" \ " -i, --input=MODPARM Input module(s)\n" \ " -o, --output=MODPARM Output module(s)\n" \ " -f, --configfile=PATH Alternative path to configuration file\n" \ " -h, --help Show this help text\n" \ " -V, --version Show version\n" \ "\n" \ "Input:\n" \ " -p, --policy=POLICY Element display policy (see below)\n" \ " -a, --show-all Show all elements (even disabled elements)\n" \ " -r, --read-interval=FLOAT Read interval in seconds (float)\n" \ " -R, --rate-interval=FLOAT Rate interval in seconds (float)\n" \ " -s, --sleep-interval=FLOAT Sleep time in seconds (float)\n" \ " -L, --lifetime=LIFETIME Lifetime of an element in seconds (float)\n" \ "\n" \ "Output:\n" \ " -U, --use-si Use SI units\n" \ " -b, --use-bit Display in bits instead of bytes\n" \ "\n" \ "Module configuration:\n" \ " modparm := MODULE:optlist,MODULE:optlist,...\n" \ " optlist := option;option;...\n" \ " option := TYPE[=VALUE]\n" \ "\n" \ " Examples:\n" \ " -o curses:ngraph=2\n" \ " -o list # Shows a list of available modules\n" \ " -o curses:help # Shows a help text for 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(8) man pages for full documentation.\n"; static void do_shutdown(void) { static int done; if (!done) { done = 1; module_shutdown(); } } static void sig_exit(void) { do_shutdown(); } void quit(const char *fmt, ...) { static int done; va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); if (!done) { done = 1; do_shutdown(); } exit(1); } static inline void print_version(void) { printf("bmon %s\n", PACKAGE_VERSION); printf("Copyright (C) 2001-2015 by Thomas Graf \n"); printf("Copyright (C) 2013 Red Hat, Inc.\n"); printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \ "software, and you\nare welcome to redistribute it under " \ "certain conditions. See the source\ncode for details.\n"); } static void parse_args_pre(int argc, char *argv[]) { DBG("Parsing arguments pre state"); for (;;) { char *gostr = "+:hvVf:"; struct option long_opts[] = { {"help", 0, 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) break; switch (c) { case 'f': set_configfile(optarg); break; case 'h': print_version(); printf("\n%s", usage_text); exit(1); case 'V': case 'v': print_version(); exit(0); } } } static int parse_args_post(int argc, char *argv[]) { DBG("Parsing arguments post state"); optind = 1; for (;;) { char *gostr = "i:o:p:r:R:s:aUb" \ "L:hvVf:"; struct option long_opts[] = { {"input", 1, 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) break; switch (c) { case 'i': if (input_set(optarg, false)) return 1; break; case 'o': if (output_set(optarg)) return 1; break; case 'p': cfg_setstr(cfg, "policy", optarg); break; case 'r': cfg_setfloat(cfg, "read_interval", strtod(optarg, NULL)); break; case 'R': cfg_setfloat(cfg, "rate_interval", strtod(optarg, NULL)); break; case 's': cfg_setint(cfg, "sleep_time", strtoul(optarg, NULL, 0)); break; case 'a': cfg_setbool(cfg, "show_all", cfg_true); break; case 'U': cfg_setbool(cfg, "use_si", cfg_true); break; case 'b': cfg_setbool(cfg, "use_bit", cfg_true); break; case 'L': cfg_setint(cfg, "lifetime", strtoul(optarg, NULL, 0)); break; case 'f': /* Already handled in pre getopt loop */ break; default: quit("Aborting...\n"); break; } } return 0; } #if 0 static void calc_variance(timestamp_t *c, timestamp_t *ri) { float v = (ts_to_float(c) / ts_to_float(ri)) * 100.0f; rtiming.rt_variance.v_error = v; rtiming.rt_variance.v_total += v; if (v > rtiming.rt_variance.v_max) rtiming.rt_variance.v_max = v; if (v < rtiming.rt_variance.v_min) rtiming.rt_variance.v_min = v; } #endif int main(int argc, char *argv[]) { unsigned long sleep_time; double read_interval; start_time = time(NULL); memset(&rtiming, 0, sizeof(rtiming)); rtiming.rt_variance.v_min = FLT_MAX; /* * Early initialization before reading config */ conf_init_pre(); parse_args_pre(argc, argv); /* * Reading the configuration file */ configfile_read(); /* * Late initialization after reading config */ if (parse_args_post(argc, argv)) return 1; conf_init_post(); module_init(); read_interval = cfg_read_interval; sleep_time = cfg_getint(cfg, "sleep_time"); if (((double) sleep_time / 1000000.0f) > read_interval) sleep_time = (unsigned long) (read_interval * 1000000.0f); DBG("Entering mainloop..."); do { /* * E := Elapsed time * NR := Next Read * LR := Last Read * RI := Read Interval * ST := Sleep Time * C := Correction */ timestamp_t e, ri, tmp; unsigned long st; float_to_timestamp(&ri, read_interval); /* * NR := NOW */ update_timestamp(&rtiming.rt_next_read); for (;;) { output_pre(); /* * E := NOW */ update_timestamp(&e); /* * IF NR <= E THEN */ if (timestamp_le(&rtiming.rt_next_read, &e)) { timestamp_t c; /* * C := (NR - E) */ timestamp_sub(&c, &rtiming.rt_next_read, &e); //calc_variance(&c, &ri); /* * LR := E */ copy_timestamp(&rtiming.rt_last_read, &e); /* * NR := E + RI + C */ timestamp_add(&rtiming.rt_next_read, &e, &ri); timestamp_add(&rtiming.rt_next_read, &rtiming.rt_next_read, &c); reset_update_flags(); input_read(); free_unused_elements(); output_draw(); output_post(); } /* * ST := Configured ST */ st = sleep_time; /* * IF (NR - E) < ST THEN */ timestamp_sub(&tmp, &rtiming.rt_next_read, &e); if (tmp.tv_sec < 0) continue; if (tmp.tv_sec == 0 && tmp.tv_usec < st) { if (tmp.tv_usec < 0) continue; /* * ST := (NR - E) */ st = tmp.tv_usec; } /* * SLEEP(ST) */ usleep(st); } } while (0); return 0; /* buddha says i'll never be reached */ } static void __init bmon_init(void) { atexit(&sig_exit); } bmon-5.0/src/conf.c000066400000000000000000000371501525227747100142130ustar00rootroot00000000000000/* * conf.c Config Crap * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include cfg_t *cfg; static cfg_opt_t element_opts[] = { CFG_STR("description", NULL, CFGF_NONE), CFG_BOOL("show", cfg_true, CFGF_NONE), CFG_INT("rxmax", 0, CFGF_NONE), CFG_INT("txmax", 0, CFGF_NONE), CFG_INT("max", 0, CFGF_NONE), CFG_END() }; static cfg_opt_t history_opts[] = { CFG_FLOAT("interval", 1.0f, CFGF_NONE), CFG_INT("size", 60, CFGF_NONE), CFG_STR("type", "64bit", CFGF_NONE), CFG_END() }; static cfg_opt_t attr_opts[] = { CFG_STR("description", "", CFGF_NONE), CFG_STR("unit", "", CFGF_NONE), CFG_STR("type", "counter", CFGF_NONE), CFG_BOOL("history", cfg_false, CFGF_NONE), CFG_END() }; static cfg_opt_t variant_opts[] = { CFG_FLOAT_LIST("div", "{}", CFGF_NONE), CFG_STR_LIST("txt", "", CFGF_NONE), CFG_END() }; static cfg_opt_t unit_opts[] = { CFG_SEC("variant", variant_opts, CFGF_MULTI | CFGF_TITLE), CFG_END() }; static cfg_opt_t 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), CFG_FLOAT("lifetime", 30.0f, CFGF_NONE), CFG_FLOAT("history_variance", 0.1f, CFGF_NONE), CFG_FLOAT("variance", 0.1f, CFGF_NONE), CFG_BOOL("show_all", cfg_false, CFGF_NONE), CFG_INT("unit_exp", -1, CFGF_NONE), CFG_INT("sleep_time", 20000UL, CFGF_NONE), CFG_BOOL("use_si", 0, CFGF_NONE), CFG_BOOL("use_bit", 0, CFGF_NONE), CFG_STR("uid", NULL, CFGF_NONE), CFG_STR("gid", NULL, CFGF_NONE), CFG_STR("policy", "", CFGF_NONE), CFG_SEC("unit", unit_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC("attr", attr_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC("history", history_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC("element", element_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC("layout", layout_opts, CFGF_MULTI | CFGF_TITLE), CFG_END() }; float cfg_read_interval; float cfg_rate_interval; float cfg_rate_variance; float cfg_history_variance; int cfg_show_all; int cfg_unit_exp = DYNAMIC_EXP; static char * configfile = NULL; #if defined HAVE_CURSES #if defined HAVE_USE_DEFAULT_COLORS struct layout cfg_layout[] = { {-1, -1, 0}, /* dummy, not used */ {-1, -1, 0}, /* default */ {-1, -1, A_REVERSE}, /* statusbar */ {-1, -1, 0}, /* header */ {-1, -1, 0}, /* list */ {-1, -1, A_REVERSE}, /* selected */ {-1, -1, 0}, /* RX graph */ {-1, -1, 0}, /* TX graph */ }; #else struct layout cfg_layout[] = { {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 tv_t * parse_tv(char *data) { char *value; tv_t *tv = xcalloc(1, sizeof(tv_t)); init_list_head(&tv->tv_list); value = strchr(data, '='); if (value) { *value = '\0'; ++value; tv->tv_value = xstrdup(value); } tv->tv_type = xstrdup(data); return tv; } module_conf_t * parse_module(char *data) { char *name = data, *opts = data, *next; module_conf_t *m; if (!*name) quit("No module name given"); m = xcalloc(1, sizeof(module_conf_t)); init_list_head(&m->m_attrs); opts = strchr(data, ':'); if (opts) { *opts = '\0'; opts++; do { tv_t *tv; next = strchr(opts, ';'); if (next) { *next = '\0'; ++next; } tv = parse_tv(opts); list_add_tail(&tv->tv_list, &m->m_attrs); opts = next; } while(next); } m->m_name = xstrdup(name); return m; } int parse_module_param(const char *data, struct list_head *list) { char *buf = xstrdup(data); char *next; char *current = buf; module_conf_t *m; int n = 0; do { next = strchr(current, ','); if (next) { *next = '\0'; ++next; } m = parse_module(current); if (m) { list_add_tail(&m->m_list, list); n++; } current = next; } while (next); xfree(buf); return n; } static void configfile_read_history(void) { int i, nhistory; nhistory = cfg_size(cfg, "history"); for (i = 0; i < nhistory; i++) { struct history_def *def; cfg_t *history; const char *name, *type; float interval; int size; if (!(history = cfg_getnsec(cfg, "history", i))) BUG(); if (!(name = cfg_title(history))) BUG(); interval = cfg_getfloat(history, "interval"); size = cfg_getint(history, "size"); type = cfg_getstr(history, "type"); if (interval == 0.0f) interval = cfg_getfloat(cfg, "read_interval"); def = history_def_alloc(name); def->hd_interval = interval; def->hd_size = size; if (!strcasecmp(type, "8bit")) def->hd_type = HISTORY_TYPE_8; else if (!strcasecmp(type, "16bit")) def->hd_type = HISTORY_TYPE_16; else if (!strcasecmp(type, "32bit")) def->hd_type = HISTORY_TYPE_32; else if (!strcasecmp(type, "64bit")) def->hd_type = HISTORY_TYPE_64; else quit("Invalid type \'%s\', must be \"(8|16|32|64)bit\"" " in history definition #%d\n", type, i+1); } } static void configfile_read_element_cfg(void) { int i, nelement; nelement = cfg_size(cfg, "element"); for (i = 0; i < nelement; i++) { struct element_cfg *ec; cfg_t *element; const char *name, *description; long max; if (!(element = cfg_getnsec(cfg, "element", i))) BUG(); if (!(name = cfg_title(element))) BUG(); ec = element_cfg_alloc(name); if ((description = cfg_getstr(element, "description"))) ec->ec_description = xstrdup(description); if ((max = cfg_getint(element, "max"))) ec->ec_rxmax = ec->ec_txmax = max; if ((max = cfg_getint(element, "rxmax"))) ec->ec_rxmax = max; if ((max = cfg_getint(element, "txmax"))) ec->ec_txmax = max; if (cfg_getbool(element, "show")) ec->ec_flags |= ELEMENT_CFG_SHOW; else ec->ec_flags |= ELEMENT_CFG_HIDE; } } static void add_div(struct unit *unit, int type, cfg_t *variant) { int ndiv, n, ntxt; if (!(ndiv = cfg_size(variant, "div"))) return; ntxt = cfg_size(variant, "txt"); if (ntxt != ndiv) quit("Number of elements for div and txt not equal\n"); if (!list_empty(&unit->u_div[type])) { struct fraction *f, *n; list_for_each_entry_safe(f, n, &unit->u_div[type], f_list) fraction_free(f); } for (n = 0; n < ndiv; n++) { char *txt; float div; div = cfg_getnfloat(variant, "div", n); txt = cfg_getnstr(variant, "txt", n); unit_add_div(unit, type, txt, div); } } static void configfile_read_units(void) { int i, nunits; struct unit *u; nunits = cfg_size(cfg, "unit"); for (i = 0; i < nunits; i++) { int nvariants, n; cfg_t *unit; const char *name; if (!(unit = cfg_getnsec(cfg, "unit", i))) BUG(); if (!(name = cfg_title(unit))) BUG(); if (!(nvariants = cfg_size(unit, "variant"))) continue; if (!(u = unit_add(name))) continue; for (n = 0; n < nvariants; n++) { cfg_t *variant; const char *vtitle; if (!(variant = cfg_getnsec(unit, "variant", n))) BUG(); if (!(vtitle = cfg_title(variant))) BUG(); if (!strcasecmp(vtitle, "default")) add_div(u, UNIT_DEFAULT, variant); else if (!strcasecmp(vtitle, "si")) add_div(u, UNIT_SI, variant); else if (!strcasecmp(vtitle, "bit")) add_div(u, UNIT_BIT, variant); else quit("Unknown unit variant \'%s\'\n", vtitle); } } } static void configfile_read_attrs(void) { int i, nattrs, t = 0; nattrs = cfg_size(cfg, "attr"); for (i = 0; i < nattrs; i++) { struct unit *u; cfg_t *attr; const char *name, *description, *unit, *type; int flags = 0; if (!(attr = cfg_getnsec(cfg, "attr", i))) BUG(); if (!(name = cfg_title(attr))) BUG(); description = cfg_getstr(attr, "description"); unit = cfg_getstr(attr, "unit"); type = cfg_getstr(attr, "type"); if (!unit) quit("Attribute '%s' is missing unit specification\n", name); if (!type) quit("Attribute '%s' is missing type specification\n", name); if (!(u = unit_lookup(unit))) quit("Unknown unit \'%s\' attribute '%s'\n", unit, name); if (!strcasecmp(type, "counter")) t = ATTR_TYPE_COUNTER; else if (!strcasecmp(type, "rate")) t = ATTR_TYPE_RATE; else if (!strcasecmp(type, "percent")) t = ATTR_TYPE_PERCENT; else quit("Unknown type \'%s\' in attribute '%s'\n", type, name); if (cfg_getbool(attr, "history")) flags |= ATTR_FORCE_HISTORY; if (cfg_getbool(attr, "ignore_overflows")) flags |= ATTR_IGNORE_OVERFLOWS; attr_def_add(name, description, u, t, flags); } } static void 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; DBG("Reading configfile %s...", path); if (access(path, R_OK) != 0) { if (must) quit("Error: Unable to read configfile \"%s\": %s\n", path, strerror(errno)); else return; } err = cfg_parse(cfg, path); if (err == CFG_FILE_ERROR) { quit("Error while reading configfile \"%s\": %s\n", path, strerror(errno)); } else if (err == CFG_PARSE_ERROR) { quit("Error while reading configfile \"%s\": parse error\n", path); } configfile_read_units(); configfile_read_history(); configfile_read_attrs(); configfile_read_element_cfg(); configfile_read_layout_cfg(); } static const char default_config[] = \ "unit byte {" \ " variant default {" \ " div = { 1, 1024, 1048576, 1073741824, 1099511627776}" \ " txt = { \"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\" }" \ " }" \ " variant si {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"B\", \"KB\", \"MB\", \"GB\", \"TB\" }" \ " }" \ " variant bit {" \ " div = { 0.125, 125, 125000, 125000000, 125000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " }" \ "unit bit {" \ " variant default {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " variant si {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ " variant bit {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ " }" \ "}" \ "unit number {" \ " variant default {" \ " div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ " txt = { \"\", \"K\", \"M\", \"G\", \"T\" }" \ " }" \ "}" \ "unit percent {" \ " variant default {" \ " div = { 1. }" \ " txt = { \"%\" }" \ " }" \ "}" \ "history second {" \ " interval = 1.0" \ " size = 60" \ "}" \ "history minute {" \ " interval = 60.0" \ " size = 60" \ "}" \ "history hour {" \ " interval = 3600.0" \ " size = 60" \ "}" \ "history day {" \ " interval = 86400.0" \ " size = 60" \ "}" "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) { int err; DBG("Reading default config"); err = cfg_parse_buf(cfg, default_config); if (err) quit("Error while parsing default config\n"); configfile_read_units(); configfile_read_history(); configfile_read_attrs(); configfile_read_element_cfg(); configfile_read_layout_cfg(); } void configfile_read(void) { if (configfile) conf_read(configfile, 1); else { conf_read(SYSCONFDIR "/bmon.conf", 0); if (getenv("HOME")) { char path[FILENAME_MAX+1]; snprintf(path, sizeof(path), "%s/.bmonrc", getenv("HOME")); conf_read(path, 0); } } } void conf_init_pre(void) { conf_read_default(); } void conf_init_post(void) { cfg_read_interval = cfg_getfloat(cfg, "read_interval"); cfg_rate_interval = cfg_getfloat(cfg, "rate_interval"); cfg_rate_variance = cfg_getfloat(cfg, "variance") * cfg_rate_interval; cfg_history_variance = cfg_getfloat(cfg, "history_variance"); cfg_show_all = cfg_getbool(cfg, "show_all"); cfg_unit_exp = cfg_getint(cfg, "unit_exp"); element_parse_policy(cfg_getstr(cfg, "policy")); } void set_configfile(const char *file) { static int set = 0; if (!set) { configfile = xstrdup(file); set = 1; } } void set_unit_exp(const char *name) { if (tolower(*name) == 'b') cfg_setint(cfg, "unit_exp", 0); else if (tolower(*name) == 'k') cfg_setint(cfg, "unit_exp", 1); else if (tolower(*name) == 'm') cfg_setint(cfg, "unit_exp", 2); else if (tolower(*name) == 'g') cfg_setint(cfg, "unit_exp", 3); else if (tolower(*name) == 't') cfg_setint(cfg, "unit_exp", 4); else if (tolower(*name) == 'd') cfg_setint(cfg, "unit_exp", DYNAMIC_EXP); else quit("Unknown unit exponent '%s'\n", name); } unsigned int get_lifecycles(void) { return (unsigned int) (cfg_getfloat(cfg, "lifetime") / cfg_getfloat(cfg, "read_interval")); } static void __exit conf_shutdown(void) { cfg_free(cfg); } static void __init __conf_init(void) { DBG("init"); cfg = cfg_init(global_opts, CFGF_NOCASE); /* FIXME: Add validation functions */ //cfg_set_validate_func(cfg, "bookmark", &cb_validate_bookmark); } bmon-5.0/src/element.c000066400000000000000000000273721525227747100147240ustar00rootroot00000000000000/* * src/element.c Elements * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include static LIST_HEAD(allowed); static LIST_HEAD(denied); static int match_mask(const struct policy *p, const char *str) { int i, n; char c; if (!p || !str) return 0; for (i = 0, n = 0; p->p_rule[i] != '\0'; i++) { if (p->p_rule[i] == '*') { c = tolower(p->p_rule[i + 1]); if (c == '\0') return 1; while (tolower(str[n]) != c) if (str[n++] == '\0') return 0; } else if (tolower(p->p_rule[i]) != tolower(str[n++])) return 0; } return str[n] == '\0' ? 1 : 0; } int element_allowed(const char *name, struct element_cfg *cfg) { struct policy *p; if (cfg) { if (cfg->ec_flags & ELEMENT_CFG_HIDE) return 0; else if (cfg->ec_flags & ELEMENT_CFG_SHOW) return 1; } list_for_each_entry(p, &denied, p_list) if (match_mask(p, name)) return 0; if (!list_empty(&allowed)) { list_for_each_entry(p, &allowed, p_list) if (match_mask(p, name)) return 1; return 0; } return 1; } void element_parse_policy(const char *policy) { char *start, *copy, *save = NULL, *tok; struct policy *p; if (!policy) return; copy = xstrdup(policy); start = copy; while ((tok = strtok_r(start, ",", &save)) != NULL) { start = NULL; p = xcalloc(1, sizeof(*p)); if (*tok == '!') { p->p_rule = xstrdup(++tok); list_add_tail(&p->p_list, &denied); } else { p->p_rule = xstrdup(tok); list_add_tail(&p->p_list, &allowed); } } xfree(copy); } 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; if (parent) list = &parent->e_childs; else list = &group->g_elements; list_for_each_entry(e, list, e_list) if (!strcmp(name, e->e_name) && e->e_id == id) return e; return NULL; } struct element *element_lookup(struct element_group *group, const char *name, uint32_t id, struct element *parent, int flags) { struct element_cfg *cfg; struct element *e; int i; if (!group) BUG(); if ((e = __lookup_element(group, name, id, parent))) return e; if (!(flags & ELEMENT_CREAT)) return NULL; cfg = element_cfg_lookup(name); if (!element_allowed(name, cfg)) return NULL; DBG("Creating element %d \"%s\"", id, name); e = xcalloc(1, sizeof(*e)); init_list_head(&e->e_list); init_list_head(&e->e_childs); init_list_head(&e->e_info_list); init_list_head(&e->e_attr_sorted); for (i = 0; i < ATTR_HASH_SIZE; i++) init_list_head(&e->e_attrhash[i]); e->e_name = xstrdup(name); e->e_id = id; e->e_parent = parent; e->e_group = group; e->e_lifecycles = get_lifecycles(); e->e_flags = ELEMENT_FLAG_CREATED; e->e_cfg = cfg; if (e->e_cfg) { if (e->e_cfg->ec_description) element_update_info(e, "Description", e->e_cfg->ec_description); element_set_rxmax(e, e->e_cfg->ec_rxmax); element_set_txmax(e, e->e_cfg->ec_txmax); } if (parent) { DBG("Attached to parent %d \"%s\"", parent->e_id, parent->e_name); list_add_tail(&e->e_list, &parent->e_childs); } else { DBG("Attached to group %s", group->g_name); list_add_tail(&e->e_list, &group->g_elements); } group->g_nelements++; return e; } void element_free(struct element *e) { struct info *info, *ninfo; struct element *c, *cnext; struct attr *a, *an; int i; list_for_each_entry_safe(c, cnext, &e->e_childs, e_list) element_free(c); list_for_each_entry_safe(info, ninfo, &e->e_info_list, i_list) { xfree(info->i_name); xfree(info->i_value); list_del(&info->i_list); xfree(info); } for (i = 0; i < ATTR_HASH_SIZE; i++) list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list) attr_free(a); if (e->e_group->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--; xfree(e->e_name); xfree(e); } #if 0 if (item->i_group->g_selected == item) { if (item_select_prev() == END_OF_LIST) { if (group_select_prev() == END_OF_LIST) { if (node_select_prev() != END_OF_LIST) item_select_last(); } else item_select_last(); } } #endif #if 0 void item_delete(struct item *item) { int m; struct item *child; for (m = 0; m < ATTR_HASH_MAX; m++) { struct attr *a, *next; for (a = item->i_attrs[m]; a; a = next) { next = a->a_next; xfree(a); } } if (item->i_group->g_selected == item) { if (item_select_prev() == END_OF_LIST) { if (group_select_prev() == END_OF_LIST) { if (node_select_prev() != END_OF_LIST) item_select_last(); } else item_select_last(); } } unlink_item(item); item->i_group->g_nitems--; for (child = item->i_childs; child; child = child->i_next) item_delete(child); if (item->i_path) xfree(item->i_path); xfree(item); } #endif void element_reset_update_flag(struct element_group *g, struct element *e, void *arg) { DBG("Reseting update flag of %s", e->e_name); e->e_flags &= ~ELEMENT_FLAG_UPDATED; } /** * Needs to be called after updating all attributes of an element */ void element_notify_update(struct element *e, timestamp_t *ts) { struct attr *a; int i; e->e_flags |= ELEMENT_FLAG_UPDATED; if (ts == NULL) ts = &rtiming.rt_last_read; for (i = 0; i < ATTR_HASH_SIZE; i++) list_for_each_entry(a, &e->e_attrhash[i], a_list) attr_notify_update(a, ts); if (e->e_usage_attr && e->e_cfg && (a = attr_lookup(e, e->e_usage_attr->ad_id))) { attr_calc_usage(a, &e->e_rx_usage, &e->e_tx_usage, e->e_cfg->ec_rxmax, e->e_cfg->ec_txmax); } else { e->e_rx_usage = FLT_MAX; e->e_tx_usage = FLT_MAX; } } void element_lifesign(struct element *e, int n) { e->e_lifecycles = n * get_lifecycles(); } void element_check_if_dead(struct element_group *g, struct element *e, void *arg) { if (--(e->e_lifecycles) <= 0) { DBG("Deleting dead element %s", e->e_name); element_free(e); } } void element_foreach_attr(struct element *e, void (*cb)(struct element *e, struct attr *, void *), void *arg) { struct attr *a; list_for_each_entry(a, &e->e_attr_sorted, a_sort_list) cb(e, a, arg); } int element_set_key_attr(struct element *e, const char *major, const char * minor) { if (!(e->e_key_attr[GT_MAJOR] = attr_def_lookup(major))) return -ENOENT; if (!(e->e_key_attr[GT_MINOR] = attr_def_lookup(minor))) return -ENOENT; return 0; } int element_set_usage_attr(struct element *e, const char *usage) { if (!(e->e_usage_attr = attr_def_lookup(usage))) return -ENOENT; return 0; } 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; 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_pick_from_policy(g); return g->g_current; } struct element *element_select_first(void) { struct element_group *g; if (!(g = group_current())) return NULL; if (list_empty(&g->g_elements)) g->g_current = NULL; else g->g_current = list_first_entry(&g->g_elements, struct element, e_list); return g->g_current; } struct element *element_select_last(void) { struct element_group *g; if (!(g = group_current())) return NULL; if (list_empty(&g->g_elements)) g->g_current = NULL; else { struct element *e; e = list_entry(g->g_elements.prev, struct element, e_list); while (!list_empty(&e->e_childs)) e = list_entry(e->e_childs.prev, struct element, e_list); g->g_current = e; } return g->g_current; } struct element *element_select_next(void) { struct element_group *g; struct element *e; if (!(g = group_current())) return NULL; if (!(e = g->g_current)) return element_select_first(); if (!list_empty(&e->e_childs)) e = list_first_entry(&e->e_childs, struct element, e_list); else { /* * move upwards until we have no parent or there is a next * entry in the list */ while (e->e_parent && e->e_list.next == &e->e_parent->e_childs) e = e->e_parent; if (!e->e_parent && e->e_list.next == &g->g_elements) { group_select_next(); return element_select_first(); } else e = list_entry(e->e_list.next, struct element, e_list); } g->g_current = e; return e; } struct element *element_select_prev(void) { struct element_group *g; struct element *e; if (!(g = group_current())) return NULL; if (!(e = g->g_current)) return element_select_last(); if (!e->e_parent && e->e_list.prev == &g->g_elements) { group_select_prev(); return element_select_last(); } if (e->e_parent && e->e_list.prev == &e->e_parent->e_childs) e = e->e_parent; else { e = list_entry(e->e_list.prev, struct element, e_list); while (!list_empty(&e->e_childs)) e = list_entry(e->e_childs.prev, struct element, e_list); } g->g_current = e; return e; } static struct info *element_info_lookup(struct element *e, const char *name) { struct info *i; list_for_each_entry(i, &e->e_info_list, i_list) if (!strcmp(i->i_name, name)) return i; return NULL; } void element_update_info(struct element *e, const char *name, const char *value) { struct info *i; if ((i = element_info_lookup(e, name))) { xfree(i->i_value); i->i_value = xstrdup(value); return; } DBG("Created element info %s (\"%s\")", name, value); i = xcalloc(1, sizeof(*i)); i->i_name = xstrdup(name); i->i_value = xstrdup(value); e->e_ninfo++; list_add_tail(&i->i_list, &e->e_info_list); } void element_delete_info(struct element *e, const char *name) { struct info *i; if (!(i = element_info_lookup(e, name))) return; xfree(i->i_name); xfree(i->i_value); list_del(&i->i_list); xfree(i); if (e->e_ninfo > 0) e->e_ninfo--; } void element_set_txmax(struct element *e, uint64_t max) { char buf[32]; if (!e->e_cfg) e->e_cfg = element_cfg_create(e->e_name); if (e->e_cfg->ec_txmax != max) e->e_cfg->ec_txmax = max; unit_bit2str(e->e_cfg->ec_txmax * 8, buf, sizeof(buf)); element_update_info(e, "TxMax", buf); } void element_set_rxmax(struct element *e, uint64_t max) { char buf[32]; if (!e->e_cfg) e->e_cfg = element_cfg_create(e->e_name); if (e->e_cfg->ec_rxmax != max) e->e_cfg->ec_rxmax = max; unit_bit2str(e->e_cfg->ec_rxmax * 8, buf, sizeof(buf)); element_update_info(e, "RxMax", buf); } bmon-5.0/src/element_cfg.c000066400000000000000000000046421525227747100155360ustar00rootroot00000000000000/* * element_cfg.c Element Configuration * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include static LIST_HEAD(cfg_list); struct element_cfg *element_cfg_alloc(const char *name) { struct element_cfg *ec; if ((ec = element_cfg_lookup(name))) { ec->ec_refcnt++; return ec; } ec = xcalloc(1, sizeof(*ec)); ec->ec_name = xstrdup(name); ec->ec_refcnt = 1; list_add_tail(&ec->ec_list, &cfg_list); return ec; } struct element_cfg *element_cfg_create(const char *name) { struct element_cfg *cfg; if (!(cfg = element_cfg_lookup(name))) cfg = element_cfg_alloc(name); return cfg; } static void __element_cfg_free(struct element_cfg *ec) { list_del(&ec->ec_list); xfree(ec->ec_name); xfree(ec->ec_description); xfree(ec); } void element_cfg_free(struct element_cfg *ec) { if (!ec || --ec->ec_refcnt) return; __element_cfg_free(ec); } struct element_cfg *element_cfg_lookup(const char *name) { struct element_cfg *ec; list_for_each_entry(ec, &cfg_list, ec_list) if (!strcmp(name, ec->ec_name)) return ec; return NULL; } static void __exit __element_cfg_exit(void) { struct element_cfg *ec, *n; list_for_each_entry_safe(ec, n, &cfg_list, ec_list) __element_cfg_free(ec); } bmon-5.0/src/graph.c000066400000000000000000000215511525227747100143650ustar00rootroot00000000000000/* * graph.c Graph creation utility * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #define GRAPH_BRAILLE_ROWS 4 static inline size_t graph_cell_size(struct graph_cfg *cfg) { return (cfg->gc_flags & GRAPH_CFG_BRAILLE) ? GRAPH_BRAILLE_CELL_BYTES : 1; } size_t graph_row_size(struct graph_cfg *cfg) { /* +1 for trailing \0 */ return (cfg->gc_width * graph_cell_size(cfg)) + 1; } static inline size_t table_size(struct graph_cfg *cfg) { return cfg->gc_height * graph_row_size(cfg); } static inline char *at_row(struct graph_cfg *cfg, char *col, int nrow) { return col + (nrow * graph_row_size(cfg)); } static inline char *at_col(struct graph_cfg *cfg, char *row, int ncol) { return row + (ncol * graph_cell_size(cfg)); } static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol) { return at_col(cfg, at_row(cfg, tbl, nrow), ncol); } static int history_index_at(struct history *h, int ncol) { int n = h->h_index - 1 - ncol; while (n < 0) n += h->h_definition->hd_size; return n; } static uint64_t graph_data_at(struct history *h, struct history_store *data, int ncol) { return history_data(h, data, history_index_at(h, ncol)); } static void put_braille(char *pos, unsigned char dots) { unsigned int cp = 0x2800 + dots; pos[0] = (char) (0xe0 | (cp >> 12)); pos[1] = (char) (0x80 | ((cp >> 6) & 0x3f)); pos[2] = (char) (0x80 | (cp & 0x3f)); } static unsigned char braille_dot_bit(int x, int y) { static const unsigned char bits[2][GRAPH_BRAILLE_ROWS] = { { 0x40, 0x04, 0x02, 0x01 }, { 0x80, 0x20, 0x10, 0x08 }, }; return bits[x][y]; } static void braille_plot_value(struct graph_cfg *cfg, unsigned char *dots, int ncol, int x, double v, double step) { int i, ndots; int maxdots = cfg->gc_height * GRAPH_BRAILLE_ROWS; if (v <= 0.0f || step <= 0.0f) return; ndots = (int) ((v / step) + 0.5f); if (ndots < 1) ndots = 1; if (ndots > maxdots) ndots = maxdots; for (i = 0; i < ndots; i++) { int nrow = i / GRAPH_BRAILLE_ROWS; int y = i % GRAPH_BRAILLE_ROWS; dots[(nrow * cfg->gc_width) + ncol] |= braille_dot_bit(x, y); } } static void fill_braille_unknown(struct graph_cfg *cfg, unsigned char *dots, int ncol) { int i; for (i = 0; i < cfg->gc_height; i++) dots[(i * cfg->gc_width) + ncol] = 0xff; } static void render_braille_table(struct graph_cfg *cfg, char *tbl, unsigned char *dots) { int i, n; for (i = 0; i < cfg->gc_height; i++) { for (n = 0; n < cfg->gc_width; n++) put_braille(tbl_pos(cfg, tbl, i, n), dots[(i * cfg->gc_width) + n]); *tbl_pos(cfg, tbl, i, cfg->gc_width) = '\0'; } } static void fill_braille_table(struct graph *g, struct graph_table *tbl, struct history *h, struct history_store *data) { struct graph_cfg *cfg = &g->g_cfg; uint64_t max = 0; unsigned char *dots; double step, dot_step, divisor; int i, n; if (!tbl->gt_table) { tbl->gt_table = xcalloc(table_size(cfg), sizeof(char)); tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double)); } dots = xcalloc(cfg->gc_height * cfg->gc_width, sizeof(*dots)); /* leave table blank if there is no data */ if (!h || !data->hs_data) { render_braille_table(cfg, tbl->gt_table, dots); xfree(dots); return; } if (cfg->gc_width > h->h_definition->hd_size) BUG(); /* find the largest peak */ for (i = 0; i < cfg->gc_width; i++) { uint64_t v = graph_data_at(h, data, i); if (v != HISTORY_UNKNOWN && max < v) max = v; } step = (double) max / (double) cfg->gc_height; dot_step = step / (double) GRAPH_BRAILLE_ROWS; for (i = 0; i < cfg->gc_height; i++) tbl->gt_scale[i] = (double) (i + 1) * step; for (i = 0; i < cfg->gc_width; i++) { uint64_t left = graph_data_at(h, data, i); double right; if (left == HISTORY_UNKNOWN) { fill_braille_unknown(cfg, dots, i); continue; } right = (double) left; if (i < (cfg->gc_width - 1)) { uint64_t next = graph_data_at(h, data, i + 1); if (next != HISTORY_UNKNOWN) right = (((double) left) + ((double) next)) / 2.0f; } braille_plot_value(cfg, dots, i, 0, (double) left, dot_step); braille_plot_value(cfg, dots, i, 1, right, dot_step); } render_braille_table(cfg, tbl->gt_table, dots); xfree(dots); n = (cfg->gc_height / 3) * 2; if (n >= cfg->gc_height) n = (cfg->gc_height - 1); divisor = unit_divisor(tbl->gt_scale[n], cfg->gc_unit, &tbl->gt_y_unit, NULL); for (i = 0; i < cfg->gc_height; i++) tbl->gt_scale[i] /= divisor; } static void fill_table(struct graph *g, struct graph_table *tbl, struct history *h, struct history_store *data) { struct graph_cfg *cfg = &g->g_cfg; uint64_t max = 0, hv; double v; int i, n, t; float half_step, step; if (cfg->gc_flags & GRAPH_CFG_BRAILLE) { fill_braille_table(g, tbl, h, data); return; } if (!tbl->gt_table) { tbl->gt_table = xcalloc(table_size(cfg), sizeof(char)); tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double)); } memset(tbl->gt_table, cfg->gc_background, table_size(cfg)); /* end each line with a \0 */ for (i = 0; i < cfg->gc_height; i++) *tbl_pos(cfg, tbl->gt_table, i, cfg->gc_width) = '\0'; /* leave table blank if there is no data */ if (!h || !data->hs_data) return; if (cfg->gc_width > h->h_definition->hd_size) BUG(); /* find the largest peak */ for (n = h->h_index, i = 0; i < cfg->gc_width; i++) { if (--n < 0) n = h->h_definition->hd_size - 1; hv = history_data(h, data, n); if (hv != HISTORY_UNKNOWN && max < hv) max = hv; } step = (double) max / (double) cfg->gc_height; half_step = step / 2.0f; for (i = 0; i < cfg->gc_height; i++) tbl->gt_scale[i] = (double) (i + 1) * step; for (n = h->h_index, i = 0; i < cfg->gc_width; i++) { char * col = at_col(cfg, tbl->gt_table, i); if (--n < 0) n = h->h_definition->hd_size - 1; hv = history_data(h, data, n); if (hv == HISTORY_UNKNOWN) { for (t = 0; t < cfg->gc_height; t++) *(at_row(cfg, col, t)) = cfg->gc_unknown; } else if (hv > 0) { *(at_row(cfg, col, 0)) = cfg->gc_noise; for (t = 0; t < cfg->gc_height; t++) if ((double) hv >= (tbl->gt_scale[t] - half_step)) *(at_row(cfg, col, t)) = cfg->gc_foreground; } } n = (cfg->gc_height / 3) * 2; if (n >= cfg->gc_height) n = (cfg->gc_height - 1); v = unit_divisor(tbl->gt_scale[n], cfg->gc_unit, &tbl->gt_y_unit, NULL); for (i = 0; i < cfg->gc_height; i++) tbl->gt_scale[i] /= v; } struct graph *graph_alloc(struct history *h, struct graph_cfg *cfg) { struct graph *g; if (!cfg->gc_height) BUG(); g = xcalloc(1, sizeof(*g)); memcpy(&g->g_cfg, cfg, sizeof(*cfg)); if (h != NULL && (cfg->gc_width > h->h_definition->hd_size || !cfg->gc_width)) g->g_cfg.gc_width = h->h_definition->hd_size; if (!g->g_cfg.gc_width) BUG(); return g; } void graph_refill(struct graph *g, struct history *h) { fill_table(g, &g->g_rx, h, h ? &h->h_rx : NULL); fill_table(g, &g->g_tx, h, h ? &h->h_tx : NULL); } void graph_free(struct graph *g) { if (!g) return; xfree(g->g_rx.gt_table); xfree(g->g_rx.gt_scale); xfree(g->g_tx.gt_table); xfree(g->g_tx.gt_scale); xfree(g); } #if 0 void new_graph(void) { if (ngraphs >= (MAX_GRAPHS - 1)) return; set_ngraphs_hard(ngraphs + 1); } void del_graph(void) { if (ngraphs <= 1) return; set_ngraphs_hard(ngraphs - 1); } int next_graph(void) { struct item *it = item_current(); if (it == NULL) return EMPTY_LIST; if (it->i_graph_sel >= (ngraphs - 1)) it->i_graph_sel = 0; else it->i_graph_sel++; return 0; } int prev_graph(void) { struct item *it = item_current(); if (it == NULL) return EMPTY_LIST; if (it->i_graph_sel <= 0) it->i_graph_sel = ngraphs - 1; else it->i_graph_sel--; return 0; } #endif bmon-5.0/src/group.c000066400000000000000000000145311525227747100144200ustar00rootroot00000000000000/* * group.c Group Management * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include static LIST_HEAD(titles_list); static LIST_HEAD(group_list); static unsigned int ngroups; static struct element_group *current_group; static void __group_foreach_element(struct element_group *g, struct list_head *list, void (*cb)(struct element_group *, struct element *, void *), void *arg) { struct element *e, *n; list_for_each_entry_safe(e, n, list, e_list) { cb(g, e, arg); if (!list_empty(&e->e_childs)) __group_foreach_element(g, &e->e_childs, cb, arg); } } void group_foreach_element(struct element_group *g, void (*cb)(struct element_group *, struct element *, void *), void *arg) { __group_foreach_element(g, &g->g_elements, cb, arg); } void group_foreach_recursive(void (*cb)(struct element_group *, struct element *, void *), void *arg) { struct element_group *g, *n; list_for_each_entry_safe(g, n, &group_list, g_list) __group_foreach_element(g, &g->g_elements, cb, arg); } void group_foreach(void (*cb)(struct element_group *, void *), void *arg) { struct element_group *g, *n; list_for_each_entry_safe(g, n, &group_list, g_list) cb(g, arg); } struct element_group *group_select_first(void) { if (list_empty(&group_list)) current_group = NULL; else current_group = list_first_entry(&group_list, struct element_group, g_list); return current_group; } struct element_group *group_select_last(void) { if (list_empty(&group_list)) current_group = NULL; else current_group = list_entry(group_list.prev, struct element_group, g_list); return current_group; } struct element_group *group_select_next(void) { if (!current_group) return group_select_first(); if (current_group->g_list.next != &group_list) current_group = list_entry(current_group->g_list.next, struct element_group, g_list); else return group_select_first(); return current_group; } struct element_group *group_select_prev(void) { if (!current_group) return group_select_last(); if (current_group->g_list.prev != &group_list) current_group = list_entry(current_group->g_list.prev, struct element_group, g_list); else return group_select_last(); return current_group; } struct element_group *group_current(void) { if (current_group == NULL) current_group = group_select_first(); return current_group; } struct element_group *group_lookup(const char *name, int flags) { struct element_group *g; struct group_hdr *hdr; list_for_each_entry(g, &group_list, g_list) if (!strcmp(name, g->g_name)) return g; if (!(flags & GROUP_CREATE)) return NULL; if (!(hdr = group_lookup_hdr(name))) { fprintf(stderr, "Cannot find title for group \"%s\"\n", name); return NULL; } g = xcalloc(1, sizeof(*g)); init_list_head(&g->g_elements); g->g_name = hdr->gh_name; g->g_hdr = hdr; list_add_tail(&g->g_list, &group_list); ngroups++; return g; } static void group_free(struct element_group *g) { struct element *e, *n; struct element_group *next; if (current_group == g) { next = group_select_next(); if (!next || next == g) current_group = NULL; } list_for_each_entry_safe(e, n, &g->g_elements, e_list) element_free(e); xfree(g); } void reset_update_flags(void) { group_foreach_recursive(&element_reset_update_flag, NULL); } void free_unused_elements(void) { group_foreach_recursive(&element_check_if_dead, NULL); } struct group_hdr *group_lookup_hdr(const char *name) { struct group_hdr *hdr; list_for_each_entry(hdr, &titles_list, gh_list) if (!strcmp(hdr->gh_name, name)) return hdr; return NULL; } int group_new_hdr(const char *name, const char *title, const char *col1, const char *col2, const char *col3, const char *col4) { struct group_hdr *hdr; if (group_lookup_hdr(name)) return -EEXIST; hdr = xcalloc(1, sizeof(*hdr)); init_list_head(&hdr->gh_list); hdr->gh_name = xstrdup(name); hdr->gh_title = xstrdup(title); hdr->gh_column[0] = xstrdup(col1); hdr->gh_column[1] = xstrdup(col2); hdr->gh_column[2] = xstrdup(col3); hdr->gh_column[3] = xstrdup(col4); list_add_tail(&hdr->gh_list, &titles_list); DBG("New group title %s \"%s\"", name, title); return 0; } int group_new_derived_hdr(const char *name, const char *title, const char *template) { struct group_hdr *t; if (group_lookup_hdr(name)) return -EEXIST; if (!(t = group_lookup_hdr(template))) return -ENOENT; return group_new_hdr(name, title, t->gh_column[0], t->gh_column[1], t->gh_column[2], t->gh_column[3]); } static void group_hdr_free(struct group_hdr *hdr) { xfree(hdr->gh_name); xfree(hdr->gh_title); xfree(hdr->gh_column[0]); xfree(hdr->gh_column[1]); xfree(hdr->gh_column[2]); xfree(hdr->gh_column[3]); xfree(hdr); } static void __init group_init(void) { DBG("init"); group_new_hdr(DEFAULT_GROUP, "Interfaces", "RX bps", "pps", "TX bps", "pps"); } static void __exit group_exit(void) { struct element_group *g, *next; struct group_hdr *hdr, *gnext; list_for_each_entry_safe(g, next, &group_list, g_list) group_free(g); list_for_each_entry_safe(hdr, gnext, &titles_list, gh_list) group_hdr_free(hdr); } bmon-5.0/src/history.c000066400000000000000000000163341525227747100147700ustar00rootroot00000000000000/* * history.c History Management * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include static LIST_HEAD(def_list); static struct history_def *current_history; struct history_def *history_def_lookup(const char *name) { struct history_def *def; list_for_each_entry(def, &def_list, hd_list) if (!strcmp(def->hd_name, name)) return def; return NULL; } struct history_def *history_def_alloc(const char *name) { struct history_def *def; if ((def = history_def_lookup(name))) return def; def = xcalloc(1, sizeof(*def)); def->hd_name = xstrdup(name); list_add_tail(&def->hd_list, &def_list); DBG("New history definition %s", name); return def; } static void history_def_free(struct history_def *def) { if (!def) return; xfree(def->hd_name); xfree(def); } static void *history_alloc_data(struct history_def *def) { return xcalloc(def->hd_size, def->hd_type); } static void history_store_data(struct history *h, struct history_store *hs, uint64_t total, float diff) { uint64_t delta; if (!hs->hs_data) { if (total == HISTORY_UNKNOWN) return; hs->hs_data = history_alloc_data(h->h_definition); } if (total == HISTORY_UNKNOWN) delta = HISTORY_UNKNOWN; else { delta = (total - hs->hs_prev_total); if (delta > 0) delta /= diff; hs->hs_prev_total = total; } switch (h->h_definition->hd_type) { case HISTORY_TYPE_8: ((uint8_t *) hs->hs_data)[h->h_index] = (uint8_t) delta; break; case HISTORY_TYPE_16: ((uint16_t *) hs->hs_data)[h->h_index] = (uint16_t) delta; break; case HISTORY_TYPE_32: ((uint32_t *) hs->hs_data)[h->h_index] = (uint32_t) delta; break; case HISTORY_TYPE_64: ((uint64_t *) hs->hs_data)[h->h_index] = (uint64_t) delta; break; default: BUG(); } } static inline void inc_history_index(struct history *h) { if (h->h_index < (h->h_definition->hd_size - 1)) h->h_index++; else h->h_index = 0; } uint64_t history_data(struct history *h, struct history_store *hs, int index) { switch (h->h_definition->hd_type) { case HISTORY_TYPE_8: { uint8_t v = ((uint8_t *) hs->hs_data)[index]; return (v == (uint8_t) -1) ? HISTORY_UNKNOWN : v; } case HISTORY_TYPE_16: { uint16_t v = ((uint16_t *) hs->hs_data)[index]; return (v == (uint16_t) -1) ? HISTORY_UNKNOWN : v; } case HISTORY_TYPE_32: { uint32_t v = ((uint32_t *) hs->hs_data)[index]; return (v == (uint32_t) -1) ? HISTORY_UNKNOWN : v; } case HISTORY_TYPE_64: { uint64_t v = ((uint64_t *) hs->hs_data)[index]; return (v == (uint64_t) -1) ? HISTORY_UNKNOWN : v; } default: BUG(); } } void history_update(struct attr *a, struct history *h, timestamp_t *ts) { struct history_def *def = h->h_definition; float timediff; if (h->h_last_update.tv_sec) timediff = timestamp_diff(&h->h_last_update, ts); else { timediff = 0.0f; /* initial history update */ /* Need a delta when working with counters */ if (a->a_def->ad_type == ATTR_TYPE_COUNTER) goto update_prev_total; } /* * A read interval greater than the desired history interval * can't possibly result in anything useful. Discard it and * mark history data as invalid. The user has to adjust the * read interval. */ if (cfg_read_interval > def->hd_interval) goto discard; /* * If the history interval matches the read interval it makes * sense to update upon every read. The reader timing already * took care of being as close as possible to the desired * interval. */ if (cfg_read_interval == def->hd_interval) goto update; if (timediff > h->h_max_interval) goto discard; if (timediff < h->h_min_interval) return; update: history_store_data(h, &h->h_rx, a->a_rx_rate.r_total, timediff); history_store_data(h, &h->h_tx, a->a_tx_rate.r_total, timediff); inc_history_index(h); goto update_ts; discard: while(timediff >= (def->hd_interval / 2)) { history_store_data(h, &h->h_rx, HISTORY_UNKNOWN, 0.0f); history_store_data(h, &h->h_tx, HISTORY_UNKNOWN, 0.0f); inc_history_index(h); timediff -= def->hd_interval; } update_prev_total: h->h_rx.hs_prev_total = a->a_rx_rate.r_total; h->h_tx.hs_prev_total = a->a_tx_rate.r_total; update_ts: copy_timestamp(&h->h_last_update, ts); } struct history *history_alloc(struct history_def *def) { struct history *h; h = xcalloc(1, sizeof(*h)); init_list_head(&h->h_list); h->h_definition = def; h->h_min_interval = (def->hd_interval - (cfg_read_interval / 2.0f)); h->h_max_interval = (def->hd_interval / cfg_history_variance); return h; } void history_free(struct history *h) { if (!h) return; xfree(h->h_rx.hs_data); xfree(h->h_tx.hs_data); list_del(&h->h_list); xfree(h); } void history_attach(struct attr *attr) { struct history_def *def; struct history *h; list_for_each_entry(def, &def_list, hd_list) { h = history_alloc(def); list_add_tail(&h->h_list, &attr->a_history_list); } } struct history_def *history_select_first(void) { if (list_empty(&def_list)) current_history = NULL; else current_history = list_first_entry(&def_list, struct history_def, hd_list); return current_history; } struct history_def *history_select_last(void) { if (list_empty(&def_list)) current_history = NULL; else current_history = list_entry(def_list.prev, struct history_def, hd_list); return current_history; } struct history_def *history_select_next(void) { if (current_history && current_history->hd_list.next != &def_list) { current_history = list_entry(current_history->hd_list.next, struct history_def, hd_list); return current_history; } return history_select_first(); } struct history_def *history_select_prev(void) { if (current_history && current_history->hd_list.prev != &def_list) { current_history = list_entry(current_history->hd_list.prev, struct history_def, hd_list); return current_history; } return history_select_last(); } struct history_def *history_current(void) { if (!current_history) current_history = history_select_first(); return current_history; } static void __exit history_exit(void) { struct history_def *def, *n; list_for_each_entry_safe(def, n, &def_list, hd_list) history_def_free(def); } bmon-5.0/src/in_dummy.c000066400000000000000000000152371525227747100151110ustar00rootroot00000000000000/* * in_dummy.c Dummy Input Method * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #define MAXDEVS 32 static uint64_t c_rx_b_inc = 1000000000; static uint64_t c_tx_b_inc = 80000000; static uint64_t c_rx_p_inc = 1000; static uint64_t c_tx_p_inc = 800; static int c_numdev = 5; static int c_randomize = 0; static int c_mtu = 1540; static int c_maxpps = 100000; static int c_numgroups = 2; static uint64_t *cnts; enum { DUMMY_BYTES, DUMMY_PACKETS, NUM_DUMMY_VALUE, }; static struct attr_map link_attrs[NUM_DUMMY_VALUE] = { { .name = "bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Bytes", }, { .name = "packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Packets", } }; /* cnts[ngroups][ndevs][2][2] */ static inline int cnt_size(void) { return c_numgroups * c_numdev * 2 * 2; } static inline uint64_t *cnt(int group, int dev, int unit, int direction) { return cnts + (group * c_numdev * 2 * 2) + (dev * 2 * 2) + (unit * 2) + direction; } static void dummy_read(void) { int gidx, n; for (gidx = 0; gidx < c_numgroups; gidx++) { char gname[32]; struct element_group *group; 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++) { char ifname[IFNAMSIZ]; struct element *e; int i; snprintf(ifname, sizeof(ifname), "dummy%d", n); if (!(e = element_lookup(group, ifname, 0, NULL, ELEMENT_CREAT))) return; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); e->e_flags &= ~ELEMENT_FLAG_CREATED; } if (e->e_flags & ELEMENT_FLAG_UPDATED) continue; if (c_randomize) { uint64_t rx = rand() % c_maxpps; uint64_t tx = rand() % c_maxpps; *cnt(gidx, n, 0, 0) += rx; *cnt(gidx, n, 0, 1) += tx; *cnt(gidx, n, 1, 0) += rx * (rand() % c_mtu); *cnt(gidx, n, 1, 1) += tx * (rand() % c_mtu); } else { *cnt(gidx, n, 0, 0) += c_rx_p_inc; *cnt(gidx, n, 0, 1) += c_tx_p_inc; *cnt(gidx, n, 1, 0) += c_rx_b_inc; *cnt(gidx, n, 1, 1) += c_tx_b_inc; } for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; attr_update(e, m->attrid, *cnt(gidx, n, i, 0), *cnt(gidx, n, i, 1), UPDATE_FLAG_RX | UPDATE_FLAG_TX | UPDATE_FLAG_64BIT); } element_notify_update(e, NULL); element_lifesign(e, 1); } } } static void print_help(void) { printf( "dummy - Statistic generator module (dummy)\n" \ "\n" \ " Basic statistic generator for testing purposes. Can produce a\n" \ " constant or random statistic flow with configurable parameters.\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " rxb=NUM RX bytes increment amount (default: 10^9)\n" \ " txb=NUM TX bytes increment amount (default: 8*10^7)\n" \ " rxp=NUM RX packets increment amount (default: 1K)\n" \ " txp=NUM TX packets increment amount (default: 800)\n" \ " num=NUM Number of devices (default: 5)\n" \ " numgroups=NUM Number of groups (default: 2)\n" \ " randomize Randomize counters (default: off)\n" \ " seed=NUM Seed for randomizer (default: time(0))\n" \ " mtu=NUM Maximal Transmission Unit (default: 1540)\n" \ " maxpps=NUM Upper limit for packets per second (default: 100K)\n" \ "\n" \ " Randomizer:\n" \ " RX-packets := Rand() %% maxpps\n" \ " TX-packets := Rand() %% maxpps\n" \ " RX-bytes := RX-packets * (Rand() %% mtu)\n" \ " TX-bytes := TX-packets * (Rand() %% mtu)\n"); } static void dummy_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "rxb") && value) c_rx_b_inc = strtol(value, NULL, 0); else if (!strcasecmp(type, "txb") && value) c_tx_b_inc = strtol(value, NULL, 0); else if (!strcasecmp(type, "rxp") && value) c_rx_p_inc = strtol(value, NULL, 0); else if (!strcasecmp(type, "txp") && value) c_tx_p_inc = strtol(value, NULL, 0); else if (!strcasecmp(type, "num") && value) c_numdev = strtol(value, NULL, 0); else if (!strcasecmp(type, "randomize")) { c_randomize = 1; srand(time(NULL)); } else if (!strcasecmp(type, "seed") && value) srand(strtol(value, NULL, 0)); else if (!strcasecmp(type, "mtu") && value) c_mtu = strtol(value, NULL, 0); else if (!strcasecmp(type, "maxpps") && value) c_maxpps = strtol(value, NULL, 0); else if (!strcasecmp(type, "numgroups") && value) c_numgroups = strtol(value, NULL, 0); else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static int dummy_do_init(void) { if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs))) BUG(); return 0; } static int dummy_probe(void) { int i; if (c_numdev >= MAXDEVS) { fprintf(stderr, "numdev must be in range 0..%d\n", MAXDEVS); return 0; } cnts = xcalloc(cnt_size(), sizeof(uint64_t)); for (i = 0; i < c_numgroups; i++) { char groupname[32]; snprintf(groupname, sizeof(groupname), "group%02d", i); group_new_derived_hdr(groupname, groupname, DEFAULT_GROUP); } return 1; } static struct bmon_module dummy_ops = { .m_name = "dummy", .m_do = dummy_read, .m_parse_opt = dummy_parse_opt, .m_probe = dummy_probe, .m_init = dummy_do_init, }; static void __init dummy_init(void) { input_register(&dummy_ops); } bmon-5.0/src/in_netlink.c000066400000000000000000000633111525227747100154160ustar00rootroot00000000000000/* * in_netlink.c Netlink input * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #ifndef SYS_BSD static int c_notc = 0; static struct element_group *grp; static struct bmon_module netlink_ops; #include #include #include #include #include #include #include #include #include #include #include /* 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 #define MAX_IPS 16 #define INET_CIDR_MASK_STRLEN 3 #ifndef NETLINK_IPV6_DISABLED #define INET6_CIDR_MASK_STRLEN 4 #endif static struct attr_map link_attrs[] = { { .name = "bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Bytes", .rxid = RTNL_LINK_RX_BYTES, .txid = RTNL_LINK_TX_BYTES, }, { .name = "packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Packets", .rxid = RTNL_LINK_RX_PACKETS, .txid = RTNL_LINK_TX_PACKETS, }, { .name = "errors", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Errors", .rxid = RTNL_LINK_RX_ERRORS, .txid = RTNL_LINK_TX_ERRORS, }, { .name = "drop", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Dropped", .rxid = RTNL_LINK_RX_DROPPED, .txid = RTNL_LINK_TX_DROPPED, }, { .name = "compressed", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Compressed", .rxid = RTNL_LINK_RX_COMPRESSED, .txid = RTNL_LINK_TX_COMPRESSED, }, { .name = "nohandler", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "No Handler", .rxid = RTNL_LINK_RX_NOHANDLER, .txid = -1, }, { .name = "fifoerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "FIFO Error", .rxid = RTNL_LINK_RX_FIFO_ERR, .txid = RTNL_LINK_TX_FIFO_ERR, }, { .name = "lenerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Length Error", .rxid = RTNL_LINK_RX_LEN_ERR, .txid = -1, }, { .name = "overerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Over Error", .rxid = RTNL_LINK_RX_OVER_ERR, .txid = -1, }, { .name = "crcerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "CRC Error", .rxid = RTNL_LINK_RX_CRC_ERR, .txid = -1, }, { .name = "frameerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Frame Error", .rxid = RTNL_LINK_RX_FRAME_ERR, .txid = -1, }, { .name = "misserr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Missed Error", .rxid = RTNL_LINK_RX_MISSED_ERR, .txid = -1, }, { .name = "aborterr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Abort Error", .rxid = -1, .txid = RTNL_LINK_TX_ABORT_ERR, }, { .name = "carrerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Carrier Error", .rxid = -1, .txid = RTNL_LINK_TX_CARRIER_ERR, }, { .name = "hbeaterr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Heartbeat Error", .rxid = -1, .txid = RTNL_LINK_TX_HBEAT_ERR, }, { .name = "winerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Window Error", .rxid = -1, .txid = RTNL_LINK_TX_WIN_ERR, }, { .name = "coll", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Collisions", .rxid = -1, .txid = RTNL_LINK_COLLISIONS, }, { .name = "mcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Multicast", .rxid = -1, .txid = RTNL_LINK_MULTICAST, } #ifndef NETLINK_IPV6_DISABLED , { .name = "ip6pkts", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6Pkts", .rxid = RTNL_LINK_IP6_INPKTS, .txid = RTNL_LINK_IP6_OUTPKTS, }, { .name = "ip6discards", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6Discards", .rxid = RTNL_LINK_IP6_INDISCARDS, .txid = RTNL_LINK_IP6_OUTDISCARDS, }, { .name = "ip6octets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Ip6Octets", .rxid = RTNL_LINK_IP6_INOCTETS, .txid = RTNL_LINK_IP6_OUTOCTETS, }, { .name = "ip6bcastp", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Broadcast Packets", .rxid = RTNL_LINK_IP6_INBCASTPKTS, .txid = RTNL_LINK_IP6_OUTBCASTPKTS, }, { .name = "ip6bcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Ip6 Broadcast", .rxid = RTNL_LINK_IP6_INBCASTOCTETS, .txid = RTNL_LINK_IP6_OUTBCASTOCTETS, }, { .name = "ip6mcastp", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Multicast Packets", .rxid = RTNL_LINK_IP6_INMCASTPKTS, .txid = RTNL_LINK_IP6_OUTMCASTPKTS, }, { .name = "ip6mcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Ip6 Multicast", .rxid = RTNL_LINK_IP6_INMCASTOCTETS, .txid = RTNL_LINK_IP6_OUTMCASTOCTETS, }, { .name = "ip6noroute", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 No Route", .rxid = RTNL_LINK_IP6_INNOROUTES, .txid = RTNL_LINK_IP6_OUTNOROUTES, }, { .name = "ip6forward", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Forwarded", .rxid = -1, .txid = RTNL_LINK_IP6_OUTFORWDATAGRAMS, }, { .name = "ip6delivers", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Delivers", .rxid = RTNL_LINK_IP6_INDELIVERS, .txid = -1, }, { .name = "icmp6", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "ICMPv6", .rxid = RTNL_LINK_ICMP6_INMSGS, .txid = RTNL_LINK_ICMP6_OUTMSGS, }, { .name = "icmp6err", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "ICMPv6 Errors", .rxid = RTNL_LINK_ICMP6_INERRORS, .txid = RTNL_LINK_ICMP6_OUTERRORS, }, { .name = "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, .unit = UNIT_NUMBER, .description = "Ip6 Header Error", .rxid = RTNL_LINK_IP6_INHDRERRORS, .txid = -1, }, { .name = "ip6toobigerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Too Big Error", .rxid = RTNL_LINK_IP6_INTOOBIGERRORS, .txid = -1, }, { .name = "ip6trunc", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Truncated Packets", .rxid = RTNL_LINK_IP6_INTRUNCATEDPKTS, .txid = -1, }, { .name = "ip6unkproto", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Unknown Protocol Error", .rxid = RTNL_LINK_IP6_INUNKNOWNPROTOS, .txid = -1, }, { .name = "ip6addrerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Address Error", .rxid = RTNL_LINK_IP6_INADDRERRORS, .txid = -1, }, { .name = "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, .unit = UNIT_NUMBER, .description = "Ip6 Reassembly Timeouts", .rxid = RTNL_LINK_IP6_REASMTIMEOUT, .txid = -1, }, { .name = "ip6fragok", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Reasm/Frag OK", .rxid = RTNL_LINK_IP6_REASMOKS, .txid = RTNL_LINK_IP6_FRAGOKS, }, { .name = "ip6fragfail", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Reasm/Frag Failures", .rxid = RTNL_LINK_IP6_REASMFAILS, .txid = RTNL_LINK_IP6_FRAGFAILS, }, { .name = "ip6fragcreate", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Ip6 Reasm/Frag Requests", .rxid = RTNL_LINK_IP6_REASMREQDS, .txid = RTNL_LINK_IP6_FRAGCREATES, }, { .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, } #endif }; static struct attr_map tc_attrs[] = { { .name = "tc_bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Bytes", .rxid = -1, .txid = RTNL_TC_BYTES, }, { .name = "tc_packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Packets", .rxid = -1, .txid = RTNL_TC_PACKETS, }, { .name = "tc_overlimits", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Overlimits", .rxid = -1, .txid = RTNL_TC_OVERLIMITS, }, { .name = "tc_drop", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Dropped", .rxid = -1, .txid = RTNL_TC_DROPS, }, { .name = "tc_bps", .type = ATTR_TYPE_RATE, .unit = UNIT_BYTE, .description = "Byte Rate/s", .rxid = -1, .txid = RTNL_TC_RATE_BPS, }, { .name = "tc_pps", .type = ATTR_TYPE_RATE, .unit = UNIT_NUMBER, .description = "Packet Rate/s", .rxid = -1, .txid = RTNL_TC_RATE_PPS, }, { .name = "tc_qlen", .type = ATTR_TYPE_RATE, .unit = UNIT_NUMBER, .description = "Queue Length", .rxid = -1, .txid = RTNL_TC_QLEN, }, { .name = "tc_backlog", .type = ATTR_TYPE_RATE, .unit = UNIT_NUMBER, .description = "Backlog", .rxid = -1, .txid = RTNL_TC_BACKLOG, }, { .name = "tc_requeues", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Requeues", .rxid = -1, .txid = RTNL_TC_REQUEUES, } }; struct rdata { struct nl_cache * class_cache; struct element * parent; int level; }; struct link_addrs { int ifindex; char inet4_addrs[MAX_IPS][INET_ADDRSTRLEN + INET_CIDR_MASK_STRLEN]; int inet4_count; #ifndef NETLINK_IPV6_DISABLED char inet6_addrs[MAX_IPS][INET6_ADDRSTRLEN + INET6_CIDR_MASK_STRLEN]; int inet6_count; #endif }; static struct nl_sock *sock; static struct nl_cache *link_cache, *qdisc_cache, *addr_cache; static void element_free_tc(struct element *e) { struct element *c, *cnext; list_for_each_entry_safe(c, cnext, &e->e_childs, e_list) { if (!strncasecmp(c->e_name, "class ", 6) || !strncasecmp(c->e_name, "qdisc ", 6) || !strncasecmp(c->e_name, "cls ", 4)) element_free(c); } } static void update_tc_attrs(struct element *e, struct rtnl_tc *tc) { int i; for (i = 0; i < ARRAY_SIZE(tc_attrs); i++) { uint64_t c_tx = rtnl_tc_get_stat(tc, tc_attrs[i].txid); attr_update(e, tc_attrs[i].attrid, 0, c_tx, UPDATE_FLAG_TX); } } static void update_tc_infos(struct element *e, struct rtnl_tc *tc) { char buf[64]; snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mtu(tc)); element_update_info(e, "MTU", buf); snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_mpu(tc)); element_update_info(e, "MPU", buf); snprintf(buf, sizeof(buf), "%u", rtnl_tc_get_overhead(tc)); element_update_info(e, "Overhead", buf); snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_handle(tc)); element_update_info(e, "Id", buf); snprintf(buf, sizeof(buf), "%#x", rtnl_tc_get_parent(tc)); element_update_info(e, "Parent", buf); } static void handle_qdisc(struct nl_object *obj, void *); static void find_classes(uint32_t, struct rdata *); static void find_qdiscs(int, uint32_t, struct rdata *); static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix, const struct rdata *rdata) { char buf[IFNAME_MAX], name[128]; uint32_t id = rtnl_tc_get_handle(tc); struct element *e; rtnl_tc_handle2str(id, buf, sizeof(buf)); snprintf(name, sizeof(name), "%s %s (%s)", prefix, buf, rtnl_tc_get_kind(tc)); if (!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->level; if (element_set_key_attr(e, "tc_bytes", "tc_packets") || element_set_usage_attr(e, "tc_bytes")) BUG(); update_tc_infos(e, tc); e->e_flags &= ~ELEMENT_FLAG_CREATED; } update_tc_attrs(e, tc); element_notify_update(e, NULL); element_lifesign(e, 1); return e; } static void handle_cls(struct nl_object *obj, void *arg) { struct rtnl_cls *cls = (struct rtnl_cls *) obj; struct rdata *rdata = arg; handle_tc_obj((struct rtnl_tc *) cls, "cls", rdata); } static void handle_class(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; const struct rdata *rdata = arg; struct rdata ndata = { .class_cache = rdata->class_cache, .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "class", rdata))) return; ndata.parent = e; if (!strcmp(rtnl_tc_get_kind(tc), "htb")) element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc)); find_classes(rtnl_tc_get_handle(tc), &ndata); find_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata); } static void find_qdiscs(int ifindex, uint32_t parent, struct rdata *rdata) { struct rtnl_qdisc *filter; if (!(filter = rtnl_qdisc_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex); nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), handle_qdisc, rdata); rtnl_qdisc_put(filter); } static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata) { struct nl_cache *cls_cache; if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0) return; nl_cache_foreach(cls_cache, handle_cls, rdata); nl_cache_free(cls_cache); } static void find_classes(uint32_t parent, struct rdata *rdata) { struct rtnl_class *filter; if (!(filter = rtnl_class_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); nl_cache_foreach_filter(rdata->class_cache, OBJ_CAST(filter), handle_class, rdata); rtnl_class_put(filter); } static void handle_qdisc(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; const struct rdata *rdata = arg; struct rdata ndata = { .class_cache = rdata->class_cache, .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "qdisc", rdata))) return; ndata.parent = e; switch(rtnl_tc_get_parent(tc)) { case TC_H_INGRESS: { const char *kind = rtnl_tc_get_kind(tc); if (kind && !strcmp(kind, "clsact")) { find_cls(rtnl_tc_get_ifindex(tc), TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS), &ndata); find_cls(rtnl_tc_get_ifindex(tc), TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS), &ndata); } else { find_cls(rtnl_tc_get_ifindex(tc), TC_H_INGRESS, &ndata); } break; } case TC_H_ROOT: find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata); find_classes(TC_H_ROOT, &ndata); /* fall-through */ default: find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata); find_classes(rtnl_tc_get_handle(tc), &ndata); } } static void handle_tc(struct element *e, struct rtnl_link *link) { struct rtnl_qdisc *qdisc; struct nl_cache *class_cache; int ifindex; struct rdata rdata = { .level = 1, .parent = e, }; if (c_notc) { element_free_tc(e); return; } ifindex = rtnl_link_get_ifindex(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); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } nl_cache_free(class_cache); } static void get_addresses_cb(struct nl_object *obj, void *arg) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct link_addrs *la = arg; struct nl_addr *local; if (rtnl_addr_get_ifindex(addr) == la->ifindex) { local = rtnl_addr_get_local(addr); if (local) { if (rtnl_addr_get_family(addr) == AF_INET && la->inet4_count < MAX_IPS) { nl_addr2str(local, la->inet4_addrs[la->inet4_count++], sizeof(la->inet4_addrs[0])); } #ifndef NETLINK_IPV6_DISABLED else if (rtnl_addr_get_family(addr) == AF_INET6 && la->inet6_count < MAX_IPS) { nl_addr2str(local, la->inet6_addrs[la->inet6_count++], sizeof(la->inet6_addrs[0])); } #endif } } } static void update_link_addrs(struct element *e, struct link_addrs *la) { char addr_name_buf[16]; uint8_t i; for (i = 0; i < la->inet4_count; i++) { snprintf(addr_name_buf, sizeof(addr_name_buf), "IPv4[%u]", i + 1); element_update_info(e, addr_name_buf, la->inet4_addrs[i]); } for (; i < MAX_IPS; i++) { snprintf(addr_name_buf, sizeof(addr_name_buf), "IPv4[%u]", i + 1); element_delete_info(e, addr_name_buf); } #ifndef NETLINK_IPV6_DISABLED for (i = 0; i < la->inet6_count; i++) { snprintf(addr_name_buf, sizeof(addr_name_buf), "IPv6[%u]", i + 1); element_update_info(e, addr_name_buf, la->inet6_addrs[i]); } for (; i < MAX_IPS; i++) { snprintf(addr_name_buf, sizeof(addr_name_buf), "IPv6[%u]", i + 1); element_delete_info(e, addr_name_buf); } #endif } static void update_link_infos(struct element *e, struct rtnl_link *link) { char buf[64]; int ifindex = rtnl_link_get_ifindex(link); struct link_addrs la = { .ifindex = ifindex }; struct rtnl_addr *filter; if (addr_cache && (filter = rtnl_addr_alloc())) { rtnl_addr_set_ifindex(filter, ifindex); nl_cache_foreach_filter(addr_cache, OBJ_CAST(filter), get_addresses_cb, &la); rtnl_addr_put(filter); } update_link_addrs(e, &la); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link)); element_update_info(e, "MTU", buf); rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf)); element_update_info(e, "Flags", buf); rtnl_link_operstate2str(rtnl_link_get_operstate(link), buf, sizeof(buf)); element_update_info(e, "Operstate", buf); snprintf(buf, sizeof(buf), "%u", ifindex); element_update_info(e, "IfIndex", buf); nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf)); element_update_info(e, "MAC", buf); nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf)); element_update_info(e, "Broadcast", buf); rtnl_link_mode2str(rtnl_link_get_linkmode(link), buf, sizeof(buf)); element_update_info(e, "Mode", buf); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link)); element_update_info(e, "TXQlen", buf); nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf)); element_update_info(e, "Family", buf); element_update_info(e, "Alias", rtnl_link_get_ifalias(link) ? : ""); element_update_info(e, "Qdisc", rtnl_link_get_qdisc(link) ? : ""); if (rtnl_link_get_link(link)) { snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link)); element_update_info(e, "SlaveOfIndex", buf); } } static void do_link(struct nl_object *obj, void *arg) { struct rtnl_link *link = (struct rtnl_link *) obj; struct element *e, *e_parent = NULL; int i, master_ifindex; if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) { /* FIXME: delete element */ return; } /* Check if the interface is a slave of another interface */ if ((master_ifindex = rtnl_link_get_link(link))) { char parent[IFNAMSIZ+1]; rtnl_link_i2name(link_cache, master_ifindex, parent, sizeof(parent)); e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0); } if (!(e = element_lookup(grp, rtnl_link_get_name(link), rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT))) return; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (e->e_parent) e->e_level = e->e_parent->e_level + 1; if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); e->e_flags &= ~ELEMENT_FLAG_CREATED; } for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; uint64_t c_rx = 0, c_tx = 0; int flags = 0; if (m->rxid >= 0) { c_rx = rtnl_link_get_stat(link, m->rxid); flags |= UPDATE_FLAG_RX; } if (m->txid >= 0) { c_tx = rtnl_link_get_stat(link, m->txid); flags |= UPDATE_FLAG_TX; } attr_update(e, m->attrid, c_rx, c_tx, flags); } if (qdisc_cache) handle_tc(e, link); update_link_infos(e, link); element_notify_update(e, NULL); element_lifesign(e, 1); } static void netlink_read(void) { int err; if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto disable; } if ((err = nl_cache_resync(sock, addr_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync addr cache: %s\n", nl_geterror(err)); goto disable; } if (qdisc_cache && (err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err)); goto disable; } nl_cache_foreach(link_cache, do_link, NULL); return; disable: netlink_ops.m_flags &= ~BMON_MODULE_ENABLED; } static void netlink_shutdown(void) { nl_cache_free(link_cache); nl_cache_free(addr_cache); nl_cache_free(qdisc_cache); nl_socket_free(sock); } static void netlink_use_bit(struct attr_map *map, const int size) { if(cfg_getbool(cfg, "use_bit")) { for(int i = 0; i < size; ++i) { if(!strcmp(map[i].description, "Bytes")) { map[i].description = "Bits"; } } } } static int netlink_do_init(void) { int err; if (!(sock = nl_socket_alloc())) { fprintf(stderr, "Unable to allocate netlink socket\n"); goto disable; } if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0) { fprintf(stderr, "Unable to connect netlink socket: %s\n", nl_geterror(err)); goto disable; } if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) { fprintf(stderr, "Unable to allocate link cache: %s\n", nl_geterror(err)); goto disable; } if ((err = rtnl_addr_alloc_cache(sock, &addr_cache)) < 0) { fprintf(stderr, "Unable to allocate addr cache: %s\n", nl_geterror(err)); goto disable; } if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) { fprintf(stderr, "Warning: Unable to allocate qdisc cache: %s\n", nl_geterror(err)); fprintf(stderr, "Disabling QoS statistics.\n"); qdisc_cache = NULL; } netlink_use_bit(link_attrs, ARRAY_SIZE(link_attrs)); netlink_use_bit(tc_attrs, ARRAY_SIZE(tc_attrs)); if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) || attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs))) BUG(); if (!(grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE))) BUG(); return 0; disable: return -EOPNOTSUPP; } static int netlink_probe(void) { struct nl_sock *sock; struct nl_cache *lc, *ac; int ret = 0; if (!(sock = nl_socket_alloc())) return 0; if (nl_connect(sock, NETLINK_ROUTE) < 0) { nl_socket_free(sock); return 0; } if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &lc) < 0) goto out; nl_cache_free(lc); if (rtnl_addr_alloc_cache(sock, &ac) < 0) goto out; nl_cache_free(ac); ret = 1; out: nl_socket_free(sock); return ret; } static void print_help(void) { printf( "netlink - Netlink statistic collector for Linux\n" \ "\n" \ " Powerful statistic collector for Linux using netlink sockets\n" \ " to collect link and traffic control statistics.\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " notc[=0|1] Enable(0)/disable(1) collection of traffic\n" \ " control statistics (bare notc implies 1,\n" \ " default if not specified is enabled)\n"); } static void netlink_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "notc")) c_notc = value ? !!strtol(value, NULL, 0) : 1; else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static int netlink_get_opt(const char *opt) { if (!strcasecmp(opt, "notc")) return c_notc; else return -EINVAL; } static struct bmon_module netlink_ops = { .m_name = "netlink", .m_flags = BMON_MODULE_DEFAULT, .m_do = netlink_read, .m_shutdown = netlink_shutdown, .m_parse_opt = netlink_parse_opt, .m_get_opt = netlink_get_opt, .m_probe = netlink_probe, .m_init = netlink_do_init, }; static void __init netlink_init(void) { input_register(&netlink_ops); } #endif bmon-5.0/src/in_null.c000066400000000000000000000035771525227747100147340ustar00rootroot00000000000000/* * in_null.c Null Input Method * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include static void null_read(void) { DBG("null: reading..."); } static void print_help(void) { printf( "null - Do not collect statistics at all\n" \ "\n" \ " Will not collect any statistics at all, used to disable \n" \ " local statistics collection.\n" \ " Author: Thomas Graf \n"); } static void null_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static struct bmon_module null_ops = { .m_name = "null", .m_do = null_read, .m_parse_opt = null_parse_opt, }; static void __init null_init(void) { input_register(&null_ops); } bmon-5.0/src/in_proc.c000066400000000000000000000136431525227747100147200ustar00rootroot00000000000000/* * in_proc.c /proc/net/dev Input (Linux) * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include static const char *c_path = "/proc/net/dev"; static int c_path_default = 1; static const char *c_group = DEFAULT_GROUP; static int c_group_default = 1; static struct element_group *grp; enum { PROC_BYTES, PROC_PACKETS, PROC_ERRORS, PROC_DROP, PROC_COMPRESSED, PROC_FIFO, PROC_FRAME, PROC_MCAST, NUM_PROC_VALUE, }; static struct attr_map link_attrs[NUM_PROC_VALUE] = { { .name = "bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .description = "Bytes", }, { .name = "packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Packets", }, { .name = "errors", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Errors", }, { .name = "drop", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Dropped", }, { .name = "compressed", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Compressed", }, { .name = "fifoerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "FIFO Error", }, { .name = "frameerr", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Frame Error", }, { .name = "mcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .description = "Multicast", } }; static void proc_read(void) { struct element *e; FILE *fd; char buf[512], *p, *s, *unused BMON_UNUSED; int w; if (!(fd = fopen(c_path, "r"))) quit("Unable to open file %s: %s\n", c_path, strerror(errno)); /* Ignore header */ unused = fgets(buf, sizeof(buf), fd); unused = fgets(buf, sizeof(buf), fd); for (; fgets(buf, sizeof(buf), fd);) { uint64_t data[NUM_PROC_VALUE][2]; int i; if (buf[0] == '\r' || buf[0] == '\n') continue; if (!(p = strchr(buf, ':'))) continue; *p = '\0'; s = (p + 1); for (p = &buf[0]; *p == ' '; p++); w = sscanf(s, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " " "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " " "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " " "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 "\n", &data[PROC_BYTES][0], &data[PROC_PACKETS][0], &data[PROC_ERRORS][0], &data[PROC_DROP][0], &data[PROC_FIFO][0], &data[PROC_FRAME][0], &data[PROC_COMPRESSED][0], &data[PROC_MCAST][0], &data[PROC_BYTES][1], &data[PROC_PACKETS][1], &data[PROC_ERRORS][1], &data[PROC_DROP][1], &data[PROC_FIFO][1], &data[PROC_FRAME][1], &data[PROC_COMPRESSED][1], &data[PROC_MCAST][1]); if (w != 16) continue; if (!(e = element_lookup(grp, p, 0, NULL, ELEMENT_CREAT))) goto skip; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); e->e_flags &= ~ELEMENT_FLAG_CREATED; } for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; attr_update(e, m->attrid, data[i][0], data[i][1], UPDATE_FLAG_RX | UPDATE_FLAG_TX); } element_notify_update(e, NULL); element_lifesign(e, 1); } skip: fclose(fd); } static void print_help(void) { printf( "proc - procfs statistic collector for Linux" \ "\n" \ " Reads statistics from procfs (/proc/net/dev)\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " file=PATH Path to statistics file (default: /proc/net/dev)\n" " group=NAME Name of group\n"); } static void proc_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "file") && value) { if (!c_path_default) xfree((char *)c_path); c_path = xstrdup(value); c_path_default = 0; } else if (!strcasecmp(type, "group") && value) { if (!c_group_default) xfree((char *)c_group); c_group = xstrdup(value); c_group_default = 0; } else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static int proc_do_init(void) { if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) || !(grp = group_lookup(c_group, GROUP_CREATE))) BUG(); return 0; } static int proc_probe(void) { FILE *fd = fopen(c_path, "r"); if (fd) { fclose(fd); return 1; } return 0; } static void proc_shutdown(void) { if (!c_path_default) { xfree((char *)c_path); c_path = NULL; c_path_default = 1; } if (!c_group_default) { xfree((char *)c_group); c_group = NULL; c_group_default = 1; } } static struct bmon_module proc_ops = { .m_name = "proc", .m_do = proc_read, .m_parse_opt = proc_parse_opt, .m_probe = proc_probe, .m_init = proc_do_init, .m_shutdown = proc_shutdown, }; static void __init proc_init(void) { input_register(&proc_ops); } bmon-5.0/src/in_sysctl.c000066400000000000000000000157001525227747100152720ustar00rootroot00000000000000/* * in_sysctl.c sysctl (BSD) * * $Id: in_sysctl.c 20 2004-10-30 22:46:16Z tgr $ * * Copyright (c) 2001-2004 Thomas Graf * Copyright (c) 2014 Žilvinas Valinskas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #if defined SYS_BSD #include #include #include #include #include #include static int c_debug = 0; static struct element_group *grp; enum { SYSCTL_RX_BYTES = 0x100, SYSCTL_TX_BYTES, SYSCTL_RX_PACKETS, SYSCTL_TX_PACKETS, SYSCTL_RX_ERRORS, SYSCTL_TX_ERRORS, SYSCTL_RX_DROPS, SYSCTL_RX_MCAST, SYSCTL_TX_MCAST, SYSCTL_TX_COLLS, }; static struct attr_map link_attrs[] = { { .name = "bytes", .type = ATTR_TYPE_COUNTER, .unit = UNIT_BYTE, .rxid = SYSCTL_RX_BYTES, .txid = SYSCTL_TX_BYTES, .description = "Bytes", }, { .name = "packets", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_PACKETS, .txid = SYSCTL_TX_PACKETS, .description = "Packets", }, { .name = "errors", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_ERRORS, .txid = SYSCTL_TX_ERRORS, .description = "Errors", }, { .name = "drop", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_DROPS, .description = "Dropped", }, { .name = "coll", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .txid = SYSCTL_TX_COLLS, .description = "Collisions", }, { .name = "mcast", .type = ATTR_TYPE_COUNTER, .unit = UNIT_NUMBER, .rxid = SYSCTL_RX_MCAST, .txid = SYSCTL_TX_MCAST, .description = "Multicast", } }; uint64_t sysctl_get_stats(const struct if_msghdr *ifm, int what) { switch(what) { case SYSCTL_RX_BYTES: return ifm->ifm_data.ifi_ibytes; case SYSCTL_TX_BYTES: return ifm->ifm_data.ifi_obytes; case SYSCTL_RX_PACKETS: return ifm->ifm_data.ifi_ipackets; case SYSCTL_TX_PACKETS: return ifm->ifm_data.ifi_opackets; case SYSCTL_RX_ERRORS: return ifm->ifm_data.ifi_ierrors; case SYSCTL_TX_ERRORS: return ifm->ifm_data.ifi_oerrors; case SYSCTL_RX_DROPS: return ifm->ifm_data.ifi_iqdrops; case SYSCTL_RX_MCAST: return ifm->ifm_data.ifi_imcasts; case SYSCTL_TX_MCAST: return ifm->ifm_data.ifi_omcasts; case SYSCTL_TX_COLLS: return ifm->ifm_data.ifi_collisions; default: return 0; }; } static void sysctl_read(void) { int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; size_t n; char *buf, *next, *lim; if (sysctl(mib, 6, NULL, &n, NULL, 0) < 0) quit("sysctl() failed"); if (c_debug) fprintf(stderr, "sysctl 1-pass n=%zd\n", n); buf = xcalloc(1, n); if (sysctl(mib, 6, buf, &n, NULL, 0) < 0) quit("sysctl() failed"); if (c_debug) fprintf(stderr, "sysctl 2-pass n=%zd\n", n); lim = (buf + n); for (next = buf; next < lim; ) { struct element *e, *e_parent = NULL; struct if_msghdr *ifm, *nextifm; struct sockaddr_dl *sdl; char info_buf[64]; ifm = (struct if_msghdr *) next; if (ifm->ifm_type != RTM_IFINFO) break; next += ifm->ifm_msglen; while (next < lim) { nextifm = (struct if_msghdr *) next; if (nextifm->ifm_type != RTM_NEWADDR) break; next += nextifm->ifm_msglen; } sdl = (struct sockaddr_dl *) (ifm + 1); if (!cfg_show_all && !(ifm->ifm_flags & IFF_UP)) continue; if (sdl->sdl_family != AF_LINK) continue; if (c_debug) fprintf(stderr, "Processing %s\n", sdl->sdl_data); sdl->sdl_data[sdl->sdl_nlen] = '\0'; e = element_lookup(grp, sdl->sdl_data, sdl->sdl_index, e_parent, ELEMENT_CREAT); if (!e) continue; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (e->e_parent) e->e_level = e->e_parent->e_level + 1; if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); e->e_flags &= ~ELEMENT_FLAG_CREATED; } int i; for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; uint64_t rx = 0, tx = 0; int flags = 0; if (m->rxid) { rx = sysctl_get_stats(ifm, m->rxid); flags |= UPDATE_FLAG_RX; } if (m->txid) { tx = sysctl_get_stats(ifm, m->txid); flags |= UPDATE_FLAG_TX; } attr_update(e, m->attrid, rx, tx, flags); } snprintf(info_buf, sizeof(info_buf), "%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__) || defined(__OpenBSD__)) 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); } xfree(buf); } static void print_help(void) { printf( "sysctl - sysctl statistic collector for BSD and Darwin\n" \ "\n" \ " BSD and Darwin statistic collector using sysctl()\n" \ " Author: Thomas Graf \n" \ "\n"); } static void sysctl_set_opts(const char* type, const char* value) { if (!strcasecmp(type, "debug")) c_debug = 1; else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static int sysctl_probe(void) { size_t n; int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; if (sysctl(mib, 6, NULL, &n, NULL, 0) < 0) return 0; return 1; } static int sysctl_do_init(void) { if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs))) BUG(); grp = group_lookup(DEFAULT_GROUP, GROUP_CREATE); if (!grp) BUG(); return 0; } static struct bmon_module kstat_ops = { .m_name = "sysctl", .m_do = sysctl_read, .m_parse_opt = sysctl_set_opts, .m_probe = sysctl_probe, .m_init = sysctl_do_init, }; static void __init sysctl_init(void) { input_register(&kstat_ops); } #endif bmon-5.0/src/input.c000066400000000000000000000053711525227747100144250ustar00rootroot00000000000000/* * input.c Input API * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include static struct bmon_subsys input_subsys; void input_register(struct bmon_module *m) { module_register(&input_subsys, m); } static void activate_default(void) { /* * Try to activate a default input module if the user did not make * a selection */ if (!input_subsys.s_nmod) { struct bmon_module *m; #ifdef SYS_LINUX if (!input_set("netlink", false)) return; if (!input_set("proc", false)) return; #endif #ifdef SYS_BSD if (!input_set("sysctl", false)) return; #endif /* Fall back to anything that could act as default */ list_for_each_entry(m, &input_subsys.s_mod_list, m_list) { if (m->m_flags & BMON_MODULE_DEFAULT) if (!input_set(m->m_name, false)) return; } quit("No input module found\n"); } } void input_read(void) { module_foreach_run_enabled(&input_subsys); } int input_set(const char *name, bool update) { return module_set(&input_subsys, name, update); } int input_is_enabled(const char *name) { struct bmon_module *m; list_for_each_entry(m, &input_subsys.s_mod_list, m_list) { if (!strcmp(name, m->m_name) && (m->m_flags & BMON_MODULE_ENABLED)) return 1; } return 0; } int input_get_opt(const char *name, const char* opt) { return module_get_opt(&input_subsys, name, opt); } static struct bmon_subsys input_subsys = { .s_name = "input", .s_activate_default = &activate_default, .s_mod_list = LIST_SELF(input_subsys.s_mod_list), }; static void __init __input_init(void) { module_register_subsys(&input_subsys); } bmon-5.0/src/module.c000066400000000000000000000133651525227747100145550ustar00rootroot00000000000000/* * module.c Module API * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include static LIST_HEAD(subsys_list); static void module_foreach(struct bmon_subsys *ss, void (*cb)(struct bmon_module *)) { struct bmon_module *m; list_for_each_entry(m, &ss->s_mod_list, m_list) cb(m); } void module_foreach_run_enabled_pre(struct bmon_subsys *ss) { struct bmon_module *m; list_for_each_entry(m, &ss->s_mod_list, m_list) if (m->m_flags & BMON_MODULE_ENABLED && m->m_pre) m->m_pre(); } void module_foreach_run_enabled(struct bmon_subsys *ss) { struct bmon_module *m; list_for_each_entry(m, &ss->s_mod_list, m_list) if (m->m_flags & BMON_MODULE_ENABLED && m->m_do) m->m_do(); } void module_foreach_run_enabled_post(struct bmon_subsys *ss) { struct bmon_module *m; list_for_each_entry(m, &ss->s_mod_list, m_list) if (m->m_flags & BMON_MODULE_ENABLED && m->m_post) m->m_post(); } static struct bmon_module *module_lookup(struct bmon_subsys *ss, const char *name) { struct bmon_module *m; list_for_each_entry(m, &ss->s_mod_list, m_list) if (!strcmp(m->m_name, name)) return m; return NULL; } static void module_list(struct bmon_subsys *ss, struct list_head *list) { printf("%s modules:\n", ss->s_name); if (list_empty(list)) printf("\tNo %s modules found.\n", ss->s_name); else { struct bmon_module *m; list_for_each_entry(m, list, m_list) printf("\t%s\n", m->m_name); } } static int module_configure(struct bmon_module *m, module_conf_t *cfg, bool update) { DBG("Configuring module %s", m->m_name); if (m->m_parse_opt && cfg) { tv_t *tv; list_for_each_entry(tv, &cfg->m_attrs, tv_list) m->m_parse_opt(tv->tv_type, tv->tv_value); } /* No need to probe on update, already checked that the module is enabled */ if (!update && m->m_probe && !m->m_probe()) return -EINVAL; if (!(m->m_flags & BMON_MODULE_ENABLED)) { m->m_flags |= BMON_MODULE_ENABLED; m->m_subsys->s_nmod++; } return 0; } int module_register(struct bmon_subsys *ss, struct bmon_module *m) { if (m->m_subsys) return -EBUSY; list_add_tail(&m->m_list, &ss->s_mod_list); m->m_subsys = ss; return 0; } static void __auto_load(struct bmon_module *m) { if ((m->m_flags & BMON_MODULE_AUTO) && !(m->m_flags & BMON_MODULE_ENABLED)) { if (module_configure(m, NULL, false) == 0) DBG("Auto-enabled module %s", m->m_name); } } int module_set(struct bmon_subsys *ss, const char *name, bool update) { struct bmon_module *mod; LIST_HEAD(tmp_list); module_conf_t *m, *mnext; tv_t *tv, *tvnext; if (!name || !strcasecmp(name, "list")) { module_list(ss, &ss->s_mod_list); return 1; } parse_module_param(name, &tmp_list); list_for_each_entry_safe(m, mnext, &tmp_list, m_list) { if (!(mod = module_lookup(ss, m->m_name))) quit("Unknown %s module: %s\n", ss->s_name, m->m_name); /* Only update if module is enabled */ if (!update || (update && (mod->m_flags & BMON_MODULE_ENABLED))) { if (module_configure(mod, m, update) == 0) DBG("%s module %s", (update ? "Updated" : "Enabled"), mod->m_name); } list_for_each_entry_safe(tv, tvnext, &m->m_attrs, tv_list) { xfree(tv->tv_value); xfree(tv->tv_type); list_del(&tv->tv_list); xfree(tv); } xfree(m->m_name); list_del(&m->m_list); xfree(m); } if (!update) module_foreach(ss, __auto_load); if (!ss->s_nmod) quit("No working %s module found\n", ss->s_name); DBG("Configured modules"); return 0; } int module_get_opt(struct bmon_subsys *ss, const char *name, const char* opt) { struct bmon_module *mod; if (!(mod = module_lookup(ss, name))) quit("Unknown %s module: %s\n", ss->s_name, name); if ((mod->m_flags & BMON_MODULE_ENABLED) && mod->m_get_opt) return mod->m_get_opt(opt); return -EINVAL; } static void __module_init(struct bmon_module *m) { if (m->m_init) { DBG("Initializing %s...", m->m_name); if (m->m_init()) m->m_flags &= ~BMON_MODULE_ENABLED; } } void module_init(void) { struct bmon_subsys *ss; DBG("Initializing modules"); list_for_each_entry(ss, &subsys_list, s_list) { if (ss->s_activate_default) ss->s_activate_default(); module_foreach(ss, __module_init); } } static void __module_shutdown(struct bmon_module *m) { if (m->m_shutdown) { DBG("Shutting down %s...", m->m_name); m->m_shutdown(); m->m_flags &= ~BMON_MODULE_ENABLED; } } void module_shutdown(void) { DBG("Shutting down modules"); struct bmon_subsys *ss; list_for_each_entry(ss, &subsys_list, s_list) module_foreach(ss, __module_shutdown); } void module_register_subsys(struct bmon_subsys *ss) { DBG("Module %s registered", ss->s_name); list_add_tail(&ss->s_list, &subsys_list); } bmon-5.0/src/out_ascii.c000066400000000000000000000175351525227747100152520ustar00rootroot00000000000000/* * out_ascii.c ASCII Output * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include typedef enum diagram_type_e { D_LIST, D_GRAPH, D_DETAILS } diagram_type_t; static struct graph_cfg graph_cfg = { .gc_foreground = '*', .gc_background = ' ', .gc_noise = '.', .gc_unknown = '?', .gc_height = 6, }; static diagram_type_t c_diagram_type = D_LIST; static char *c_hist = "second"; static int c_quit_after = -1; static void print_list(struct element *e) { char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = ""; double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f; int rx1prec = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0; char pad[IFNAMSIZ + 32]; struct attr *a; if (e->e_key_attr[GT_MAJOR] && (a = attr_lookup(e, e->e_key_attr[GT_MAJOR]->ad_id))) attr_rate2float(a, &rx1, &rxu1, &rx1prec, &tx1, &txu1, &tx1prec); if (e->e_key_attr[GT_MINOR] && (a = attr_lookup(e, e->e_key_attr[GT_MINOR]->ad_id))) attr_rate2float(a, &rx2, &rxu2, &rx2prec, &tx2, &txu2, &tx2prec); memset(pad, 0, sizeof(pad)); memset(pad, ' ', e->e_level < 15 ? e->e_level : 15); strncat(pad, e->e_name, sizeof(pad) - strlen(pad) - 1); if (e->e_description) { strncat(pad, " (", sizeof(pad) - strlen(pad) - 1); strncat(pad, e->e_description, sizeof(pad) - strlen(pad) - 1); strncat(pad, ")", sizeof(pad) - strlen(pad) - 1); } printf(" %-36s %8.*f%-3s %8.*f%-3s ", pad, rx1prec, rx1, rxu1, rx2prec, rx2, rxu2); if (e->e_rx_usage == FLT_MAX) printf(" "); else printf("%2.0f%%", e->e_rx_usage); printf(" %8.*f%-3s %8.*f%-3s ", tx1prec, tx1, txu1, tx2prec, tx2, txu2); if (e->e_tx_usage == FLT_MAX) printf(" \n"); else printf("%2.0f%%\n", e->e_tx_usage); } static void print_attr_detail(struct element *e, struct attr *a, void *arg) { char *rx_u, *tx_u; int rxprec, txprec; double rx = unit_value2str(rate_get_total(&a->a_rx_rate), a->a_def->ad_unit, &rx_u, &rxprec); double tx = unit_value2str(rate_get_total(&a->a_tx_rate), a->a_def->ad_unit, &tx_u, &txprec); printf(" %-36s %12.*f%-3s %12.*f%-3s\n", a->a_def->ad_description, rxprec, rx, rx_u, txprec, tx, tx_u); } static void print_details(struct element *e) { printf(" %s", e->e_name); if (e->e_id) printf(" (%u)", e->e_id); printf("\n"); element_foreach_attr(e, print_attr_detail, NULL); printf("\n"); } static void print_table(struct graph *g, struct graph_table *tbl, const char *hdr) { int i; if (!tbl->gt_table) return; printf("%s %s\n", hdr, tbl->gt_y_unit); for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) printf("%8.2f %s\n", tbl->gt_scale[i], tbl->gt_table + (i * graph_row_size(&g->g_cfg))); printf(" 1 5 10 15 20 25 30 35 40 " \ "45 50 55 60\n"); } static void __print_graph(struct element *e, struct attr *a, void *arg) { struct history *h; struct graph *g; if (!(a->a_flags & ATTR_DOING_HISTORY)) return; graph_cfg.gc_unit = a->a_def->ad_unit; list_for_each_entry(h, &a->a_history_list, h_list) { if (strcasecmp(c_hist, h->h_definition->hd_name)) continue; g = graph_alloc(h, &graph_cfg); graph_refill(g, h); printf("Interface: %s\n", e->e_name); printf("Attribute: %s\n", a->a_def->ad_description); print_table(g, &g->g_rx, "RX"); print_table(g, &g->g_tx, "TX"); graph_free(g); } } static void print_graph(struct element *e) { element_foreach_attr(e, __print_graph, NULL); } static void ascii_draw_element(struct element_group *g, struct element *e, void *arg) { switch (c_diagram_type) { case D_LIST: print_list(e); break; case D_DETAILS: print_details(e); break; case D_GRAPH: print_graph(e); break; } } static void ascii_draw_group(struct element_group *g, void *arg) { if (c_diagram_type == D_LIST) printf("%-37s%10s %11s %%%10s %11s %%\n", g->g_hdr->gh_title, g->g_hdr->gh_column[0], g->g_hdr->gh_column[1], g->g_hdr->gh_column[2], g->g_hdr->gh_column[3]); else printf("%s\n", g->g_hdr->gh_title); group_foreach_element(g, ascii_draw_element, NULL); } static void ascii_draw(void) { group_foreach(ascii_draw_group, NULL); fflush(stdout); if (c_quit_after > 0) if (--c_quit_after == 0) exit(0); } static void print_help(void) { printf( "ascii - ASCII Output\n" \ "\n" \ " Plain configurable ASCII output.\n" \ "\n" \ " scriptable: (output graph for eth1 10 times)\n" \ " bmon -p eth1 -o 'ascii:diagram=graph;quitafter=10'\n" \ " show details for all ethernet interfaces:\n" \ " bmon -p 'eth*' -o 'ascii:diagram=details;quitafter=1'\n" \ "\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " diagram=TYPE Diagram type\n" \ " fgchar=CHAR Foreground character (default: '*')\n" \ " bgchar=CHAR Background character (default: '.')\n" \ " nchar=CHAR Noise character (default: ':')\n" \ " uchar=CHAR Unknown character (default: '?')\n" \ " height=NUM Height of graph (default: 6)\n" \ " xunit=UNIT X-Axis Unit (default: seconds)\n" \ " yunit=UNIT Y-Axis Unit (default: dynamic)\n" \ " quitafter=NUM Quit bmon after NUM outputs\n"); } static void ascii_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "diagram") && value) { if (tolower(*value) == 'l') c_diagram_type = D_LIST; else if (tolower(*value) == 'g') c_diagram_type = D_GRAPH; else if (tolower(*value) == 'd') c_diagram_type = D_DETAILS; else quit("Unknown diagram type '%s'\n", value); } else if (!strcasecmp(type, "fgchar") && value) graph_cfg.gc_foreground = value[0]; else if (!strcasecmp(type, "bgchar") && value) graph_cfg.gc_background = value[0]; else if (!strcasecmp(type, "nchar") && value) graph_cfg.gc_noise = value[0]; #if 0 else if (!strcasecmp(type, "uchar") && value) set_unk_char(value[0]); #endif else if (!strcasecmp(type, "xunit") && value) c_hist = xstrdup(value); #if 0 else if (!strcasecmp(type, "yunit") && value) { struct unit *u; if (!(u = unit_lookup(value))) quit("Unknown unit '%s'\n", value); graph_cfg.gc_unit = u; #endif else if (!strcasecmp(type, "height") && value) graph_cfg.gc_height = strtol(value, NULL, 0); else if (!strcasecmp(type, "quitafter") && value) c_quit_after = strtol(value, NULL, 0); else if (!strcasecmp(type, "help")) { print_help(); exit(0); } else quit("Unknown module option '%s'\n", type); } static struct bmon_module ascii_ops = { .m_name = "ascii", .m_do = ascii_draw, .m_parse_opt = ascii_parse_opt, }; static void __init ascii_init(void) { output_register(&ascii_ops); } bmon-5.0/src/out_curses.c000066400000000000000000000755661525227747100154760ustar00rootroot00000000000000/* * out_curses.c Curses Output * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include enum { GRAPH_DISPLAY_SIDE_BY_SIDE = 1, GRAPH_DISPLAY_STANDARD = 2, }; enum { KEY_TOGGLE_LIST = 'l', KEY_TOGGLE_GRAPH = 'g', KEY_TOGGLE_DETAILS = 'd', KEY_TOGGLE_INFO = 'i', KEY_TOGGLE_IPV4 = '4', KEY_TOGGLE_IPV6 = '6', KEY_TOGGLE_TC = 't', KEY_COLLECT_HISTORY = 'h', KEY_CTRL_N = 14, KEY_CTRL_P = 16, }; #define DETAILS_COLS 68 #define INFO_VALUE_LEN 50 #define LIST_COL_1 31 #define LIST_COL_2 55 #define BRAILLE_RX_PAIR (LAYOUT_MAX + 1) #define BRAILLE_TX_PAIR (LAYOUT_MAX + 2) #define BRAILLE_DEFAULT_PAIR (LAYOUT_MAX + 3) /* Set to element_current() before drawing */ static struct element *current_element; static struct attr *current_attr; /* Length of list to draw, updated in draw_content() */ static int list_length; static int list_req; /* Number of graphs to draw (may be < c_ngraph) */ static int ngraph; /* * Offset in number of lines within the the element list of the currently * selected element. Updated while summing up required lines. */ static unsigned int selection_offset; /* * Offset in number of lines of the first element to be drawn. Updated * in draw_content() */ static int offset; /* * Offset to the first graph to draw in number of attributes with graphs. */ static unsigned int graph_offset; static int graph_display = GRAPH_DISPLAY_STANDARD; /* * Number of detail columns */ static int detail_cols; static int info_cols; static int initialized; static int print_help; static int help_page; /* Current row */ static int row; /* Number of rows */ static int rows; /* Number of columns */ static int cols; static int c_show_graph = 1; static int c_ngraph = 1; static int c_use_colors = 1; static int c_show_details = 0; static int c_show_list = 1; static int c_show_info = 0; static int c_show_ipv4 = 1; static int c_show_ipv6 = 1; static int c_show_tc = 1; static int c_list_min = 6; static struct graph_cfg c_graph_cfg = { .gc_width = 60, .gc_height = 6, .gc_foreground = '|', .gc_background = '.', .gc_noise = ':', .gc_unknown = '?', .gc_flags = GRAPH_CFG_BRAILLE, }; #define NEXT_ROW() \ do { \ row++; \ if (row >= rows - 1) \ return; \ move(row, 0); \ } while(0) static void apply_layout(int layout) { if (c_use_colors) attrset(COLOR_PAIR(layout) | cfg_layout[layout].l_attr); else attrset(cfg_layout[layout].l_attr); } static void apply_braille_graph_layout(int layout) { if (!c_use_colors) { attrset(cfg_layout[layout].l_attr); return; } if (layout == LAYOUT_RX_GRAPH) attrset(COLOR_PAIR(BRAILLE_RX_PAIR) | cfg_layout[layout].l_attr); else if (layout == LAYOUT_TX_GRAPH) attrset(COLOR_PAIR(BRAILLE_TX_PAIR) | cfg_layout[layout].l_attr); else apply_layout(layout); } static void apply_braille_default_layout(void) { if (c_use_colors) { attrset(COLOR_PAIR(BRAILLE_DEFAULT_PAIR) | cfg_layout[LAYOUT_LIST].l_attr); return; } attrset(A_NORMAL); } 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); return buf; } static void put_line(const char *fmt, ...) { va_list args; char *buf; int len; int x, y BMON_UNUSED; getyx(stdscr, y, x); len = cols - x; buf = xcalloc(len+1, 1); va_start(args, fmt); vsnprintf(buf, len+1, fmt, args); va_end(args); if (strlen(buf) < len) memset(&buf[strlen(buf)], ' ', len - strlen(buf)); addstr(buf); xfree(buf); } static void center_text(const char *fmt, ...) { va_list args; char *str; unsigned int col; va_start(args, fmt); if (vasprintf(&str, fmt, args) < 0) { fprintf(stderr, "vasprintf: Out of memory\n"); exit(ENOMEM); } va_end(args); col = (cols / 2) - (strlen(str) / 2); if (col > cols - 1) col = cols - 1; move(row, col); addstr(str); move(row, 0); xfree(str); } static int curses_init(void) { setlocale(LC_CTYPE, ""); if ((c_graph_cfg.gc_flags & GRAPH_CFG_BRAILLE) && MB_CUR_MAX < 2) { fprintf(stderr, "Braille graphs require a UTF-8 locale, falling back to classic graphs\n"); c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } if (!initscr()) { fprintf(stderr, "Unable to initialize curses screen\n"); return -EOPNOTSUPP; } initialized = 1; if (!has_colors()) c_use_colors = 0; if (c_use_colors) { int i; start_color(); #if defined HAVE_USE_DEFAULT_COLORS use_default_colors(); #endif for (i = 1; i < LAYOUT_MAX+1; i++) init_pair(i, cfg_layout[i].l_fg, cfg_layout[i].l_bg); init_pair(BRAILLE_RX_PAIR, cfg_layout[LAYOUT_RX_GRAPH].l_fg, cfg_layout[LAYOUT_LIST].l_bg); init_pair(BRAILLE_TX_PAIR, cfg_layout[LAYOUT_TX_GRAPH].l_fg, cfg_layout[LAYOUT_LIST].l_bg); init_pair(BRAILLE_DEFAULT_PAIR, cfg_layout[LAYOUT_LIST].l_fg, cfg_layout[LAYOUT_LIST].l_bg); } keypad(stdscr, TRUE); nonl(); cbreak(); noecho(); nodelay(stdscr, TRUE); /* getch etc. must be non-blocking */ clear(); curs_set(0); if (input_is_enabled("netlink")) c_show_tc = !input_get_opt("netlink", "notc"); return 0; } static void curses_shutdown(void) { if (initialized) endwin(); } struct detail_arg { int nattr; }; static void draw_attr_detail(struct element *e, struct attr *a, void *arg) { char *rx_u, *tx_u, buf1[32], buf2[32]; int rxprec, txprec, ncol; struct detail_arg *da = arg; double rx = unit_value2str(rate_get_total(&a->a_rx_rate), a->a_def->ad_unit, &rx_u, &rxprec); double tx = unit_value2str(rate_get_total(&a->a_tx_rate), a->a_def->ad_unit, &tx_u, &txprec); if (da->nattr >= detail_cols) { NEXT_ROW(); da->nattr = 0; } ncol = (da->nattr * DETAILS_COLS) - 1; move(row, ncol); if (ncol > 0) addch(ACS_VLINE); put_line(" %-14.14s %8s%-3s %8s%-3s", a->a_def->ad_description, (a->a_flags & ATTR_RX_ENABLED) ? float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u, (a->a_flags & ATTR_TX_ENABLED) ? float2str(tx, 8, txprec, buf2, sizeof(buf2)) : "-", tx_u); da->nattr++; } static void draw_details(void) { int i; struct detail_arg arg = { .nattr = 0, }; if (!current_element->e_nattrs) return; for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS) - 1, ACS_TTEE); NEXT_ROW(); put_line(""); for (i = 0; i < detail_cols; i++) { if (i > 0) mvaddch(row, (i * DETAILS_COLS) - 1, ACS_VLINE); move(row, (i * DETAILS_COLS) + 22); put_line("RX TX"); } NEXT_ROW(); element_foreach_attr(current_element, draw_attr_detail, &arg); /* * If the last row was incomplete, not all vlines have been drawn. * draw them here */ for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE); } static void draw_help(void) { #define HW 46 #define HH 22 int i, y = (rows/2) - (HH/2); int x = (cols/2) - (HW/2); char pad[HW+1]; memset(pad, ' ', sizeof(pad)); pad[sizeof(pad) - 1] = '\0'; attron(A_STANDOUT); for (i = 0; i < HH; i++) mvaddnstr(y + i, x, pad, -1); mvaddch(y - 1, x - 1, ACS_ULCORNER); mvaddch(y + HH, x - 1, ACS_LLCORNER); mvaddch(y - 1, x + HW, ACS_URCORNER); mvaddch(y + HH, x + HW, ACS_LRCORNER); for (i = 0; i < HH; i++) { mvaddch(y + i, x - 1, ACS_VLINE); mvaddch(y + i, x + HW, ACS_VLINE); } for (i = 0; i < HW; i++) { mvaddch(y - 1, x + i, ACS_HLINE); mvaddch(y + HH, x + i, ACS_HLINE); } attron(A_BOLD); mvaddnstr(y- 1, x+15, "QUICK REFERENCE", -1); attron(A_UNDERLINE); mvaddnstr(y+ 0, x+1, "Navigation", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 1, x+3, "Up, Down Previous/Next element", -1); mvaddnstr(y+ 2, x+3, "PgUp, PgDown Scroll up/down entire page", -1); mvaddnstr(y+ 3, x+3, "Left, Right Previous/Next attribute", -1); mvaddnstr(y+ 4, x+3, "[, ] Previous/Next group", -1); mvaddnstr(y+ 5, x+3, "? Toggle quick reference", -1); mvaddnstr(y+ 6, x+3, "q Quit bmon", -1); attron(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 8, x+1, "Display Settings", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+ 9, x+3, "d Toggle detailed statistics", -1); mvaddnstr(y+10, x+3, "l Toggle element list", -1); mvaddnstr(y+11, x+3, "t Toggle TC elements", -1); mvaddnstr(y+12, x+3, "i Toggle additional info", -1); mvaddnstr(y+13, x+3, "4 Toggle IPv4 addresses", -1); mvaddnstr(y+14, x+3, "6 Toggle IPv6 addresses", -1); attron(A_BOLD | A_UNDERLINE); mvaddnstr(y+16, x+1, "Graph Settings", -1); attroff(A_BOLD | A_UNDERLINE); mvaddnstr(y+17, x+3, "g Toggle graphical statistics", -1); mvaddnstr(y+18, x+3, "H Start recording history data", -1); mvaddnstr(y+19, x+3, "TAB Switch time unit of graph", -1); mvaddnstr(y+20, x+3, "<, > Change number of graphs", -1); mvaddnstr(y+21, x+3, "r Reset counter of element", -1); attroff(A_STANDOUT); row = y + HH; } static int lines_required_for_header(void) { return 1; } static void draw_header(void) { apply_layout(LAYOUT_STATUSBAR); if (current_element) put_line(" %s %c%s%c", current_element->e_name, current_element->e_description ? '(' : ' ', current_element->e_description ? : "", current_element->e_description ? ')' : ' '); else put_line(""); move(row, COLS - strlen(PACKAGE_STRING) - 1); put_line("%s", PACKAGE_STRING); move(row, 0); apply_layout(LAYOUT_LIST); } static int lines_required_for_statusbar(void) { return 1; } static void draw_statusbar(void) { static const char *help_text = "Press ? for help"; char s[27]; time_t t = time(NULL); apply_layout(LAYOUT_STATUSBAR); asctime_r(localtime(&t), s); s[strlen(s) - 1] = '\0'; row = rows-1; move(row, 0); put_line(" %s", s); move(row, COLS - strlen(help_text) - 1); put_line("%s", help_text); move(row, 0); } static void count_attr_graph(struct element *g, struct attr *a, void *arg) { if (a == current_attr) graph_offset = ngraph; ngraph++; } static int lines_required_for_graph(void) { int lines = 0; ngraph = 0; if (c_show_graph && current_element) { graph_display = GRAPH_DISPLAY_STANDARD; element_foreach_attr(current_element, count_attr_graph, NULL); if (ngraph > c_ngraph) ngraph = c_ngraph; /* check if we have room to draw graphs on the same level */ if (cols > (2 * (c_graph_cfg.gc_width + 10))) graph_display = GRAPH_DISPLAY_SIDE_BY_SIDE; /* +2 = header + time axis */ lines = ngraph * (graph_display * (c_graph_cfg.gc_height + 2)); } return lines + 1; } static int lines_required_for_details(void) { int lines = 1; if (c_show_details && current_element) { lines++; /* header */ detail_cols = cols / DETAILS_COLS; if (!detail_cols) detail_cols = 1; lines += (current_element->e_nattrs / detail_cols); if (current_element->e_nattrs % detail_cols) lines++; } return lines; } static void count_element_lines(struct element_group *g, struct element *e, void *arg) { int *lines = arg; if (e == current_element) selection_offset = *lines; (*lines)++; } static void count_group_lines(struct element_group *g, void *arg) { int *lines = arg; /* group title */ (*lines)++; group_foreach_element(g, &count_element_lines, arg); } static int lines_required_for_list(void) { int lines = 0; if (c_show_list) group_foreach(&count_group_lines, &lines); else lines = 1; return lines; } static inline int line_visible(int line) { return line >= offset && line < (offset + list_length); } static void draw_attr(double rate1, int prec1, char *unit1, double rate2, int prec2, char *unit2, float usage, int ncol) { char buf[32]; move(row, ncol); addch(ACS_VLINE); printw("%7s%-3s", float2str(rate1, 7, prec1, buf, sizeof(buf)), unit1); printw("%7s%-3s", float2str(rate2, 7, prec2, buf, sizeof(buf)), unit2); if (usage != FLT_MAX) printw("%2.0f%%", usage); else printw("%3s", ""); } static void draw_element(struct element_group *g, struct element *e, void *arg) { int *line = arg; apply_layout(LAYOUT_LIST); if (line_visible(*line)) { char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = ""; double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f; char pad[IFNAMSIZ + 32]; int rx1prec = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0; struct attr *a; NEXT_ROW(); if (e->e_key_attr[GT_MAJOR] && (a = attr_lookup(e, e->e_key_attr[GT_MAJOR]->ad_id))) attr_rate2float(a, &rx1, &rxu1, &rx1prec, &tx1, &txu1, &tx1prec); if (e->e_key_attr[GT_MINOR] && (a = attr_lookup(e, e->e_key_attr[GT_MINOR]->ad_id))) attr_rate2float(a, &rx2, &rxu2, &rx2prec, &tx2, &txu2, &tx2prec); memset(pad, 0, sizeof(pad)); memset(pad, ' ', e->e_level < 6 ? e->e_level * 2 : 12); strncat(pad, e->e_name, sizeof(pad) - strlen(pad) - 1); if (e->e_description) { strncat(pad, " (", sizeof(pad) - strlen(pad) - 1); strncat(pad, e->e_description, sizeof(pad) - strlen(pad) - 1); strncat(pad, ")", sizeof(pad) - strlen(pad) - 1); } if (*line == offset) { attron(A_BOLD); addch(ACS_UARROW); attroff(A_BOLD); addch(' '); } else if (e == current_element) { apply_layout(LAYOUT_SELECTED); addch(' '); attron(A_BOLD); addch(ACS_RARROW); attroff(A_BOLD); apply_layout(LAYOUT_LIST); } else if (*line == offset + list_length - 1 && *line < (list_req - 1)) { attron(A_BOLD); addch(ACS_DARROW); attroff(A_BOLD); addch(' '); } else printw(" "); put_line("%-30.30s", pad); draw_attr(rx1, rx1prec, rxu1, rx2, rx2prec, rxu2, e->e_rx_usage, LIST_COL_1); draw_attr(tx1, tx1prec, txu1, tx2, tx2prec, txu2, e->e_tx_usage, LIST_COL_2); } (*line)++; } static void draw_group(struct element_group *g, void *arg) { apply_layout(LAYOUT_HEADER); int *line = arg; if (line_visible(*line)) { NEXT_ROW(); attron(A_BOLD); put_line("%s", g->g_hdr->gh_title); attroff(A_BOLD); mvaddch(row, LIST_COL_1, ACS_VLINE); attron(A_BOLD); put_line("%7s %7s %%", g->g_hdr->gh_column[0], g->g_hdr->gh_column[1]); attroff(A_BOLD); mvaddch(row, LIST_COL_2, ACS_VLINE); attron(A_BOLD); put_line("%7s %7s %%", g->g_hdr->gh_column[2], g->g_hdr->gh_column[3]); } (*line)++; group_foreach_element(g, draw_element, arg); } static void draw_element_list(void) { int line = 0; group_foreach(draw_group, &line); } static inline int attr_visible(int nattr) { return nattr >= graph_offset && nattr < (graph_offset + ngraph); } static void draw_graph_centered(struct graph *g, int row, int ncol, const char *text) { int hcenter = (g->g_cfg.gc_width / 2) - (strlen(text) / 2) + 8; if (hcenter < 9) hcenter = 9; mvprintw(row, ncol + hcenter, "%.*s", g->g_cfg.gc_width, text); } static int is_braille_blank(const char *p) { return (unsigned char) p[0] == 0xe2 && (unsigned char) p[1] == 0xa0 && (unsigned char) p[2] == 0x80; } static void put_graph_row(struct graph *g, const char *line, int layout, int panel_end) { int i, maxcells, fillcells; int x, y; if (!(g->g_cfg.gc_flags & GRAPH_CFG_BRAILLE)) { put_line("%s", line); return; } getyx(stdscr, y, x); maxcells = cols - x; if (maxcells < 0) maxcells = 0; if (maxcells > g->g_cfg.gc_width) maxcells = g->g_cfg.gc_width; if (panel_end > cols) panel_end = cols; fillcells = panel_end - x; if (fillcells < 0) fillcells = 0; if (fillcells < maxcells) fillcells = maxcells; apply_braille_default_layout(); for (i = 0; i < fillcells; i++) addch(' '); for (i = 0; i < maxcells; i++) { const char *cell = line + (i * GRAPH_BRAILLE_CELL_BYTES); if (!is_braille_blank(cell)) { move(y, x + i); apply_braille_graph_layout(layout); addnstr(cell, GRAPH_BRAILLE_CELL_BYTES); } } move(y, x + fillcells); } static void draw_table(struct graph *g, struct graph_table *tbl, struct attr *a, struct history *h, const char *hdr, int ncol, int layout) { int i, save_row; char buf[32]; if (!tbl->gt_table) { for (i = g->g_cfg.gc_height; i >= 0; i--) { move(++row, ncol); put_line(""); } return; } move(++row, ncol); put_line("%8s", tbl->gt_y_unit ? : ""); snprintf(buf, sizeof(buf), "(%s %s/%s)", hdr, a->a_def->ad_description, h ? h->h_definition->hd_name : "?"); draw_graph_centered(g, row, ncol, buf); //move(row, ncol + g->g_cfg.gc_width - 3); //put_line("[err %.2f%%]", rtiming.rt_variance.v_error); memset(buf, 0, strlen(buf)); for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) { move(++row, ncol); sprintf(buf, "%'8.2f ", tbl->gt_scale[i]); addstr(buf); apply_layout(layout); put_graph_row(g, tbl->gt_table + (i * graph_row_size(&g->g_cfg)), layout, graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE && !ncol ? cols / 2 : cols); apply_layout(LAYOUT_LIST); } move(++row, ncol); put_line(" 1"); for (i = 1; i <= g->g_cfg.gc_width; i++) { if (i % 5 == 0) { move(row, ncol + i + 7); printw("%2d", i); } } if (!h) { const char *t1 = " No history data available. "; const char *t2 = " Press h to start collecting history. "; int vcenter = g->g_cfg.gc_height / 2; save_row = row; draw_graph_centered(g, save_row - vcenter - 1, ncol, t1); draw_graph_centered(g, save_row - vcenter, ncol, t2); row = save_row; } } static void draw_history_graph(struct attr *a, struct history *h) { struct graph *g; int ncol = 0, save_row; g = graph_alloc(h, &c_graph_cfg); graph_refill(g, h); save_row = row; draw_table(g, &g->g_rx, a, h, "RX", ncol, 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, LAYOUT_TX_GRAPH); graph_free(g); } static void draw_attr_graph(struct element *e, struct attr *a, void *arg) { int *nattr = arg; if (attr_visible(*nattr)) { struct history_def *sel; struct history *h; sel = history_current(); c_graph_cfg.gc_unit = a->a_def->ad_unit; list_for_each_entry(h, &a->a_history_list, h_list) { if (h->h_definition != sel) continue; draw_history_graph(a, h); goto out; } draw_history_graph(a, NULL); } out: (*nattr)++; } static void draw_graph(void) { int nattr = 0; element_foreach_attr(current_element, &draw_attr_graph, &nattr); } static int info_is_visible(struct info *info) { if (!strncasecmp(info->i_name, "IPv4[", 5)) return c_show_ipv4; if (!strncasecmp(info->i_name, "IPv6[", 5)) return c_show_ipv6; return 1; } static int lines_required_for_info(void) { int lines = 1; if (c_show_info) { struct info *info; int ninfo = 0; info_cols = cols / DETAILS_COLS; if (!info_cols) info_cols = 1; list_for_each_entry(info, ¤t_element->e_info_list, i_list) if (info_is_visible(info)) ninfo++; lines += (ninfo / info_cols); if (ninfo % info_cols) lines++; } return lines; } static void __draw_info(struct element *e, struct info *info, int *ninfo) { int ncol; if (!info_is_visible(info)) return; ncol = ((*ninfo) * DETAILS_COLS) - 1; move(row, ncol); if (ncol > 0) addch(ACS_VLINE); put_line(" %-14.14s %-*.*s", info->i_name, INFO_VALUE_LEN, INFO_VALUE_LEN, info->i_value); if (++(*ninfo) >= info_cols) { NEXT_ROW(); *ninfo = 0; } } static void draw_info(void) { struct info *info; int i, ninfo = 0; if (!current_element->e_ninfo) return; for (i = 1; i < detail_cols; i++) mvaddch(row, (i * DETAILS_COLS) - 1, c_show_details ? ACS_PLUS : ACS_TTEE); NEXT_ROW(); list_for_each_entry(info, ¤t_element->e_info_list, i_list) __draw_info(current_element, info, &ninfo); /* * If the last row was incomplete, not all vlines have been drawn. * draw them here */ for (i = 1; i < info_cols; i++) mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE); } static void draw_content(void) { int graph_req, details_req, lines_available, total_req; int info_req, empty_lines; int disable_graph = 0, disable_details = 0, disable_info = 0; if (!current_element) return; /* * Reset selection offset. Will be set in lines_required_for_list(). */ selection_offset = 0; offset = 0; /* Reset graph offset, will be set in lines_required_for_graph() */ graph_offset = 0; lines_available = rows - lines_required_for_statusbar() - lines_required_for_header(); list_req = lines_required_for_list(); graph_req = lines_required_for_graph(); details_req = lines_required_for_details(); info_req = lines_required_for_info(); total_req = list_req + graph_req + details_req + info_req; if (total_req <= lines_available) { /* * Enough lines available for all data to displayed, all * is good. Display the full list. */ list_length = list_req; goto draw; } /* * Not enough lines available for full list and all details * requested... */ if (c_show_list) { /* * ... try shortening the list first. */ list_length = lines_available - (total_req - list_req); if (list_length >= c_list_min) goto draw; } if (c_show_info) { /* try disabling info */ list_length = lines_available - (total_req - info_req + 1); if (list_length >= c_list_min) { disable_info = 1; goto draw; } } if (c_show_details) { /* ... try disabling details */ list_length = lines_available - (total_req - details_req + 1); if (list_length >= c_list_min) { disable_details = 1; goto draw; } } /* ... try disabling graph, details, and info */ list_length = lines_available - 1 - 1 - 1; if (list_length >= c_list_min) { disable_graph = 1; disable_details = 1; disable_info = 1; goto draw; } NEXT_ROW(); put_line("A minimum of %d lines is required to display content.\n", (rows - lines_available) + c_list_min + 2); return; draw: if (selection_offset && list_length > 0) { /* * Vertically align the selected element in the middle * of the list. */ offset = selection_offset - (list_length / 2); /* * If element 0..(list_length/2) is selected, offset is * negative here. Start drawing from first element. */ if (offset < 0) offset = 0; /* * Ensure the full list length is used if one of the * last (list_length/2) elements is selected. */ if (offset > (list_req - list_length)) offset = (list_req - list_length); if (offset >= list_req) BUG(); } if (c_show_list) { draw_element_list(); } else { NEXT_ROW(); hline(ACS_HLINE, cols); center_text(" Press %c to enable list view ", KEY_TOGGLE_LIST); } /* * Graphical statistics */ NEXT_ROW(); hline(ACS_HLINE, cols); 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 ", KEY_TOGGLE_GRAPH); else { if (disable_graph) center_text(" Increase screen height to see graphical statistics "); else draw_graph(); } empty_lines = rows - row - details_req - info_req - lines_required_for_statusbar() - 1; while (empty_lines-- > 0) { NEXT_ROW(); put_line(""); } /* * Detailed statistics */ NEXT_ROW(); hline(ACS_HLINE, cols); if (!c_show_details) center_text(" Press %c to enable detailed statistics ", KEY_TOGGLE_DETAILS); else { if (disable_details) center_text(" Increase screen height to see detailed statistics "); else draw_details(); } /* * Additional information */ NEXT_ROW(); hline(ACS_HLINE, cols); if (c_show_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); else { if (disable_info) center_text(" Increase screen height to see additional information "); else draw_info(); } } static void curses_draw(void) { row = 0; move(0,0); getmaxyx(stdscr, rows, cols); if (rows < 4) { clear(); put_line("Screen must be at least 4 rows in height"); goto out; } if (cols < 48) { clear(); put_line("Screen must be at least 48 columns width"); goto out; } current_element = element_current(); current_attr = attr_current(); draw_header(); apply_layout(LAYOUT_DEFAULT); draw_content(); /* fill empty lines with blanks */ while (row < (rows - 1 - lines_required_for_statusbar())) { move(++row, 0); put_line(""); } draw_statusbar(); if (print_help) { if (help_page == 0) draw_help(); #if 0 else draw_help_2(); #endif } out: attrset(0); 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 void toggle_tc_elements(int enable) { if (input_is_enabled("netlink")) { if (enable) { input_set("netlink:notc=0", true); } else { input_set("netlink:notc=1", true); } } } static int handle_input(int ch) { switch (ch) { case 'q': exit(0); return 1; case 0x1b: print_help = 0; return 1; case 12: case KEY_CLEAR: #ifdef HAVE_REDRAWWIN redrawwin(stdscr); #endif clear(); return 1; case '?': clear(); print_help = print_help ? 0 : 1; return 1; case KEY_TOGGLE_GRAPH: c_show_graph = !c_show_graph; if (c_show_graph && !c_ngraph) c_ngraph = 1; return 1; case KEY_TOGGLE_DETAILS: c_show_details = !c_show_details; return 1; case KEY_TOGGLE_LIST: c_show_list = !c_show_list; return 1; case KEY_TOGGLE_INFO: c_show_info = !c_show_info; return 1; case KEY_TOGGLE_IPV4: c_show_ipv4 = !c_show_ipv4; return 1; case KEY_TOGGLE_IPV6: c_show_ipv6 = !c_show_ipv6; return 1; case KEY_TOGGLE_TC: c_show_tc = !c_show_tc; toggle_tc_elements(c_show_tc); return 1; case KEY_COLLECT_HISTORY: if (current_attr) { attr_start_collecting_history(current_attr); return 1; } break; case KEY_PPAGE: { int i; for (i = 1; i < list_length; i++) element_select_prev(); } return 1; case KEY_NPAGE: { int i; for (i = 1; i < list_length; i++) element_select_next(); } return 1; case KEY_DOWN: case KEY_CTRL_N: element_select_next(); return 1; case KEY_UP: case KEY_CTRL_P: element_select_prev(); return 1; case KEY_LEFT: attr_select_prev(); return 1; case KEY_RIGHT: attr_select_next(); return 1; case ']': group_select_next(); return 1; case '[': group_select_prev(); return 1; case '<': c_ngraph--; if (c_ngraph <= 1) c_ngraph = 1; return 1; case '>': c_ngraph++; if (c_ngraph > 32) c_ngraph = 32; return 1; case '\t': history_select_next(); return 1; case 'r': reset_counters(); return 1; } return 0; } static void curses_pre(void) { static int init = 0; if (!init) { curses_init(); init = 1; } for (;;) { int ch = getch(); if (ch == -1) break; if (handle_input(ch)) curses_draw(); } } static void print_module_help(void) { printf( "curses - Curses Output\n" \ "\n" \ " Interactive curses UI. Press '?' to see help.\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " braille[=0|1] Enable(1)/disable(0) Braille-smoothed graphs (default: 1)\n" \ " fgchar=CHAR Classic graph foreground character (default: '|')\n" \ " bgchar=CHAR Classic graph background character (default: '.')\n" \ " nchar=CHAR Classic graph noise character (default: ':')\n" \ " uchar=CHAR Classic graph unknown character (default: '?')\n" \ " gheight=NUM Height of graph (default: 6)\n" \ " gwidth=NUM Width of graph (default: 60)\n" \ " ngraph=NUM Number of graphs (default: 1)\n" \ " nocolors Do not use colors\n" \ " graph Show graphical stats by default\n" \ " details Show detailed stats by default\n" \ " info Show additional info screen by default\n" \ " ipv4[=0|1] Show IPv4 addresses in additional info (default: 1)\n" \ " ipv6[=0|1] Show IPv6 addresses in additional info (default: 1)\n" \ " minlist=INT Minimum item list length\n"); } static void curses_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "fgchar") && value) { c_graph_cfg.gc_foreground = value[0]; c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } else if (!strcasecmp(type, "bgchar") && value) { c_graph_cfg.gc_background = value[0]; c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } else if (!strcasecmp(type, "nchar") && value) { c_graph_cfg.gc_noise = value[0]; c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } else if (!strcasecmp(type, "uchar") && value) { c_graph_cfg.gc_unknown = value[0]; c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } else if (!strcasecmp(type, "gheight") && value) c_graph_cfg.gc_height = strtol(value, NULL, 0); else if (!strcasecmp(type, "gwidth") && value) c_graph_cfg.gc_width = strtol(value, NULL, 0); else if (!strcasecmp(type, "ngraph") && value) { c_ngraph = strtol(value, NULL, 0); c_show_graph = !!c_ngraph; } else if (!strcasecmp(type, "details")) c_show_details = 1; else if (!strcasecmp(type, "info")) c_show_info = 1; else if (!strcasecmp(type, "ipv4")) c_show_ipv4 = value ? !!strtol(value, NULL, 0) : 1; else if (!strcasecmp(type, "ipv6")) c_show_ipv6 = value ? !!strtol(value, NULL, 0) : 1; else if (!strcasecmp(type, "nocolors")) c_use_colors = 0; else if (!strcasecmp(type, "braille")) { if (value ? !!strtol(value, NULL, 0) : 1) c_graph_cfg.gc_flags |= GRAPH_CFG_BRAILLE; else c_graph_cfg.gc_flags &= ~GRAPH_CFG_BRAILLE; } else if (!strcasecmp(type, "minlist") && value) c_list_min = strtol(value, NULL, 0); else if (!strcasecmp(type, "help")) { print_module_help(); exit(0); } } static struct bmon_module curses_ops = { .m_name = "curses", .m_flags = BMON_MODULE_DEFAULT, .m_shutdown = curses_shutdown, .m_pre = curses_pre, .m_do = curses_draw, .m_parse_opt = curses_parse_opt, }; static void __init do_curses_init(void) { output_register(&curses_ops); } bmon-5.0/src/out_format.c000066400000000000000000000225611525227747100154450ustar00rootroot00000000000000/* * out_format.c Formatted Output * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include static int c_quit_after = -1; static char *c_format; static int c_debug = 0; static FILE *c_fd; enum { OT_STRING, OT_TOKEN }; static struct out_token { int ot_type; char *ot_str; } *out_tokens; static int token_index; static int out_tokens_size; static char *get_token(struct element_group *g, struct element *e, const char *token, char *buf, size_t len) { if (!strncasecmp(token, "group:", 6)) { const char *n = token + 6; if (!strcasecmp(n, "nelements")) { snprintf(buf, len, "%u", g->g_nelements); return buf; } else if (!strcasecmp(n, "name")) return g->g_name; else if (!strcasecmp(n, "title")) return g->g_hdr->gh_title; } else if (!strncasecmp(token, "element:", 8)) { const char *n = token + 8; if (!strcasecmp(n, "name")) return e->e_name; else if (!strcasecmp(n, "description")) return e->e_description; else if (!strcasecmp(n, "nattrs")) { snprintf(buf, len, "%u", e->e_nattrs); return buf; } else if (!strcasecmp(n, "lifecycles")) { snprintf(buf, len, "%u", e->e_lifecycles); return buf; } else if (!strcasecmp(n, "level")) { snprintf(buf, len, "%u", e->e_level); return buf; } else if (!strcasecmp(n, "parent")) return e->e_parent ? e->e_parent->e_name : ""; else if (!strcasecmp(n, "id")) { snprintf(buf, len, "%u", e->e_id); return buf; } else if (!strcasecmp(n, "rxusage")) { snprintf(buf, len, "%2.0f", e->e_rx_usage == FLT_MAX ? e->e_rx_usage : 0.0f); return buf; } else if (!strcasecmp(n, "txusage")) { snprintf(buf, len, "%2.0f", e->e_tx_usage == FLT_MAX ? e->e_tx_usage : 0.0f); return buf; } else if (!strcasecmp(n, "haschilds")) { snprintf(buf, len, "%u", list_empty(&e->e_childs) ? 0 : 1); return buf; } } else if (!strncasecmp(token, "attr:", 5)) { const char *type = token + 5; const char *name = strchr(type, ':'); struct attr_def *def; struct attr *a; if (!name) { fprintf(stderr, "Invalid attribute field \"%s\"\n", type); goto out; } name++; def = attr_def_lookup(name); if (!def) { fprintf(stderr, "Undefined attribute \"%s\"\n", name); goto out; } if (!(a = attr_lookup(e, def->ad_id))) goto out; if (!strncasecmp(type, "rx:", 3)) { snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_rx_rate)); return buf; } else if (!strncasecmp(type, "tx:", 3)) { 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(type, "txrate:", 7)) { snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate); return buf; } } fprintf(stderr, "Unknown field \"%s\"\n", token); out: return "unknown"; } static void draw_element(struct element_group *g, struct element *e, void *arg) { int i; for (i = 0; i < token_index; i++) { char buf[128]; char *p; if (out_tokens[i].ot_type == OT_STRING) p = out_tokens[i].ot_str; else if (out_tokens[i].ot_type == OT_TOKEN) p = get_token(g, e, out_tokens[i].ot_str, buf, sizeof(buf)); else BUG(); if (p) fprintf(c_fd, "%s", p); } } static void format_draw(void) { group_foreach_recursive(draw_element, NULL); fflush(stdout); if (c_quit_after > 0) if (--c_quit_after == 0) exit(0); } static inline void add_token(int type, char *data) { if (!out_tokens_size) { out_tokens_size = 32; out_tokens = calloc(out_tokens_size, sizeof(struct out_token)); if (out_tokens == NULL) quit("Cannot allocate out token array\n"); } if (out_tokens_size <= token_index) { out_tokens_size += 32; out_tokens = realloc(out_tokens, out_tokens_size * sizeof(struct out_token)); if (out_tokens == NULL) quit("Cannot reallocate out token array\n"); } out_tokens[token_index].ot_type = type; out_tokens[token_index].ot_str = data; token_index++; } static int format_probe(void) { int new_one = 1; char *p, *e; for (p = c_format; *p; p++) { if (*p == '$') { char *s = p; s++; if (*s == '(') { s++; if (!*s) goto unexpected_end; e = strchr(s, ')'); if (e == NULL) goto invalid; *p = '\0'; *e = '\0'; add_token(OT_TOKEN, s); new_one = 1; p = e; continue; } } if (*p == '\\') { char *s = p; s++; switch (*s) { case 'n': *s = '\n'; goto finish_escape; case 't': *s = '\t'; goto finish_escape; case 'r': *s = '\r'; goto finish_escape; case 'v': *s = '\v'; goto finish_escape; case 'b': *s = '\b'; goto finish_escape; case 'f': *s = '\f'; goto finish_escape; case 'a': *s = '\a'; goto finish_escape; } goto out; finish_escape: *p = '\0'; add_token(OT_STRING, s); p = s; new_one = 0; continue; } out: if (new_one) { add_token(OT_STRING, p); new_one = 0; } } if (c_debug) { int i; for (i = 0; i < token_index; i++) printf(">>%s<\n", out_tokens[i].ot_str); } return 1; unexpected_end: fprintf(stderr, "Unexpected end of format string\n"); return 0; invalid: fprintf(stderr, "Missing ')' in format string\n"); return 0; } static void print_help(void) { printf( "format - Formatable Output\n" \ "\n" \ " Formatable ASCII output for scripts. Calls a drawing function for\n" \ " every item per node and outputs according to the specified format\n" \ " string. The format string consists of normal text and placeholders\n" \ " in the form of $(placeholder).\n" \ "\n" \ " Author: Thomas Graf \n" \ "\n" \ " Options:\n" \ " fmt=FORMAT Format string\n" \ " stderr Write to stderr instead of stdout\n" \ " quitafter=NUM Quit bmon after NUM outputs\n" \ "\n" \ " Placeholders:\n" \ " group:nelements Number of elements this group\n" \ " :name Name of group\n" \ " :title Title of group\n" \ " element:name Name of element\n" \ " :desc Description of element\n" \ " :nattrs Number of attributes\n" \ " :lifecycles Number of lifecycles\n" \ " :level Indentation level\n" \ " :parent Name of parent element\n" \ " :rxusage RX usage in percent\n" \ " :txusage TX usage in percent)\n" \ " :id ID of element\n" \ " :haschilds Indicate if element has children (0|1)\n" \ " attr:rx: RX counter of attribute \n" \ " :tx: TX counter of attribute \n" \ " :rxrate: RX rate of attribute \n" \ " :txrate: TX rate of attribute \n" \ "\n" \ " Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \ "\n" \ " Examples:\n" \ " '$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n'\n" \ " lo 12074 12074\n" \ "\n" \ " '$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n'\n" \ " eth0 33 5\n" \ "\n" \ " 'Item: $(element:name)\\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" \ "\n"); } static void format_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "stderr")) c_fd = stderr; else if (!strcasecmp(type, "debug")) c_debug = 1; else if (!strcasecmp(type, "fmt")) { xfree(c_format); c_format = xstrdup(value); } else if (!strcasecmp(type, "quitafter") && value) c_quit_after = strtol(value, NULL, 0); else if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static struct bmon_module format_ops = { .m_name = "format", .m_do = format_draw, .m_probe = format_probe, .m_parse_opt = format_parse_opt, }; static void __init ascii_init(void) { c_fd = stdout; c_format = xstrdup("$(element:name) $(attr:rx:bytes) $(attr:tx:bytes) " \ "$(attr:rx:packets) $(attr:tx:packets)\\n"); output_register(&format_ops); } bmon-5.0/src/out_json.c000066400000000000000000000130551525227747100151240ustar00rootroot00000000000000/* * out_json.c JSON Output * * Copyright (c) 2017 Paul Miller * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * Copyright (c) 2026 Architecture Technology Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include static int c_quit_after = -1; static char c_rschar = '\n'; static void json_print_string(const char *s) { putchar('"'); if (s) { const unsigned char *p; for (p = (const unsigned char *) s; *p; p++) { switch (*p) { case '"': fputs("\\\"", stdout); break; case '\\': fputs("\\\\", stdout); break; case '\b': fputs("\\b", stdout); break; case '\f': fputs("\\f", stdout); break; case '\n': fputs("\\n", stdout); break; case '\r': fputs("\\r", stdout); break; case '\t': fputs("\\t", stdout); break; default: if (*p < 0x20) printf("\\u%04x", *p); else putchar(*p); break; } } } putchar('"'); } static void json_print_float(double v) { long long iv; if (!isfinite(v)) { fputs("null", stdout); return; } /* Locale-independent: JSON requires '.' as the decimal separator */ if (v < 0) { putchar('-'); v = -v; } iv = (long long) (v * 100.0 + 0.5); printf("%lld.%02d", iv / 100, (int) (iv % 100)); } static void print_attr_detail(struct element *e BMON_UNUSED, struct attr *a, void *arg) { int *a_count = arg; const char *unit = a->a_def->ad_unit ? a->a_def->ad_unit->u_name : ""; if (*a_count > 0) printf(","); printf("\n "); json_print_string(a->a_def->ad_name); printf(": { \"desc\": "); json_print_string(a->a_def->ad_description); printf(", \"unit\": "); json_print_string(unit); printf(", \"rx\": %" PRIu64 ", \"tx\": %" PRIu64 ", \"rx_rate\": ", rate_get_total(&a->a_rx_rate), rate_get_total(&a->a_tx_rate)); json_print_float(a->a_rx_rate.r_rate); printf(", \"tx_rate\": "); json_print_float(a->a_tx_rate.r_rate); printf("}"); (*a_count)++; } static void json_draw_element(struct element_group *g BMON_UNUSED, struct element *e, void *arg) { int *e_count = arg; int a_count = 0; if (*e_count > 0) printf(","); printf("\n {\n \"name\": "); json_print_string(e->e_name); if (e->e_id) printf(",\n \"id\": %u", e->e_id); if (e->e_parent) { printf(",\n \"parent\": "); json_print_string(e->e_parent->e_name); } printf(",\n \"attrs\": {"); element_foreach_attr(e, print_attr_detail, &a_count); if (a_count > 0) printf("\n "); printf("}\n }"); (*e_count)++; } static void json_draw_group(struct element_group *g, void *arg) { int *g_count = arg; int e_count = 0; if (*g_count > 0) printf(",\n"); printf(" { \"name\": "); json_print_string(g->g_name); printf(", \"elements\": ["); group_foreach_element(g, json_draw_element, &e_count); if (e_count > 0) printf("\n "); printf("]}"); (*g_count)++; } static void json_draw(void) { int g_count = 0; printf("{\n \"timestamp\": %lld,\n \"groups\": [\n", (long long) time(NULL)); group_foreach(json_draw_group, &g_count); if (g_count > 0) printf("\n"); printf(" ]\n}%c", c_rschar); fflush(stdout); if (c_quit_after > 0) if (--c_quit_after == 0) exit(0); } static void print_help(void) { printf( "json - JSON output\n" \ "\n" \ " Prints one JSON object per update for scripting / streaming.\n" \ " Each object has a Unix timestamp and a groups array, followed\n" \ " by the record separator (default: newline).\n" \ "\n" \ " Example:\n" \ " bmon -p eth0 -o 'json:quitafter=1'\n" \ "\n" \ " Options:\n" \ " quitafter=NUM Quit bmon after NUM outputs\n" \ " rschar=CHAR Record separator after each JSON object\n" \ " (default: \\n)\n"); } static void json_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "rschar")) { if (value && value[0] != '\0') c_rschar = value[0]; } else if (!strcasecmp(type, "quitafter") && value) { char *endptr; c_quit_after = strtol(value, &endptr, 0); if (*endptr != '\0') quit("Invalid value for quitafter: '%s'\n", value); } else if (!strcasecmp(type, "help")) { print_help(); exit(0); } else quit("Unknown module option '%s'\n", type); } static struct bmon_module json_ops = { .m_name = "json", .m_do = json_draw, .m_parse_opt = json_parse_opt, }; static void __init json_init(void) { output_register(&json_ops); } bmon-5.0/src/out_null.c000066400000000000000000000033331525227747100151230ustar00rootroot00000000000000/* * out_null.c Null Output * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include static void print_help(void) { printf( "null - No output\n" \ "\n" \ " Disable primary output method\n" \ " Author: Thomas Graf \n" \ "\n"); } static void null_parse_opt(const char *type, const char *value) { if (!strcasecmp(type, "help")) { print_help(); exit(0); } } static struct bmon_module null_ops = { .m_name = "null", .m_parse_opt = null_parse_opt, }; static void __init null_init(void) { output_register(&null_ops); } bmon-5.0/src/output.c000066400000000000000000000050261525227747100146230ustar00rootroot00000000000000/* * output.c Output API * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include static struct bmon_subsys output_subsys; void output_register(struct bmon_module *m) { module_register(&output_subsys, m); } static void activate_default(void) { /* * Try to activate a default output module if the user did not make * a selection */ if (!output_subsys.s_nmod) { struct bmon_module *m; if (!output_set("curses")) return; if (!output_set("ascii")) return; /* Fall back to anything that could act as default */ list_for_each_entry(m, &output_subsys.s_mod_list, m_list) { if (m->m_flags & BMON_MODULE_DEFAULT) if (!output_set(m->m_name)) return; } quit("No output module found\n"); } } void output_pre(void) { module_foreach_run_enabled_pre(&output_subsys); } void output_draw(void) { module_foreach_run_enabled(&output_subsys); } void output_post(void) { module_foreach_run_enabled_post(&output_subsys); } int output_set(const char *name) { return module_set(&output_subsys, name, false); } static struct bmon_subsys output_subsys = { .s_name = "output", .s_activate_default = &activate_default, .s_mod_list = LIST_SELF(output_subsys.s_mod_list), }; static void __init __output_init(void) { return module_register_subsys(&output_subsys); } bmon-5.0/src/unit.c000066400000000000000000000116001525227747100142350ustar00rootroot00000000000000/* * unit.c Unit Definitions * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include static struct unit *byte_unit, *bit_unit; static LIST_HEAD(units); static struct list_head *get_flist(struct unit *unit) { int div = UNIT_DEFAULT; if (cfg_getbool(cfg, "use_bit")) div = UNIT_BIT; else if (cfg_getbool(cfg, "use_si")) div = UNIT_SI; if (!list_empty(&unit->u_div[div])) return &unit->u_div[div]; else return &unit->u_div[UNIT_DEFAULT]; } struct unit *unit_lookup(const char *name) { struct unit *unit; list_for_each_entry(unit, &units, u_list) if (!strcmp(name, unit->u_name)) return unit; return NULL; } /** * Lookup best divisor to use for a certain situation * @hint Value in question (for DYNAMIC_EXP) * @unit Unit of value * @name Place to store name of divisor used * @prec Place to store suggested precision * * Searches for the best divisor to be used depending on the unit * exponent configured by the user. If a dynamic exponent is * configured, the divisor is selected based on the value of hint * so that hint is divided into a small float >= 1.0. The name * of the divisor used is stored in *name. * * If prec points to a valid integer, a number of precision digits * is suggested to avoid n.00 to make pretty printing easier. */ double unit_divisor(uint64_t hint, struct unit *unit, char **name, int *prec) { struct list_head *flist = get_flist(unit); struct fraction *f; if (prec) *prec = 2; if (cfg_unit_exp == DYNAMIC_EXP) { list_for_each_entry_reverse(f, flist, f_list) { if (hint >= f->f_divisor) goto found_it; } } else { int n = cfg_unit_exp; list_for_each_entry(f, flist, f_list) { if (--n == 0) goto found_it; } } *name = ""; return 1; found_it: if (f->f_divisor == 1.0f && prec) *prec = 0; *name = f->f_name; return f->f_divisor; } double unit_value2str(uint64_t value, struct unit *unit, char **name, int *prec) { double div = unit_divisor(value, unit, name, prec); double v = (double) value; if (fmod(v, div) == 0.0f && prec) *prec = 0; return v / div; } void fraction_free(struct fraction *f) { if (!f) return; list_del(&f->f_list); xfree(f->f_name); xfree(f); } void unit_add_div(struct unit *unit, int type, const char *txt, float div) { struct fraction *f; if (!unit) BUG(); f = xcalloc(1, sizeof(*f)); init_list_head(&f->f_list); f->f_divisor = div; f->f_name = xstrdup(txt); list_add_tail(&f->f_list, &unit->u_div[type]); } struct unit *unit_add(const char *name) { struct unit *unit; int i; if (!(unit = unit_lookup(name))) { unit = xcalloc(1, sizeof(*unit)); unit->u_name = xstrdup(name); for (i = 0; i < __UNIT_MAX; i++) init_list_head(&unit->u_div[i]); list_add_tail(&unit->u_list, &units); } return unit; } static void unit_free(struct unit *u) { struct fraction *f, *n; if (!u) return; list_for_each_entry_safe(f, n, &u->u_div[UNIT_DEFAULT], f_list) fraction_free(f); list_for_each_entry_safe(f, n, &u->u_div[UNIT_SI], f_list) fraction_free(f); xfree(u->u_name); xfree(u); } char *unit_bytes2str(uint64_t bytes, char *buf, size_t len) { char *ustr; int prec; double v; if (byte_unit) { v = unit_value2str(bytes, byte_unit, &ustr, &prec); snprintf(buf, len, "%'.*f%3s", prec, v, ustr); } else snprintf(buf, len, "%" PRIu64, bytes); return buf; } char *unit_bit2str(uint64_t bits, char *buf, size_t len) { char *ustr; int prec; double v; if (bit_unit) { v = unit_value2str(bits, bit_unit, &ustr, &prec); snprintf(buf, len, "%'.*f%3s", prec, v, ustr); } else snprintf(buf, len, "%" PRIu64, bits); return buf; } static void __exit unit_exit(void) { struct unit *u, *n; list_for_each_entry_safe(u, n, &units, u_list) unit_free(u); } bmon-5.0/src/utils.c000066400000000000000000000217561525227747100144330ustar00rootroot00000000000000/* * utils.c General purpose utilities * * Copyright (c) 2001-2013 Thomas Graf * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #ifdef __MACH__ #include #include #endif void *xcalloc(size_t n, size_t s) { void *d = calloc(n, s); if (NULL == d) { fprintf(stderr, "xalloc: Out of memory\n"); exit(ENOMEM); } return d; } void *xrealloc(void *p, size_t s) { void *d = realloc(p, s); if (NULL == d) { fprintf(stderr, "xrealloc: Out of memory!\n"); exit(ENOMEM); } return d; } char *xstrdup(const char *p) { char *d = strdup(p); if (NULL == d) { fprintf(stderr, "xstrdup: Out of memory!\n"); exit(ENOMEM); } return d; } void xfree(void *d) { if (d) free(d); } float timestamp_to_float(timestamp_t *src) { return (float) src->tv_sec + ((float) src->tv_usec / 1000000.0f); } int64_t timestamp_to_int(timestamp_t *src) { return (src->tv_sec * 1000000ULL) + src->tv_usec; } void float_to_timestamp(timestamp_t *dst, float src) { dst->tv_sec = (time_t) src; dst->tv_usec = (src - ((float) ((time_t) src))) * 1000000.0f; } void timestamp_add(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2) { dst->tv_sec = src1->tv_sec + src2->tv_sec; dst->tv_usec = src1->tv_usec + src2->tv_usec; if (dst->tv_usec >= 1000000) { dst->tv_sec++; dst->tv_usec -= 1000000; } } void timestamp_sub(timestamp_t *dst, timestamp_t *src1, timestamp_t *src2) { dst->tv_sec = src1->tv_sec - src2->tv_sec; dst->tv_usec = src1->tv_usec - src2->tv_usec; if (dst->tv_usec < 0) { dst->tv_sec--; dst->tv_usec += 1000000; } } int timestamp_le(timestamp_t *a, timestamp_t *b) { if (a->tv_sec > b->tv_sec) return 0; if (a->tv_sec < b->tv_sec || a->tv_usec <= b->tv_usec) return 1; return 0; } int timestamp_is_negative(timestamp_t *ts) { return (ts->tv_sec < 0 || ts->tv_usec < 0); } void update_timestamp(timestamp_t *dst) { #ifdef __MACH__ clock_serv_t cclock; mach_timespec_t tp; 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; 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) { ts1->tv_sec = ts2->tv_sec; ts1->tv_usec = ts2->tv_usec; } float timestamp_diff(timestamp_t *t1, timestamp_t *t2) { float diff; diff = t2->tv_sec - t1->tv_sec; diff += (((float) t2->tv_usec - (float) t1->tv_usec) / 1000000.0f); return diff; } #if 0 float diff_now(timestamp_t *t1) { timestamp_t now; update_ts(&now); return time_diff(t1, &now); } const char *xinet_ntop(struct sockaddr *src, char *dst, socklen_t cnt) { void *s; int family; if (src->sa_family == AF_INET6) { s = &((struct sockaddr_in6 *) src)->sin6_addr; family = AF_INET6; } else if (src->sa_family == AF_INET) { s = &((struct sockaddr_in *) src)->sin_addr; family = AF_INET; } else return NULL; return inet_ntop(family, s, dst, cnt); } uint64_t parse_size(const char *str) { char *p; uint64_t l = strtol(str, &p, 0); if (p == str) return -1; if (*p) { if (!strcasecmp(p, "kb") || !strcasecmp(p, "k")) l *= 1024; else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g")) l *= 1024*1024*1024; else if (!strcasecmp(p, "gbit")) l *= 1024*1024*1024/8; else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m")) l *= 1024*1024; else if (!strcasecmp(p, "mbit")) l *= 1024*1024/8; else if (!strcasecmp(p, "kbit")) l *= 1024/8; else if (strcasecmp(p, "b") != 0) return -1; } return l; } #ifndef HAVE_STRDUP char *strdup(const char *s) { char *t = xcalloc(1, strlen(s) + 1); memcpy(t, s, strlen(s)); return s; } #endif char *timestamp2str(timestamp_t *ts, char *buf, size_t len) { int i, split[5]; char *units[] = {"d", "h", "m", "s", "usec"}; time_t sec = ts->tv_sec; #define _SPLIT(idx, unit) if ((split[idx] = sec / unit) > 0) sec %= unit _SPLIT(0, 86400); /* days */ _SPLIT(1, 3600); /* hours */ _SPLIT(2, 60); /* minutes */ _SPLIT(3, 1); /* seconds */ #undef _SPLIT split[4] = ts->tv_usec; memset(buf, 0, len); for (i = 0; i < ARRAY_SIZE(split); i++) { if (split[i] > 0) { char t[64]; snprintf(t, sizeof(t), "%s%d%s", strlen(buf) ? " " : "", split[i], units[i]); strncat(buf, t, len - strlen(buf) - 1); } } return buf; } int parse_date(const char *str, xdate_t *dst) { time_t now = time(NULL); struct tm *now_tm = localtime(&now); const char *next; char *p; struct tm backup; memset(dst, 0, sizeof(*dst)); if (strchr(str, '-')) { next = strptime(str, "%Y-%m-%d", &dst->d_tm); if (next == NULL || (*next != '\0' && *next != ' ')) goto invalid_date; } else { dst->d_tm.tm_mday = now_tm->tm_mday; dst->d_tm.tm_mon = now_tm->tm_mon; dst->d_tm.tm_year = now_tm->tm_year; dst->d_tm.tm_wday = now_tm->tm_wday; dst->d_tm.tm_yday = now_tm->tm_yday; dst->d_tm.tm_isdst = now_tm->tm_isdst; next = str; } if (*next == '\0') return 0; while (*next == ' ') next++; if (*next == '.') goto read_us; /* Make a backup, we can't rely on strptime to not screw * up what we've got so far. */ memset(&backup, 0, sizeof(backup)); memcpy(&backup, &dst->d_tm, sizeof(backup)); next = strptime(next, "%H:%M:%S", &dst->d_tm); if (next == NULL || (*next != '\0' && *next != '.')) goto invalid_date; dst->d_tm.tm_mday = backup.tm_mday; dst->d_tm.tm_mon = backup.tm_mon; dst->d_tm.tm_year = backup.tm_year; dst->d_tm.tm_wday = backup.tm_wday; dst->d_tm.tm_yday = backup.tm_yday; dst->d_tm.tm_isdst = backup.tm_isdst; if (*next == '\0') return 0; read_us: if (*next == '.') next++; else BUG(); dst->d_usec = strtoul(next, &p, 10); if (*p != '\0') goto invalid_date; return 0; invalid_date: fprintf(stderr, "Invalid date \"%s\"\n", str); return -1; } static inline void print_token(FILE *fd, struct db_token *tok) { fprintf(fd, "%s", tok->t_name); if (tok->t_flags & DB_T_ATTR) fprintf(fd, ""); } void db_print_filter(FILE *fd, struct db_filter *filter) { if (filter->f_node) print_token(fd, filter->f_node); if (filter->f_group) { fprintf(fd, "."); print_token(fd, filter->f_group); } if (filter->f_item) { fprintf(fd, "."); print_token(fd, filter->f_item); } if (filter->f_attr) { fprintf(fd, "."); print_token(fd, filter->f_attr); } if (filter->f_field) fprintf(fd, "@%s", filter->f_field); } void *db_filter__scan_string(const char *); void db_filter__switch_to_buffer(void *); int db_filter_parse(void); struct db_filter * parse_db_filter(const char *buf) { struct db_filter *f; struct db_token *tok, *t; void *state = db_filter__scan_string(buf); db_filter__switch_to_buffer(state); if (db_filter_parse()) { fprintf(stderr, "Failed to parse filter \"%s\"\n", buf); return NULL; } tok = db_filter_out; /* generated by yacc */ if (tok == NULL) return NULL; f = xcalloc(1, sizeof(*f)); f->f_node = tok; if (!tok->t_next) goto out; tok = tok->t_next; if (tok->t_flags & DB_T_ATTR) { fprintf(stderr, "Node may not contain an attribute field\n"); goto errout; } f->f_group = tok; if (!tok->t_next) goto out; tok = tok->t_next; if (tok->t_flags & DB_T_ATTR) { fprintf(stderr, "Group may not contain an attribute field\n"); goto errout; } f->f_item = tok; if (!tok->t_next) goto out; tok = tok->t_next; if (tok->t_flags & DB_T_ATTR) { if (!tok->t_name) BUG(); f->f_field = tok->t_name; goto out; } else f->f_attr = tok; if (!tok->t_next) goto out; tok = tok->t_next; if (tok->t_flags & DB_T_ATTR) { if (!tok->t_name) BUG(); f->f_field = tok->t_name; } else { fprintf(stderr, "Unexpected additional token after attribute\n"); goto errout; } out: /* free unused tokens */ for (tok = tok->t_next ; tok; tok = t) { t = tok->t_next; xfree(tok->t_name); xfree(tok); } return f; errout: xfree(f); f = NULL; tok = db_filter_out; goto out; } #endif