]> arthur.barton.de Git - netdata.git/commitdiff
converted tabs for C, JS, BASH to 4 spaces
authorCosta Tsaousis <costa@tsaousis.gr>
Sat, 13 Aug 2016 19:08:15 +0000 (22:08 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Sat, 13 Aug 2016 19:08:15 +0000 (22:08 +0300)
68 files changed:
netdata-installer.sh
node.d/named.node.js
node.d/sma_webbox.node.js
node.d/snmp.node.js
plugins.d/cgroup-name.sh
plugins.d/charts.d.dryrun-helper.sh
plugins.d/charts.d.plugin
plugins.d/loopsleepms.sh.inc
plugins.d/node.d.plugin
plugins.d/tc-qos-helper.sh
src/appconfig.c
src/apps_plugin.c
src/avl.c
src/avl.h
src/common.c
src/daemon.c
src/dictionary.c
src/dictionary.h
src/global_statistics.h
src/log.c
src/log.h
src/main.h
src/plugin_checks.c
src/plugin_idlejitter.c
src/plugin_nfacct.c
src/plugin_proc.c
src/plugin_tc.c
src/plugins_d.c
src/plugins_d.h
src/popen.c
src/proc_diskstats.c
src/proc_interrupts.c
src/proc_loadavg.c
src/proc_meminfo.c
src/proc_net_dev.c
src/proc_net_ip_vs_stats.c
src/proc_net_netstat.c
src/proc_net_rpc_nfsd.c
src/proc_net_snmp.c
src/proc_net_snmp6.c
src/proc_net_stat_conntrack.c
src/proc_net_stat_synproxy.c
src/proc_self_mountinfo.c
src/proc_self_mountinfo.h
src/proc_softirqs.c
src/proc_stat.c
src/proc_sys_kernel_random_entropy_avail.c
src/proc_vmstat.c
src/procfile.c
src/procfile.h
src/registry.c
src/rrd.c
src/rrd.h
src/rrd2json.c
src/rrd2json.h
src/storage_number.c
src/storage_number.h
src/sys_fs_cgroup.c
src/sys_kernel_mm_ksm.c
src/unit_test.c
src/url.c
src/web_buffer.c
src/web_buffer.h
src/web_buffer_svg.c
src/web_client.c
src/web_client.h
src/web_server.c
src/web_server.h

index d465cc08b4d21658aa64c863943150e6dd3ee88b..1a3e1a188cdcc8605e89313a41e799075c3bc0f5 100755 (executable)
@@ -26,18 +26,18 @@ printf "\n" >>netdata-installer.log
 service="$(which service 2>/dev/null || command -v service 2>/dev/null)"
 systemctl="$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)"
 service() {
-       local cmd="${1}" action="${2}"
-
-       if [ ! -z "${service}" ]
-       then
-               run "${service}" "${cmd}" "${action}"
-               return $?
-       elif [ ! -z "${systemctl}" ]
-       then
-               run "${systemctl}" "${action}" "${cmd}"
-               return $?
-       fi
-       return 1
+    local cmd="${1}" action="${2}"
+
+    if [ ! -z "${service}" ]
+    then
+        run "${service}" "${cmd}" "${action}"
+        return $?
+    elif [ ! -z "${systemctl}" ]
+    then
+        run "${systemctl}" "${action}" "${cmd}"
+        return $?
+    fi
+    return 1
 }
 
 ME="$0"
@@ -47,353 +47,353 @@ NETDATA_PREFIX=
 LIBS_ARE_HERE=0
 
 usage() {
-       cat <<-USAGE
+    cat <<-USAGE
 
-       ${ME} <installer options>
+    ${ME} <installer options>
 
-       Valid <installer options> are:
+    Valid <installer options> are:
 
-          --install /PATH/TO/INSTALL
+       --install /PATH/TO/INSTALL
 
-                       If your give: --install /opt
-                       netdata will be installed in /opt/netdata
+            If your give: --install /opt
+            netdata will be installed in /opt/netdata
 
-          --dont-start-it
+       --dont-start-it
 
-                       Do not (re)start netdata.
-                       Just install it.
+            Do not (re)start netdata.
+            Just install it.
 
-          --dont-wait
+       --dont-wait
 
-                       Do not wait for the user to press ENTER.
-                       Start immediately building it.
+            Do not wait for the user to press ENTER.
+            Start immediately building it.
 
-          --zlib-is-really-here
-          --libs-are-really-here
+       --zlib-is-really-here
+       --libs-are-really-here
 
-                       If you get errors about missing zlib,
-                       or libuuid but you know it is available,
-                       you have a broken pkg-config.
-                       Use this option to allow it continue
-                       without checking pkg-config.
+            If you get errors about missing zlib,
+            or libuuid but you know it is available,
+            you have a broken pkg-config.
+            Use this option to allow it continue
+            without checking pkg-config.
 
-       Netdata will by default be compiled with gcc optimization -O3
-       If you need to pass different CFLAGS, use something like this:
+    Netdata will by default be compiled with gcc optimization -O3
+    If you need to pass different CFLAGS, use something like this:
 
-         CFLAGS="<gcc options>" ${ME} <installer options>
+      CFLAGS="<gcc options>" ${ME} <installer options>
 
-       For the installer to complete successfully, you will need
-       these packages installed:
+    For the installer to complete successfully, you will need
+    these packages installed:
 
-          gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel)
-          uuid-dev (or libuuid-devel)
+       gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel)
+       uuid-dev (or libuuid-devel)
 
-       For the plugins, you will at least need:
+    For the plugins, you will at least need:
 
-          curl nodejs
+       curl nodejs
 
 USAGE
 }
 
 md5sum="$(which md5sum 2>/dev/null || command -v md5sum 2>/dev/null)"
 get_git_config_signatures() {
-       local x s file md5
-
-       [ ! -d "conf.d" ] && echo >&2 "Wrong directory." && return 1
-       [ -z "${md5sum}" -o ! -x "${md5sum}" ] && echo >&2 "No md5sum command." && return 1
-
-       echo >configs.signatures.tmp
-
-       for x in $(find conf.d -name \*.conf)
-       do
-               x="${x/conf.d\//}"
-               echo "${x}"
-               for c in $(git log --follow "conf.d/${x}" | grep ^commit | cut -d ' ' -f 2)
-               do
-                       git checkout ${c} "conf.d/${x}" || continue
-                       s="$(cat "conf.d/${x}" | md5sum | cut -d ' ' -f 1)"
-                       echo >>configs.signatures.tmp "${x}:${s}"
-                       echo "    ${s}"
-               done
-               git checkout HEAD "conf.d/${x}" || break
-       done
-
-       cat configs.signatures.tmp |\
-               grep -v "^$" |\
-               sort -u |\
-               {
-                       echo "declare -A configs_signatures=("
-                       IFS=":"
-                       while read file md5
-                       do
-                               echo "  ['${md5}']='${file}'"
-                       done
-                       echo ")"
-               } >configs.signatures
-
-       rm configs.signatures.tmp
-
-       return 0
+    local x s file md5
+
+    [ ! -d "conf.d" ] && echo >&2 "Wrong directory." && return 1
+    [ -z "${md5sum}" -o ! -x "${md5sum}" ] && echo >&2 "No md5sum command." && return 1
+
+    echo >configs.signatures.tmp
+
+    for x in $(find conf.d -name \*.conf)
+    do
+            x="${x/conf.d\//}"
+            echo "${x}"
+            for c in $(git log --follow "conf.d/${x}" | grep ^commit | cut -d ' ' -f 2)
+            do
+                    git checkout ${c} "conf.d/${x}" || continue
+                    s="$(cat "conf.d/${x}" | md5sum | cut -d ' ' -f 1)"
+                    echo >>configs.signatures.tmp "${x}:${s}"
+                    echo "    ${s}"
+            done
+            git checkout HEAD "conf.d/${x}" || break
+    done
+
+    cat configs.signatures.tmp |\
+        grep -v "^$" |\
+        sort -u |\
+        {
+            echo "declare -A configs_signatures=("
+            IFS=":"
+            while read file md5
+            do
+                echo "  ['${md5}']='${file}'"
+            done
+            echo ")"
+        } >configs.signatures
+
+    rm configs.signatures.tmp
+
+    return 0
 }
 
 
 while [ ! -z "${1}" ]
 do
-       if [ "$1" = "--install" ]
-               then
-               NETDATA_PREFIX="${2}/netdata"
-               shift 2
-       elif [ "$1" = "--zlib-is-really-here" -o "$1" = "--libs-are-really-here" ]
-               then
-               LIBS_ARE_HERE=1
-               shift 1
-       elif [ "$1" = "--dont-start-it" ]
-               then
-               DONOTSTART=1
-               shift 1
-       elif [ "$1" = "--dont-wait" ]
-               then
-               DONOTWAIT=1
-               shift 1
-       elif [ "$1" = "--help" -o "$1" = "-h" ]
-               then
-               usage
-               exit 1
-       elif [ "$1" = "get_git_config_signatures" ]
-               then
-               get_git_config_signatures && exit 0
-               exit 1
-       else
-               echo >&2
-               echo >&2 "ERROR:"
-               echo >&2 "I cannot understand option '$1'."
-               usage
-               exit 1
-       fi
+    if [ "$1" = "--install" ]
+        then
+        NETDATA_PREFIX="${2}/netdata"
+        shift 2
+    elif [ "$1" = "--zlib-is-really-here" -o "$1" = "--libs-are-really-here" ]
+        then
+        LIBS_ARE_HERE=1
+        shift 1
+    elif [ "$1" = "--dont-start-it" ]
+        then
+        DONOTSTART=1
+        shift 1
+    elif [ "$1" = "--dont-wait" ]
+        then
+        DONOTWAIT=1
+        shift 1
+    elif [ "$1" = "--help" -o "$1" = "-h" ]
+        then
+        usage
+        exit 1
+    elif [ "$1" = "get_git_config_signatures" ]
+        then
+        get_git_config_signatures && exit 0
+        exit 1
+    else
+        echo >&2
+        echo >&2 "ERROR:"
+        echo >&2 "I cannot understand option '$1'."
+        usage
+        exit 1
+    fi
 done
 
 cat <<-BANNER
 
-       Welcome to netdata!
-       Nice to see you are giving it a try!
+    Welcome to netdata!
+    Nice to see you are giving it a try!
 
-       You are about to build and install netdata to your system.
+    You are about to build and install netdata to your system.
 
-       It will be installed at these locations:
+    It will be installed at these locations:
 
-         - the daemon    at ${NETDATA_PREFIX}/usr/sbin/netdata
-         - config files  at ${NETDATA_PREFIX}/etc/netdata
-         - web files     at ${NETDATA_PREFIX}/usr/share/netdata
-         - plugins       at ${NETDATA_PREFIX}/usr/libexec/netdata
-         - cache files   at ${NETDATA_PREFIX}/var/cache/netdata
-         - db files      at ${NETDATA_PREFIX}/var/lib/netdata
-         - log files     at ${NETDATA_PREFIX}/var/log/netdata
-         - pid file      at ${NETDATA_PREFIX}/var/run
+      - the daemon    at ${NETDATA_PREFIX}/usr/sbin/netdata
+      - config files  at ${NETDATA_PREFIX}/etc/netdata
+      - web files     at ${NETDATA_PREFIX}/usr/share/netdata
+      - plugins       at ${NETDATA_PREFIX}/usr/libexec/netdata
+      - cache files   at ${NETDATA_PREFIX}/var/cache/netdata
+      - db files      at ${NETDATA_PREFIX}/var/lib/netdata
+      - log files     at ${NETDATA_PREFIX}/var/log/netdata
+      - pid file      at ${NETDATA_PREFIX}/var/run
 
-       This installer allows you to change the installation path.
-       Press Control-C and run the same command with --help for help.
+    This installer allows you to change the installation path.
+    Press Control-C and run the same command with --help for help.
 
 BANNER
 
 if [ "${UID}" -ne 0 ]
-       then
-       if [ -z "${NETDATA_PREFIX}" ]
-               then
-               cat <<-NONROOTNOPREFIX
+    then
+    if [ -z "${NETDATA_PREFIX}" ]
+        then
+        cat <<-NONROOTNOPREFIX
 
-               Sorry! This will fail!
+        Sorry! This will fail!
 
-               You are attempting to install netdata as non-root, but you plan to install it
-               in system paths.
+        You are attempting to install netdata as non-root, but you plan to install it
+        in system paths.
 
-               Please set an installation prefix, like this:
+        Please set an installation prefix, like this:
 
-                       $0 ${@} --install /tmp
+            $0 ${@} --install /tmp
 
-               or, run the installer as root:
+        or, run the installer as root:
 
-                       sudo $0 ${@}
+            sudo $0 ${@}
 
-               We suggest to install it as root, or certain data collectors will not be able
-               to work. Netdata drops root privileges when running. So, if you plan to keep
-               it, install it as root to get the full functionality.
+        We suggest to install it as root, or certain data collectors will not be able
+        to work. Netdata drops root privileges when running. So, if you plan to keep
+        it, install it as root to get the full functionality.
 
 NONROOTNOPREFIX
-               exit 1
+        exit 1
 
-       else
-               cat <<-NONROOT
+    else
+        cat <<-NONROOT
 
-               IMPORTANT:
-               You are about to install netdata as a non-root user.
-               Netdata will work, but a few data collection modules that
-               require root access will fail.
+        IMPORTANT:
+        You are about to install netdata as a non-root user.
+        Netdata will work, but a few data collection modules that
+        require root access will fail.
 
-               If you installing permanently on your system, run the
-               installer like this:
+        If you installing permanently on your system, run the
+        installer like this:
 
-                       sudo $0 ${@}
+            sudo $0 ${@}
 
 NONROOT
-       fi
+    fi
 fi
 
 have_autotools=
 if [ "$(type autoreconf 2> /dev/null)" ]
 then
-       autoconf_maj_min() {
-               local maj min IFS=.-
-
-               maj=$1
-               min=$2
-
-               set -- $(autoreconf -V | sed -ne '1s/.* \([^ ]*\)$/\1/p')
-               eval $maj=\$1 $min=\$2
-       }
-       autoconf_maj_min AMAJ AMIN
-
-       if [ "$AMAJ" -gt 2 ]
-       then
-               have_autotools=Y
-       elif [ "$AMAJ" -eq 2 -a "$AMIN" -ge 60 ]
-       then
-               have_autotools=Y
-       else
-               echo "Found autotools $AMAJ.$AMIN"
-       fi
+    autoconf_maj_min() {
+        local maj min IFS=.-
+
+        maj=$1
+        min=$2
+
+        set -- $(autoreconf -V | sed -ne '1s/.* \([^ ]*\)$/\1/p')
+        eval $maj=\$1 $min=\$2
+    }
+    autoconf_maj_min AMAJ AMIN
+
+    if [ "$AMAJ" -gt 2 ]
+    then
+        have_autotools=Y
+    elif [ "$AMAJ" -eq 2 -a "$AMIN" -ge 60 ]
+    then
+        have_autotools=Y
+    else
+        echo "Found autotools $AMAJ.$AMIN"
+    fi
 else
-       echo "No autotools found"
+    echo "No autotools found"
 fi
 
 if [ ! "$have_autotools" ]
 then
-       if [ -f configure ]
-       then
-               echo "Will skip autoreconf step"
-       else
-               cat <<-"EOF"
+    if [ -f configure ]
+    then
+        echo "Will skip autoreconf step"
+    else
+        cat <<-"EOF"
 
-               -------------------------------------------------------------------------------
-               autotools 2.60 or later is required
+        -------------------------------------------------------------------------------
+        autotools 2.60 or later is required
 
-               Sorry, you do not seem to have autotools 2.60 or later, which is
-               required to build from the git sources of netdata.
+        Sorry, you do not seem to have autotools 2.60 or later, which is
+        required to build from the git sources of netdata.
 
-               You can either install a suitable version of autotools and automake
-               or download a netdata package which does not have these dependencies.
+        You can either install a suitable version of autotools and automake
+        or download a netdata package which does not have these dependencies.
 
-               Source packages where autotools have already been run are available
-               here:
-                          https://firehol.org/download/netdata/
+        Source packages where autotools have already been run are available
+        here:
+               https://firehol.org/download/netdata/
 
-               The unsigned/master folder tracks the head of the git tree and released
-               packages are also available.
+        The unsigned/master folder tracks the head of the git tree and released
+        packages are also available.
 EOF
-               exit 1
-       fi
+        exit 1
+    fi
 fi
 
 if [ ${DONOTWAIT} -eq 0 ]
-       then
-       if [ ! -z "${NETDATA_PREFIX}" ]
-               then
-               read -p "Press ENTER to build and install netdata to '${NETDATA_PREFIX}' > "
-       else
-               read -p "Press ENTER to build and install netdata to your system > "
-       fi
+    then
+    if [ ! -z "${NETDATA_PREFIX}" ]
+        then
+        read -p "Press ENTER to build and install netdata to '${NETDATA_PREFIX}' > "
+    else
+        read -p "Press ENTER to build and install netdata to your system > "
+    fi
 fi
 
 build_error() {
-       cat <<-EOF
+    cat <<-EOF
 
-       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-       Sorry! NetData failed to build...
+    Sorry! NetData failed to build...
 
-       You many need to check these:
+    You many need to check these:
 
-       1. The package uuid-dev (or libuuid-devel) has to be installed.
+    1. The package uuid-dev (or libuuid-devel) has to be installed.
 
-          If your system cannot find libuuid, although it is installed
-          run me with the option:  --libs-are-really-here
+       If your system cannot find libuuid, although it is installed
+       run me with the option:  --libs-are-really-here
 
-       2. The package zlib1g-dev (or zlib-devel) has to be installed.
+    2. The package zlib1g-dev (or zlib-devel) has to be installed.
 
-          If your system cannot find zlib, although it is installed
-          run me with the option:  --libs-are-really-here
+       If your system cannot find zlib, although it is installed
+       run me with the option:  --libs-are-really-here
 
-       3. You need basic build tools installed, like:
+    3. You need basic build tools installed, like:
 
-          gcc make autoconf automake pkg-config
+       gcc make autoconf automake pkg-config
 
-          Autoconf version 2.60 or higher is required.
+       Autoconf version 2.60 or higher is required.
 
-       If you still cannot get it to build, ask for help at github:
+    If you still cannot get it to build, ask for help at github:
 
-          https://github.com/firehol/netdata/issues
+       https://github.com/firehol/netdata/issues
 
 
 EOF
-       trap - EXIT
-       exit 1
+    trap - EXIT
+    exit 1
 }
 
 run() {
-       printf >>netdata-installer.log "# "
-       printf >>netdata-installer.log "%q " "${@}"
-       printf >>netdata-installer.log " ... "
-
-       printf >&2 "\n"
-       printf >&2 ":-----------------------------------------------------------------------------\n"
-       printf >&2 "Running command:\n"
-       printf >&2 "\n"
-       printf >&2 "%q " "${@}"
-       printf >&2 "\n"
-
-       "${@}"
-
-       local ret=$?
-       if [ ${ret} -ne 0 ]
-               then
-               printf >>netdata-installer.log "FAILED!\n"
-       else
-               printf >>netdata-installer.log "OK\n"
-       fi
-
-       return ${ret}
+    printf >>netdata-installer.log "# "
+    printf >>netdata-installer.log "%q " "${@}"
+    printf >>netdata-installer.log " ... "
+
+    printf >&2 "\n"
+    printf >&2 ":-----------------------------------------------------------------------------\n"
+    printf >&2 "Running command:\n"
+    printf >&2 "\n"
+    printf >&2 "%q " "${@}"
+    printf >&2 "\n"
+
+    "${@}"
+
+    local ret=$?
+    if [ ${ret} -ne 0 ]
+        then
+        printf >>netdata-installer.log "FAILED!\n"
+    else
+        printf >>netdata-installer.log "OK\n"
+    fi
+
+    return ${ret}
 }
 
 if [ ${LIBS_ARE_HERE} -eq 1 ]
-       then
-       shift
-       echo >&2 "ok, assuming libs are really installed."
-       export ZLIB_CFLAGS=" "
-       export ZLIB_LIBS="-lz"
-       export UUID_CFLAGS=" "
-       export UUID_LIBS="-luuid"
+    then
+    shift
+    echo >&2 "ok, assuming libs are really installed."
+    export ZLIB_CFLAGS=" "
+    export ZLIB_LIBS="-lz"
+    export UUID_CFLAGS=" "
+    export UUID_LIBS="-luuid"
 fi
 
 trap build_error EXIT
 
 if [ "$have_autotools" ]
 then
-       run ./autogen.sh || exit 1
+    run ./autogen.sh || exit 1
 fi
 
 run ./configure \
-       --prefix="${NETDATA_PREFIX}/usr" \
-       --sysconfdir="${NETDATA_PREFIX}/etc" \
-       --localstatedir="${NETDATA_PREFIX}/var" \
-       --with-zlib --with-math --with-user=netdata \
-       CFLAGS="${CFLAGS}" || exit 1
+    --prefix="${NETDATA_PREFIX}/usr" \
+    --sysconfdir="${NETDATA_PREFIX}/etc" \
+    --localstatedir="${NETDATA_PREFIX}/var" \
+    --with-zlib --with-math --with-user=netdata \
+    CFLAGS="${CFLAGS}" || exit 1
 
 # remove the build_error hook
 trap - EXIT
 
 if [ -f src/netdata ]
-       then
-       echo >&2 "Cleaning a possibly old compilation ..."
-       run make clean
+    then
+    echo >&2 "Cleaning a possibly old compilation ..."
+    run make clean
 fi
 
 echo >&2 "Compiling netdata ..."
@@ -401,101 +401,101 @@ run make || exit 1
 
 if [ "${BASH_VERSINFO[0]}" -ge "4" ]
 then
-       declare -A configs_signatures=()
-       if [ -f "configs.signatures" ]
-               then
-               source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
-       fi
+    declare -A configs_signatures=()
+    if [ -f "configs.signatures" ]
+        then
+        source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
+    fi
 fi
 
 # migrate existing configuration files
 # for node.d and charts.d
 if [ -d "${NETDATA_PREFIX}/etc/netdata" ]
-       then
-       # the configuration directory exists
-
-       if [ ! -d "${NETDATA_PREFIX}/etc/netdata/charts.d" ]
-               then
-               run mkdir "${NETDATA_PREFIX}/etc/netdata/charts.d"
-       fi
-
-       # move the charts.d config files
-       for x in apache ap cpu_apps cpufreq example exim hddtemp load_average mem_apps mysql nginx nut opensips phpfpm postfix sensors squid tomcat
-       do
-               for y in "" ".old" ".orig"
-               do
-                       if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}" ]
-                               then
-                               run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}"
-                       fi
-               done
-       done
-
-       if [ ! -d "${NETDATA_PREFIX}/etc/netdata/node.d" ]
-               then
-               run mkdir "${NETDATA_PREFIX}/etc/netdata/node.d"
-       fi
-
-       # move the node.d config files
-       for x in named sma_webbox snmp
-       do
-               for y in "" ".old" ".orig"
-               do
-                       if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}" ]
-                               then
-                               run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}"
-                       fi
-               done
-       done
+    then
+    # the configuration directory exists
+
+    if [ ! -d "${NETDATA_PREFIX}/etc/netdata/charts.d" ]
+        then
+        run mkdir "${NETDATA_PREFIX}/etc/netdata/charts.d"
+    fi
+
+    # move the charts.d config files
+    for x in apache ap cpu_apps cpufreq example exim hddtemp load_average mem_apps mysql nginx nut opensips phpfpm postfix sensors squid tomcat
+    do
+        for y in "" ".old" ".orig"
+        do
+            if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}" ]
+                then
+                run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}"
+            fi
+        done
+    done
+
+    if [ ! -d "${NETDATA_PREFIX}/etc/netdata/node.d" ]
+        then
+        run mkdir "${NETDATA_PREFIX}/etc/netdata/node.d"
+    fi
+
+    # move the node.d config files
+    for x in named sma_webbox snmp
+    do
+        for y in "" ".old" ".orig"
+        do
+            if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}" ]
+                then
+                run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}"
+            fi
+        done
+    done
 fi
 
 # backup user configurations
 installer_backup_suffix="${PID}.${RANDOM}"
 for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
 do
-       if [ -f "${x}" ]
-               then
-               # make a backup of the configuration file
-               cp -p "${x}" "${x}.old"
-
-               if [ -z "${md5sum}" -o ! -x "${md5sum}" ]
-                       then
-                       # we don't have md5sum - keep it
-                       cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
-               else
-                       # find it relative filename
-                       f="${x/*\/etc\/netdata\//}"
-
-                       # find its checksum
-                       md5="$(cat "${x}" | ${md5sum} | cut -d ' ' -f 1)"
-
-                       # copy the original
-                       if [ -f "conf.d/${f}" ]
-                               then
-                               cp "conf.d/${f}" "${x}.orig"
-                       fi
-
-                       if [ "${BASH_VERSINFO[0]}" -ge "4" ]
-                       then
-                               if [ "${configs_signatures[${md5}]}" = "${f}" ]
-                               then
-                                       # it is a stock version - don't keep it
-                                       echo >&2 "File '${x}' is stock version."
-                               else
-                                       # edited by user - keep it
-                                       echo >&2 "File '${x}' has been edited by user."
-                                       cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
-                               fi
-                       else
-                               echo >&2 "File '${x}' cannot be check for custom edits."
-                               cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
-                       fi
-               fi
-
-       elif [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
-               then
-               rm -f "${x}.installer_backup.${installer_backup_suffix}"
-       fi
+    if [ -f "${x}" ]
+        then
+        # make a backup of the configuration file
+        cp -p "${x}" "${x}.old"
+
+        if [ -z "${md5sum}" -o ! -x "${md5sum}" ]
+            then
+            # we don't have md5sum - keep it
+            cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
+        else
+            # find it relative filename
+            f="${x/*\/etc\/netdata\//}"
+
+            # find its checksum
+            md5="$(cat "${x}" | ${md5sum} | cut -d ' ' -f 1)"
+
+            # copy the original
+            if [ -f "conf.d/${f}" ]
+                then
+                cp "conf.d/${f}" "${x}.orig"
+            fi
+
+            if [ "${BASH_VERSINFO[0]}" -ge "4" ]
+            then
+                if [ "${configs_signatures[${md5}]}" = "${f}" ]
+                then
+                    # it is a stock version - don't keep it
+                    echo >&2 "File '${x}' is stock version."
+                else
+                    # edited by user - keep it
+                    echo >&2 "File '${x}' has been edited by user."
+                    cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
+                fi
+            else
+                echo >&2 "File '${x}' cannot be check for custom edits."
+                cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
+            fi
+        fi
+
+    elif [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
+        then
+        rm -f "${x}.installer_backup.${installer_backup_suffix}"
+    fi
 done
 
 echo >&2 "Installing netdata ..."
@@ -504,53 +504,53 @@ run make install || exit 1
 # restore user configurations
 for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
 do
-       if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
-               then
-               cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
-               rm -f "${x}.installer_backup.${installer_backup_suffix}"
-       fi
+    if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
+        then
+        cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
+        rm -f "${x}.installer_backup.${installer_backup_suffix}"
+    fi
 done
 
 NETDATA_ADDED_TO_DOCKER=0
 if [ ${UID} -eq 0 ]
-       then
-       getent group netdata > /dev/null
-       if [ $? -ne 0 ]
-               then
-               echo >&2 "Adding netdata user group ..."
-               run groupadd -r netdata
-       fi
-
-       getent passwd netdata > /dev/null
-       if [ $? -ne 0 ]
-               then
-               echo >&2 "Adding netdata user account ..."
-               run useradd -r -g netdata -c netdata -s $(which nologin || echo '/bin/false') -d / netdata
-       fi
-
-       getent group docker > /dev/null
-       if [ $? -eq 0 ]
-               then
-               # find the users in the docker group
-               docker=$(getent group docker | cut -d ':' -f 4)
-               if [[ ",${docker}," =~ ,netdata, ]]
-                       then
-                       # netdata is already there
-                       :
-               else
-                       # netdata is not in docker group
-                       echo >&2 "Adding netdata user to the docker group (needed to get container names) ..."
-                       run usermod -a -G docker netdata
-               fi
-               # let the uninstall script know
-               NETDATA_ADDED_TO_DOCKER=1
-       fi
-
-       if [ -d /etc/logrotate.d -a ! -f /etc/logrotate.d/netdata ]
-               then
-               echo >&2 "Adding netdata logrotate configuration ..."
-               run cp system/netdata.logrotate /etc/logrotate.d/netdata
-       fi
+    then
+    getent group netdata > /dev/null
+    if [ $? -ne 0 ]
+        then
+        echo >&2 "Adding netdata user group ..."
+        run groupadd -r netdata
+    fi
+
+    getent passwd netdata > /dev/null
+    if [ $? -ne 0 ]
+        then
+        echo >&2 "Adding netdata user account ..."
+        run useradd -r -g netdata -c netdata -s $(which nologin || echo '/bin/false') -d / netdata
+    fi
+
+    getent group docker > /dev/null
+    if [ $? -eq 0 ]
+        then
+        # find the users in the docker group
+        docker=$(getent group docker | cut -d ':' -f 4)
+        if [[ ",${docker}," =~ ,netdata, ]]
+            then
+            # netdata is already there
+            :
+        else
+            # netdata is not in docker group
+            echo >&2 "Adding netdata user to the docker group (needed to get container names) ..."
+            run usermod -a -G docker netdata
+        fi
+        # let the uninstall script know
+        NETDATA_ADDED_TO_DOCKER=1
+    fi
+
+    if [ -d /etc/logrotate.d -a ! -f /etc/logrotate.d/netdata ]
+        then
+        echo >&2 "Adding netdata logrotate configuration ..."
+        run cp system/netdata.logrotate /etc/logrotate.d/netdata
+    fi
 fi
 
 
@@ -562,15 +562,15 @@ fi
 
 # function to extract values from the config file
 config_option() {
-       local key="${1}" value="${2}" line=
+    local key="${1}" value="${2}" line=
 
-       if [ -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
-               then
-               line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" | head -n 1 )"
-               [ ! -z "${line}" ] && value="$( echo "${line}" | cut -d '=' -f 2 | sed -e "s/^[[:space:]]\+//g" -e "s/[[:space:]]\+$//g" )"
-       fi
+    if [ -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
+        then
+        line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" | head -n 1 )"
+        [ ! -z "${line}" ] && value="$( echo "${line}" | cut -d '=' -f 2 | sed -e "s/^[[:space:]]\+//g" -e "s/[[:space:]]\+$//g" )"
+    fi
 
-       echo "${value}"
+    echo "${value}"
 }
 
 # user
@@ -612,304 +612,304 @@ NETDATA_RUN_DIR="${NETDATA_PREFIX}/var/run"
 
 # this is needed if NETDATA_PREFIX is not empty
 if [ ! -d "${NETDATA_RUN_DIR}" ]
-       then
-       mkdir -p "${NETDATA_RUN_DIR}" || exit 1
+    then
+    mkdir -p "${NETDATA_RUN_DIR}" || exit 1
 fi
 
 echo >&2
 echo >&2 "Fixing directories (user: ${NETDATA_USER})..."
 for x in "${NETDATA_WEB_DIR}" "${NETDATA_CONF_DIR}" "${NETDATA_CACHE_DIR}" "${NETDATA_LOG_DIR}" "${NETDATA_LIB_DIR}" "${NETDATA_CONF_DIR}/python.d" "${NETDATA_CONF_DIR}/charts.d" "${NETDATA_CONF_DIR}/node.d"
 do
-       if [ ! -d "${x}" ]
-               then
-               echo >&2 "Creating directory '${x}'"
-               run mkdir -p "${x}" || exit 1
-       fi
-
-       if [ ${UID} -eq 0 ]
-               then
-               if [ "${x}" = "${NETDATA_WEB_DIR}" ]
-                       then
-                       run chown -R "${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}..."
-               else
-                       run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
-               fi
-       fi
-
-       run chmod 0755 "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
+    if [ ! -d "${x}" ]
+        then
+        echo >&2 "Creating directory '${x}'"
+        run mkdir -p "${x}" || exit 1
+    fi
+
+    if [ ${UID} -eq 0 ]
+        then
+        if [ "${x}" = "${NETDATA_WEB_DIR}" ]
+            then
+            run chown -R "${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}..."
+        else
+            run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
+        fi
+    fi
+
+    run chmod 0755 "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
 done
 
 if [ ${UID} -eq 0 ]
-       then
-       run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-       run chmod 0755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-       run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-       if [ $? -ne 0 ]
-               then
-               # fix apps.plugin to be setuid to root
-               run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-               run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-       fi
+    then
+    run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+    run chmod 0755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+    run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+    if [ $? -ne 0 ]
+        then
+        # fix apps.plugin to be setuid to root
+        run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+    fi
 fi
 
 # -----------------------------------------------------------------------------
 # check if we can re-start netdata
 
 if [ ${DONOTSTART} -eq 1 ]
-       then
-       if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
-               then
-               echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-               echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-
-               if [ "${UID}" -eq 0 ]
-                       then
-                       chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-               fi
-               chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-       fi
-       echo >&2 "OK. It is now installed and ready."
-       exit 0
+    then
+    if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
+        then
+        echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+        echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+
+        if [ "${UID}" -eq 0 ]
+            then
+            chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+        fi
+        chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+    fi
+    echo >&2 "OK. It is now installed and ready."
+    exit 0
 fi
 
 # -----------------------------------------------------------------------------
 # stop a running netdata
 
 isnetdata() {
-       [ -z "$1" -o ! -f "/proc/$1/stat" ] && return 1
-       [ "$(cat "/proc/$1/stat" | cut -d '(' -f 2 | cut -d ')' -f 1)" = "netdata" ] && return 0
-       return 1
+    [ -z "$1" -o ! -f "/proc/$1/stat" ] && return 1
+    [ "$(cat "/proc/$1/stat" | cut -d '(' -f 2 | cut -d ')' -f 1)" = "netdata" ] && return 0
+    return 1
 }
 
 stop_netdata_on_pid() {
-       local pid="$1" ret=0 count=0
+    local pid="$1" ret=0 count=0
 
-       isnetdata $pid || return 0
+    isnetdata $pid || return 0
 
-       printf >&2 "Stopping netdata on pid $pid ..."
-       while [ ! -z "$pid" -a $ret -eq 0 ]
-       do
-               if [ $count -gt 45 ]
-                       then
-                       echo >&2 "Cannot stop the running netdata on pid $pid."
-                       return 1
-               fi
+    printf >&2 "Stopping netdata on pid $pid ..."
+    while [ ! -z "$pid" -a $ret -eq 0 ]
+    do
+        if [ $count -gt 45 ]
+            then
+            echo >&2 "Cannot stop the running netdata on pid $pid."
+            return 1
+        fi
 
-               count=$(( count + 1 ))
+        count=$(( count + 1 ))
 
-               run kill $pid 2>/dev/null
-               ret=$?
+        run kill $pid 2>/dev/null
+        ret=$?
 
-               test $ret -eq 0 && printf >&2 "." && sleep 2
-       done
+        test $ret -eq 0 && printf >&2 "." && sleep 2
+    done
 
-       echo >&2
-       if [ $ret -eq 0 ]
-       then
-               echo >&2 "SORRY! CANNOT STOP netdata ON PID $pid !"
-               return 1
-       fi
+    echo >&2
+    if [ $ret -eq 0 ]
+    then
+        echo >&2 "SORRY! CANNOT STOP netdata ON PID $pid !"
+        return 1
+    fi
 
-       echo >&2 "netdata on pid $pid stopped."
-       return 0
+    echo >&2 "netdata on pid $pid stopped."
+    return 0
 }
 
 stop_all_netdata() {
-       local p
+    local p
 
-       echo >&2 "Stopping a (possibly) running netdata..."
+    echo >&2 "Stopping a (possibly) running netdata..."
 
-       for p in $(cat "${NETDATA_RUN_DIR}/netdata.pid" 2>/dev/null) \
-               $(cat /var/run/netdata.pid 2>/dev/null) \
-               $(cat /var/run/netdata/netdata.pid 2>/dev/null) \
-               $(pidof netdata 2>/dev/null)
-       do
-               stop_netdata_on_pid $p
-       done
+    for p in $(cat "${NETDATA_RUN_DIR}/netdata.pid" 2>/dev/null) \
+        $(cat /var/run/netdata.pid 2>/dev/null) \
+        $(cat /var/run/netdata/netdata.pid 2>/dev/null) \
+        $(pidof netdata 2>/dev/null)
+    do
+        stop_netdata_on_pid $p
+    done
 }
 
 # -----------------------------------------------------------------------------
 # check netdata for systemd
 
 issystemd() {
-       # if the directory /etc/systemd/system does not exit, it is not systemd
-       [ ! -d /etc/systemd/system ] && return 1
+    # if the directory /etc/systemd/system does not exit, it is not systemd
+    [ ! -d /etc/systemd/system ] && return 1
 
-       # if pid 1 is systemd, it is systemd
-       [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
+    # if pid 1 is systemd, it is systemd
+    [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
 
-       # if systemd is running, it is systemd
-       pidof systemd >/dev/null 2>&1 && return 0
+    # if systemd is running, it is systemd
+    pidof systemd >/dev/null 2>&1 && return 0
 
-       # else, it is not systemd
-       return 1
+    # else, it is not systemd
+    return 1
 }
 
 started=0
 if [ "${UID}" -eq 0 ]
-       then
-
-       if issystemd
-       then
-               # systemd is running on this system
-
-               if [ ! -f /etc/systemd/system/netdata.service ]
-               then
-                       echo >&2 "Installing systemd service..."
-                       run cp system/netdata.service /etc/systemd/system/netdata.service && \
-                               run systemctl daemon-reload && \
-                               run systemctl enable netdata
-               else
-                       service netdata stop
-               fi
-
-               stop_all_netdata
-               service netdata restart && started=1
-       fi
-
-       if [ ${started} -eq 0 ]
-       then
-               # check if we can use the system service
-               service netdata stop
-               stop_all_netdata
-               service netdata restart && started=1
-               if [ ${started} -eq 0 ]
-               then
-                       service netdata start && started=1
-               fi
-       fi
+    then
+
+    if issystemd
+    then
+        # systemd is running on this system
+
+        if [ ! -f /etc/systemd/system/netdata.service ]
+        then
+            echo >&2 "Installing systemd service..."
+            run cp system/netdata.service /etc/systemd/system/netdata.service && \
+                run systemctl daemon-reload && \
+                run systemctl enable netdata
+        else
+            service netdata stop
+        fi
+
+        stop_all_netdata
+        service netdata restart && started=1
+    fi
+
+    if [ ${started} -eq 0 ]
+    then
+        # check if we can use the system service
+        service netdata stop
+        stop_all_netdata
+        service netdata restart && started=1
+        if [ ${started} -eq 0 ]
+        then
+            service netdata start && started=1
+        fi
+    fi
 fi
 
 if [ ${started} -eq 0 ]
 then
-       # still not started...
-
-       stop_all_netdata
-
-       echo >&2 "Starting netdata..."
-       run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
-       if [ $? -ne 0 ]
-               then
-               echo >&2
-               echo >&2 "SORRY! FAILED TO START NETDATA!"
-               exit 1
-       else
-               echo >&2 "OK. NetData Started!"
-       fi
-
-       echo >&2
+    # still not started...
+
+    stop_all_netdata
+
+    echo >&2 "Starting netdata..."
+    run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
+    if [ $? -ne 0 ]
+        then
+        echo >&2
+        echo >&2 "SORRY! FAILED TO START NETDATA!"
+        exit 1
+    else
+        echo >&2 "OK. NetData Started!"
+    fi
+
+    echo >&2
 fi
 
 # -----------------------------------------------------------------------------
 # save a config file, if it is not already there
 
 if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
-       then
-       echo >&2
-       echo >&2 "-------------------------------------------------------------------------------"
-       echo >&2
-       echo >&2 "Downloading default configuration from netdata..."
-       sleep 5
-
-       # remove a possibly obsolete download
-       [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
-
-       # disable a proxy to get data from the local netdata
-       export http_proxy=
-       export https_proxy=
-
-       # try wget
-       wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
-       ret=$?
-
-       # try curl
-       if [ $ret -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
-               then
-               curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
-               ret=$?
-       fi
-
-       if [ $ret -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
-               then
-               mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-               echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-
-               if [ "${UID}" -eq 0 ]
-                       then
-                       chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-               fi
-               chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
-       else
-               echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
-               [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
-       fi
+    then
+    echo >&2
+    echo >&2 "-------------------------------------------------------------------------------"
+    echo >&2
+    echo >&2 "Downloading default configuration from netdata..."
+    sleep 5
+
+    # remove a possibly obsolete download
+    [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
+
+    # disable a proxy to get data from the local netdata
+    export http_proxy=
+    export https_proxy=
+
+    # try wget
+    wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
+    ret=$?
+
+    # try curl
+    if [ $ret -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
+        then
+        curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
+        ret=$?
+    fi
+
+    if [ $ret -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
+        then
+        mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+        echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+
+        if [ "${UID}" -eq 0 ]
+            then
+            chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+        fi
+        chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
+    else
+        echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
+        [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
+    fi
 fi
 
 # -----------------------------------------------------------------------------
 # Check for KSM
 
 ksm_is_available_but_disabled() {
-       cat <<-KSM1
+    cat <<-KSM1
 
-       -------------------------------------------------------------------------------
-       Memory de-duplication instructions
+    -------------------------------------------------------------------------------
+    Memory de-duplication instructions
 
-       You have kernel memory de-duper (called Kernel Same-page Merging,
-       or KSM) available, but it is not currently enabled.
+    You have kernel memory de-duper (called Kernel Same-page Merging,
+    or KSM) available, but it is not currently enabled.
 
-       To enable it run:
+    To enable it run:
 
-       echo 1 >/sys/kernel/mm/ksm/run
-       echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
+    echo 1 >/sys/kernel/mm/ksm/run
+    echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
 
-       If you enable it, you will save 40-60% of netdata memory.
+    If you enable it, you will save 40-60% of netdata memory.
 
 KSM1
 }
 
 ksm_is_not_available() {
-       cat <<-KSM2
+    cat <<-KSM2
 
-       -------------------------------------------------------------------------------
-       Memory de-duplication not present in your kernel
+    -------------------------------------------------------------------------------
+    Memory de-duplication not present in your kernel
 
-       It seems you do not have kernel memory de-duper (called Kernel Same-page
-       Merging, or KSM) available.
+    It seems you do not have kernel memory de-duper (called Kernel Same-page
+    Merging, or KSM) available.
 
-       To enable it, you need a kernel built with CONFIG_KSM=y
+    To enable it, you need a kernel built with CONFIG_KSM=y
 
-       If you can have it, you will save 40-60% of netdata memory.
+    If you can have it, you will save 40-60% of netdata memory.
 
 KSM2
 }
 
 if [ -f "/sys/kernel/mm/ksm/run" ]
-       then
-       if [ $(cat "/sys/kernel/mm/ksm/run") != "1" ]
-               then
-               ksm_is_available_but_disabled
-       fi
+    then
+    if [ $(cat "/sys/kernel/mm/ksm/run") != "1" ]
+        then
+        ksm_is_available_but_disabled
+    fi
 else
-       ksm_is_not_available
+    ksm_is_not_available
 fi
 
 # -----------------------------------------------------------------------------
 # Check for version.txt
 
 if [ ! -s web/version.txt ]
-       then
-       cat <<-VERMSG
+    then
+    cat <<-VERMSG
 
-       -------------------------------------------------------------------------------
-       Version update check warning
+    -------------------------------------------------------------------------------
+    Version update check warning
 
-       The way you downloaded netdata, we cannot find its version. This means the
-       Update check on the dashboard, will not work.
+    The way you downloaded netdata, we cannot find its version. This means the
+    Update check on the dashboard, will not work.
 
-       If you want to have version update check, please re-install it
-       following the procedure in:
+    If you want to have version update check, please re-install it
+    following the procedure in:
 
-       https://github.com/firehol/netdata/wiki/Installation
+    https://github.com/firehol/netdata/wiki/Installation
 
 VERMSG
 fi
@@ -918,30 +918,30 @@ fi
 # apps.plugin warning
 
 if [ "${UID}" -ne 0 ]
-       then
-       cat <<-SETUID_WARNING
+    then
+    cat <<-SETUID_WARNING
 
-       -------------------------------------------------------------------------------
-       apps.plugin needs privileges
+    -------------------------------------------------------------------------------
+    apps.plugin needs privileges
 
-       Since you have installed netdata as a normal user, to have apps.plugin collect
-       all the needed data, you have to give it the access rights it needs, by running
-       either of the following sets of commands:
+    Since you have installed netdata as a normal user, to have apps.plugin collect
+    all the needed data, you have to give it the access rights it needs, by running
+    either of the following sets of commands:
 
-       To run apps.plugin with escalated capabilities:
+    To run apps.plugin with escalated capabilities:
 
-               sudo chown root:${NETDATA_USER} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-               sudo chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-               sudo setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        sudo chown root:${NETDATA_USER} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        sudo chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        sudo setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
 
-       or, to run apps.plugin as root:
+    or, to run apps.plugin as root:
 
-               sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-               sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+        sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
 
-       apps.plugin is performing a hard-coded function of data collection for all
-       running processes. It cannot be instructed from the netdata daemon to perform
-       any task, so it is pretty safe to do this.
+    apps.plugin is performing a hard-coded function of data collection for all
+    running processes. It cannot be instructed from the netdata daemon to perform
+    any task, so it is pretty safe to do this.
 
 SETUID_WARNING
 fi
@@ -950,91 +950,91 @@ fi
 # Keep un-install info
 
 cat >netdata-uninstaller.sh <<-UNINSTALL
-       #!/bin/bash
-
-       # this script will uninstall netdata
-
-       if [ "\$1" != "--force" ]
-               then
-               echo >&2 "This script will REMOVE netdata from your system."
-               echo >&2 "Run it again with --force to do it."
-               exit 1
-       fi
-
-       echo >&2 "Stopping a possibly running netdata..."
-       for p in \$(pidof netdata); do kill \$p; done
-       sleep 2
-
-       deletedir() {
-               if [ ! -z "\$1" -a -d "\$1" ]
-                       then
-                       echo
-                       echo "Deleting directory '\$1' ..."
-                       rm -I -R "\$1"
-               fi
-       }
-
-       if [ ! -z "${NETDATA_PREFIX}" -a -d "${NETDATA_PREFIX}" ]
-               then
-               # installation prefix was given
-
-               deletedir "${NETDATA_PREFIX}"
-
-       else
-               # installation prefix was NOT given
-
-               if [ -f "${NETDATA_PREFIX}/usr/sbin/netdata" ]
-                       then
-                       echo "Deleting ${NETDATA_PREFIX}/usr/sbin/netdata ..."
-                       rm -i "${NETDATA_PREFIX}/usr/sbin/netdata"
-               fi
-
-               deletedir "${NETDATA_PREFIX}/etc/netdata"
-               deletedir "${NETDATA_PREFIX}/usr/share/netdata"
-               deletedir "${NETDATA_PREFIX}/usr/libexec/netdata"
-               deletedir "${NETDATA_PREFIX}/var/lib/netdata"
-               deletedir "${NETDATA_PREFIX}/var/cache/netdata"
-               deletedir "${NETDATA_PREFIX}/var/log/netdata"
-       fi
-
-       if [ -f /etc/logrotate.d/netdata ]
-               then
-               echo "Deleting /etc/logrotate.d/netdata ..."
-               rm -i /etc/logrotate.d/netdata
-       fi
-
-       if [ -f /etc/systemd/system/netdata.service ]
-               then
-               echo "Deleting /etc/systemd/system/netdata.service ..."
-               rm -i /etc/systemd/system/netdata.service
-       fi
-
-       getent passwd netdata > /dev/null
-       if [ $? -eq 0 ]
-               then
-               echo
-               echo "You may also want to remove the user netdata"
-               echo "by running:"
-               echo "   userdel netdata"
-       fi
-
-       getent group netdata > /dev/null
-       if [ $? -eq 0 ]
-               then
-               echo
-               echo "You may also want to remove the group netdata"
-               echo "by running:"
-               echo "   groupdel netdata"
-       fi
-
-       getent group docker > /dev/null
-       if [ $? -eq 0 -a "${NETDATA_ADDED_TO_DOCKER}" = "1" ]
-               then
-               echo
-               echo "You may also want to remove the netdata user from the docker group"
-               echo "by running:"
-               echo "   gpasswd -d netdata docker"
-       fi
+    #!/bin/bash
+
+    # this script will uninstall netdata
+
+    if [ "\$1" != "--force" ]
+        then
+        echo >&2 "This script will REMOVE netdata from your system."
+        echo >&2 "Run it again with --force to do it."
+        exit 1
+    fi
+
+    echo >&2 "Stopping a possibly running netdata..."
+    for p in \$(pidof netdata); do kill \$p; done
+    sleep 2
+
+    deletedir() {
+        if [ ! -z "\$1" -a -d "\$1" ]
+            then
+            echo
+            echo "Deleting directory '\$1' ..."
+            rm -I -R "\$1"
+        fi
+    }
+
+    if [ ! -z "${NETDATA_PREFIX}" -a -d "${NETDATA_PREFIX}" ]
+        then
+        # installation prefix was given
+
+        deletedir "${NETDATA_PREFIX}"
+
+    else
+        # installation prefix was NOT given
+
+        if [ -f "${NETDATA_PREFIX}/usr/sbin/netdata" ]
+            then
+            echo "Deleting ${NETDATA_PREFIX}/usr/sbin/netdata ..."
+            rm -i "${NETDATA_PREFIX}/usr/sbin/netdata"
+        fi
+
+        deletedir "${NETDATA_PREFIX}/etc/netdata"
+        deletedir "${NETDATA_PREFIX}/usr/share/netdata"
+        deletedir "${NETDATA_PREFIX}/usr/libexec/netdata"
+        deletedir "${NETDATA_PREFIX}/var/lib/netdata"
+        deletedir "${NETDATA_PREFIX}/var/cache/netdata"
+        deletedir "${NETDATA_PREFIX}/var/log/netdata"
+    fi
+
+    if [ -f /etc/logrotate.d/netdata ]
+        then
+        echo "Deleting /etc/logrotate.d/netdata ..."
+        rm -i /etc/logrotate.d/netdata
+    fi
+
+    if [ -f /etc/systemd/system/netdata.service ]
+        then
+        echo "Deleting /etc/systemd/system/netdata.service ..."
+        rm -i /etc/systemd/system/netdata.service
+    fi
+
+    getent passwd netdata > /dev/null
+    if [ $? -eq 0 ]
+        then
+        echo
+        echo "You may also want to remove the user netdata"
+        echo "by running:"
+        echo "   userdel netdata"
+    fi
+
+    getent group netdata > /dev/null
+    if [ $? -eq 0 ]
+        then
+        echo
+        echo "You may also want to remove the group netdata"
+        echo "by running:"
+        echo "   groupdel netdata"
+    fi
+
+    getent group docker > /dev/null
+    if [ $? -eq 0 -a "${NETDATA_ADDED_TO_DOCKER}" = "1" ]
+        then
+        echo
+        echo "You may also want to remove the netdata user from the docker group"
+        echo "by running:"
+        echo "   gpasswd -d netdata docker"
+    fi
 
 UNINSTALL
 chmod 750 netdata-uninstaller.sh
@@ -1044,27 +1044,27 @@ chmod 750 netdata-uninstaller.sh
 cat <<-END
 
 
-       -------------------------------------------------------------------------------
+    -------------------------------------------------------------------------------
 
-       OK. NetData is installed and it is running.
+    OK. NetData is installed and it is running.
 
-       -------------------------------------------------------------------------------
+    -------------------------------------------------------------------------------
 
-       By default netdata listens on all IPs on port ${NETDATA_PORT},
-       so you can access it with:
+    By default netdata listens on all IPs on port ${NETDATA_PORT},
+    so you can access it with:
 
-       http://this.machine.ip:${NETDATA_PORT}/
+    http://this.machine.ip:${NETDATA_PORT}/
 
-       To stop netdata, just kill it, with:
+    To stop netdata, just kill it, with:
 
-         killall netdata
+      killall netdata
 
-       To start it, just run it:
+    To start it, just run it:
 
-         ${NETDATA_PREFIX}/usr/sbin/netdata
+      ${NETDATA_PREFIX}/usr/sbin/netdata
 
 
-       Enjoy!
+    Enjoy!
 
 END
 echo >&2 "Uninstall script generated: ./netdata-uninstaller.sh"
index c2b15eae72a1aec2ca84351db280b234d9ace8df..26c6ec2e09540a7ec6627957673c76060f54f705 100644 (file)
 
 /*
 {
-       "enable_autodetect": true,
-       "update_every": 5,
-       "servers": [
-               {
-                       "name": "bind1",
-                       "url": "http://127.0.0.1:8888/json/v1/server",
-                       "update_every": 1
-               },
-               {
-                       "name": "bind2",
-                       "url": "http://10.0.0.1:8888/xml/v3/server",
-                       "update_every": 2
-               }
-       ]
+    "enable_autodetect": true,
+    "update_every": 5,
+    "servers": [
+        {
+            "name": "bind1",
+            "url": "http://127.0.0.1:8888/json/v1/server",
+            "update_every": 1
+        },
+        {
+            "name": "bind2",
+            "url": "http://10.0.0.1:8888/xml/v3/server",
+            "update_every": 2
+        }
+    ]
 }
 */
 
@@ -44,543 +44,543 @@ var netdata = require('netdata');
 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
 
 var named = {
-       name: __filename,
-       enable_autodetect: true,
-       update_every: 1,
-       base_priority: 60000,
-       charts: {},
-
-       chartFromMembersCreate: function(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
-               var chart = {
-                       id: id,                                                                                 // the unique id of the chart
-                       name: '',                                                                               // the unique name of the chart
-                       title: service.name + ' ' + title_suffix,               // the title of the chart
-                       units: units,                                                                   // the units of the chart dimensions
-                       family: family,                                                                 // the family of the chart
-                       context: context,                                                               // the context of the chart
-                       type: type,                                                                             // the type of the chart
-                       priority: priority,                                                             // the priority relative to others in the same family
-                       update_every: service.update_every,                     // the expected update frequency of the chart
-                       dimensions: {}
-               }
-
-               var found = 0;
-               for(var x in obj) {
-                       if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
-                               found++;
-                               chart.dimensions[x] = {
-                                       id: x,                                  // the unique id of the dimension
-                                       name: x,                                // the name of the dimension
-                                       algorithm: algorithm,   // the id of the netdata algorithm
-                                       multiplier: multiplier, // the multiplier
-                                       divisor: divisor,               // the divisor
-                                       hidden: false                   // is hidden (boolean)
-                               }
-                       }
-               }
-
-               if(found === false)
-                       return null;
-
-               chart = service.chart(id, chart);
-               this.charts[id] = chart;
-               return chart;
-       },
-
-       chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
-               var id = 'named_' + service.name + '.' + id_suffix;
-               var chart = this.charts[id];
-
-               if(typeof chart === 'undefined') {
-                       chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
-                       if(chart === null) return false;
-               }
-               else {
-                       // check if we need to re-generate the chart
-                       for(var x in obj) {
-                               if(typeof(chart.dimensions[x]) === 'undefined') {
-                                       chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
-                                       if(chart === null) return false;
-                                       break;
-                               }
-                       }
-               }
-
-               var found = 0;
-               service.begin(chart);
-               for(var x in obj) {
-                       if(typeof(chart.dimensions[x]) !== 'undefined') {
-                               found++;
-                               service.set(x, obj[x]);
-                       }
-               }
-               service.end();
-
-               if(found > 0) return true;
-               return false;
-       },
-
-       // an index to map values to different charts
-       lookups: {
-               nsstats: {},
-               resolver_stats: {},
-               numfetch: {}
-       },
-
-       // transform the XML response of bind
-       // to the JSON response of bind
-       xml2js: function(service, data_xml) {
-               var d = XML.parse(data_xml);
-               if(d === null) return null;
-
-               var data = {};
-               var len = d.server.counters.length;
-               while(len--) {
-                       var a = d.server.counters[len];
-                       if(typeof a.counter === 'undefined') continue;
-                       if(a.type === 'opcode') a.type = 'opcodes';
-                       else if(a.type === 'qtype') a.type = 'qtypes';
-                       else if(a.type === 'nsstat') a.type = 'nsstats';
-                       var aa = data[a.type] = {};
-                       var alen = 0
-                       var alen2 = a.counter.length;
-                       while(alen < alen2) {
-                               aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
-                               alen++;
-                       }
-               }
-
-               data.views = {};
-               var vlen = d.views.view.length;
-               while(vlen--) {
-                       var vname = d.views.view[vlen].name;
-                       data.views[vname] = { resolver: {} };
-                       var len = d.views.view[vlen].counters.length;
-                       while(len--) {
-                               var a = d.views.view[vlen].counters[len];
-                               if(typeof a.counter === 'undefined') continue;
-                               if(a.type === 'resstats') a.type = 'stats';
-                               else if(a.type === 'resqtype') a.type = 'qtypes';
-                               else if(a.type === 'adbstat') a.type = 'adb';
-                               var aa = data.views[vname].resolver[a.type] = {};
-                               var alen = 0;
-                               var alen2 = a.counter.length;
-                               while(alen < alen2) {
-                                       aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
-                                       alen++;
-                               }
-                       }
-               }
-
-               return data;
-       },
-
-       processResponse: function(service, data) {
-               if(data !== null) {
-                       var r;
-
-                       // parse XML or JSON
-                       // pepending on the URL given
-                       if(service.request.path.match(/^\/xml/) !== null)
-                               r = named.xml2js(service, data);
-                       else
-                               r = JSON.parse(data);
-
-                       if(typeof r === 'undefined' || r === null) {
-                               netdata.serviceError(service, "Cannot parse these data: " + data);
-                               return;
-                       }
-
-                       if(service.added !== true)
-                               service.commit();
-
-                       if(typeof r.nsstats !== 'undefined') {
-                               // we split the nsstats object to several others
-                               var global_requests = {}, global_requests_enable = false;
-                               var global_failures = {}, global_failures_enable = false;
-                               var global_failures_detail = {}, global_failures_detail_enable = false;
-                               var global_updates = {}, global_updates_enable = false;
-                               var protocol_queries = {}, protocol_queries_enable = false;
-                               var global_queries = {}, global_queries_enable = false;
-                               var global_queries_success = {}, global_queries_success_enable = false;
-                               var default_enable = false;
-                               var RecursClients = 0;
-
-                               // RecursClients is an absolute value
-                               if(typeof r.nsstats['RecursClients'] !== 'undefined') {
-                                       RecursClients = r.nsstats['RecursClients'];
-                                       delete r.nsstats['RecursClients'];
-                               }
-
-                               for( var x in r.nsstats ) {
-                                       // we maintain an index of the values found
-                                       // mapping them to objects splitted
-
-                                       var look = named.lookups.nsstats[x];
-                                       if(typeof look === 'undefined') {
-                                               // a new value, not found in the index
-                                               // index it:
-                                               if(x === 'Requestv4') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'IPv4',
-                                                               type: 'global_requests'
-                                                       };
-                                               }
-                                               else if(x === 'Requestv6') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'IPv6',
-                                                               type: 'global_requests'
-                                                       };
-                                               }
-                                               else if(x === 'QryFailure') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'failures',
-                                                               type: 'global_failures'
-                                                       };
-                                               }
-                                               else if(x === 'QryUDP') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'UDP',
-                                                               type: 'protocol_queries'
-                                                       };
-                                               }
-                                               else if(x === 'QryTCP') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'TCP',
-                                                               type: 'protocol_queries'
-                                                       };
-                                               }
-                                               else if(x === 'QrySuccess') {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: 'queries',
-                                                               type: 'global_queries_success'
-                                                       };
-                                               }
-                                               else if(x.match(/QryRej$/) !== null) {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: x,
-                                                               type: 'global_failures_detail'
-                                                       };
-                                               }
-                                               else if(x.match(/^Qry/) !== null) {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: x,
-                                                               type: 'global_queries'
-                                                       };
-                                               }
-                                               else if(x.match(/^Update/) !== null) {
-                                                       named.lookups.nsstats[x] = {
-                                                               name: x,
-                                                               type: 'global_updates'
-                                                       };
-                                               }
-                                               else {
-                                                       // values not mapped, will remain
-                                                       // in the default map
-                                                       named.lookups.nsstats[x] = {
-                                                               name: x,
-                                                               type: 'default'
-                                                       };
-                                               }
-
-                                               look = named.lookups.nsstats[x];
-                                               // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
-                                       }
-
-                                       switch(look.type) {
-                                               case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
-                                               case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
-                                               case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
-                                               case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
-                                               case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
-                                               case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
-                                               case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
-                                               default: default_enable = true; break;
-                                       }
-                               }
-
-                               if(global_requests_enable == true)
-                                       service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'requests', 'named.requests', netdata.chartTypes.stacked, named.base_priority + 1, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(global_queries_success_enable == true)
-                                       service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'queries', 'named.queries.succcess', netdata.chartTypes.line, named.base_priority + 2, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(protocol_queries_enable == true)
-                                       service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'queries', 'named.protocol.queries', netdata.chartTypes.stacked, named.base_priority + 3, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(global_queries_enable == true)
-                                       service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'queries', 'named.global.queries', netdata.chartTypes.stacked, named.base_priority + 4, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(global_updates_enable == true)
-                                       service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'updates', 'named.global.updates', netdata.chartTypes.stacked, named.base_priority + 5, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(global_failures_enable == true)
-                                       service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'failures', 'named.global.failures', netdata.chartTypes.line, named.base_priority + 6, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(global_failures_detail_enable == true)
-                                       service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'failures', 'named.global.failures.detail', netdata.chartTypes.stacked, named.base_priority + 7, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               if(default_enable === true)
-                                       service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'other', 'named.nsstats', netdata.chartTypes.line, named.base_priority + 8, netdata.chartAlgorithms.incremental, 1, 1);
-
-                               // RecursClients chart
-                               {
-                                       var id = 'named_' + service.name + '.recursive_clients';
-                                       var chart = named.charts[id];
-
-                                       if(typeof chart === 'undefined') {
-                                               chart = {
-                                                       id: id,                                                                                 // the unique id of the chart
-                                                       name: '',                                                                               // the unique name of the chart
-                                                       title: service.name + ' Bind, Current Recursive Clients',               // the title of the chart
-                                                       units: 'clients',                                                               // the units of the chart dimensions
-                                                       family: 'clients',                                                              // the family of the chart
-                                                       context: 'named.recursive.clients',                             // the context of the chart
-                                                       type: netdata.chartTypes.line,                                  // the type of the chart
-                                                       priority: named.base_priority + 1,                              // the priority relative to others in the same family
-                                                       update_every: service.update_every,                             // the expected update frequency of the chart
-                                                       dimensions: {
-                                                               'clients': {
-                                                                       id: 'clients',                                                          // the unique id of the dimension
-                                                                       name: '',                                                                       // the name of the dimension
-                                                                       algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
-                                                                       multiplier: 1,                                                          // the multiplier
-                                                                       divisor: 1,                                                                     // the divisor
-                                                                       hidden: false                                                           // is hidden (boolean)
-                                                               }
-                                                       }
-                                               };
-
-                                               chart = service.chart(id, chart);
-                                               named.charts[id] = chart;
-                                       }
-
-                                       service.begin(chart);
-                                       service.set('clients', RecursClients);
-                                       service.end();
-                               }
-                       }
-
-                       if(typeof r.opcodes !== 'undefined')
-                               service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'requests', 'named.in.opcodes', netdata.chartTypes.stacked, named.base_priority + 9, netdata.chartAlgorithms.incremental, 1, 1);
-
-                       if(typeof r.qtypes !== 'undefined')
-                               service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'requests', 'named.in.qtypes', netdata.chartTypes.stacked, named.base_priority + 10, netdata.chartAlgorithms.incremental, 1, 1);
-
-                       if(typeof r.sockstats !== 'undefined')
-                               service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'sockets', 'named.in.sockstats', netdata.chartTypes.line, named.base_priority + 11, netdata.chartAlgorithms.incremental, 1, 1);
-
-                       if(typeof r.views !== 'undefined') {
-                               for( var x in r.views ) {
-                                       var resolver = r.views[x].resolver;
-
-                                       if(typeof resolver !== 'undefined') {
-                                               if(typeof resolver.stats !== 'undefined') {
-                                                       var NumFetch = 0;
-                                                       var key = service.name + '.' + x;
-                                                       var default_enable = false;
-                                                       var rtt = {}, rtt_enable = false;
-
-                                                       // NumFetch is an absolute value
-                                                       if(typeof resolver.stats['NumFetch'] !== 'undefined') {
-                                                               named.lookups.numfetch[key] = true;
-                                                               NumFetch = resolver.stats['NumFetch'];
-                                                               delete resolver.stats['NumFetch'];
-                                                       }
-                                                       if(typeof resolver.stats['BucketSize'] !== 'undefined') {
-                                                               delete resolver.stats['BucketSize'];
-                                                       }
-
-                                                       // split the QryRTT* from the main chart
-                                                       for( var y in resolver.stats ) {
-                                                               // we maintain an index of the values found
-                                                               // mapping them to objects splitted
-
-                                                               var look = named.lookups.resolver_stats[y];
-                                                               if(typeof look === 'undefined') {
-                                                                       if(y.match(/^QryRTT/) !== null) {
-                                                                               named.lookups.resolver_stats[y] = {
-                                                                                       name: y,
-                                                                                       type: 'rtt'
-                                                                               };
-                                                                       }
-                                                                       else {
-                                                                               named.lookups.resolver_stats[y] = {
-                                                                                       name: y,
-                                                                                       type: 'default'
-                                                                               };
-                                                                       }
-
-                                                                       look = named.lookups.resolver_stats[y];
-                                                                       // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
-                                                               }
-
-                                                               switch(look.type) {
-                                                                       case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
-                                                                       default: default_enable = true; break;
-                                                               }
-                                                       }
-
-                                                       if(rtt_enable)
-                                                               service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'view_' + x, 'named.resolver.rtt', netdata.chartTypes.stacked, named.base_priority + 12, netdata.chartAlgorithms.incremental, 1, 1);
-
-                                                       if(default_enable)
-                                                               service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'view_' + x, 'named.resolver.stats', netdata.chartTypes.line, named.base_priority + 13, netdata.chartAlgorithms.incremental, 1, 1);
-
-                                                       // NumFetch chart
-                                                       if(typeof named.lookups.numfetch[key] !== 'undefined') {
-                                                               var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
-                                                               var chart = named.charts[id];
-
-                                                               if(typeof chart === 'undefined') {
-                                                                       chart = {
-                                                                               id: id,                                                                                 // the unique id of the chart
-                                                                               name: '',                                                                               // the unique name of the chart
-                                                                               title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries',         // the title of the chart
-                                                                               units: 'queries',                                                               // the units of the chart dimensions
-                                                                               family: 'view_' + x,                                                    // the family of the chart
-                                                                               context: 'named.resolver.active.queries',               // the context of the chart
-                                                                               type: netdata.chartTypes.line,                                  // the type of the chart
-                                                                               priority: named.base_priority + 1001,                   // the priority relative to others in the same family
-                                                                               update_every: service.update_every,                             // the expected update frequency of the chart
-                                                                               dimensions: {
-                                                                                       'queries': {
-                                                                                               id: 'queries',                                                          // the unique id of the dimension
-                                                                                               name: '',                                                                       // the name of the dimension
-                                                                                               algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
-                                                                                               multiplier: 1,                                                          // the multiplier
-                                                                                               divisor: 1,                                                                     // the divisor
-                                                                                               hidden: false                                                           // is hidden (boolean)
-                                                                                       }
-                                                                               }
-                                                                       };
-
-                                                                       chart = service.chart(id, chart);
-                                                                       named.charts[id] = chart;
-                                                               }
-
-                                                               service.begin(chart);
-                                                               service.set('queries', NumFetch);
-                                                               service.end();
-                                                       }
-                                               }
-                                       }
-
-                                       if(typeof resolver.qtypes !== 'undefined')
-                                               service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'view_' + x, 'named.resolver.qtypes', netdata.chartTypes.stacked, named.base_priority + 14, netdata.chartAlgorithms.incremental, 1, 1);
-
-                                       //if(typeof resolver.cache !== 'undefined')
-                                       //      service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'view_' + x, 'named.resolver.cache', netdata.chartTypes.stacked, named.base_priority + 15, netdata.chartAlgorithms.absolute, 1, 1);
-
-                                       if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
-                                               var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
-                                               var chart = named.charts[id];
-
-                                               if(typeof chart === 'undefined') {
-                                                       chart = {
-                                                               id: id,                                                                                 // the unique id of the chart
-                                                               name: '',                                                                               // the unique name of the chart
-                                                               title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits',             // the title of the chart
-                                                               units: 'operations/s',                                                  // the units of the chart dimensions
-                                                               family: 'view_' + x,                                                    // the family of the chart
-                                                               context: 'named.resolver.cache.hits',                   // the context of the chart
-                                                               type: netdata.chartTypes.area,                                  // the type of the chart
-                                                               priority: named.base_priority + 1100,                   // the priority relative to others in the same family
-                                                               update_every: service.update_every,                             // the expected update frequency of the chart
-                                                               dimensions: {
-                                                                       'CacheHits': {
-                                                                               id: 'CacheHits',                                                        // the unique id of the dimension
-                                                                               name: 'hits',                                                           // the name of the dimension
-                                                                               algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
-                                                                               multiplier: 1,                                                          // the multiplier
-                                                                               divisor: 1,                                                                     // the divisor
-                                                                               hidden: false                                                           // is hidden (boolean)
-                                                                       },
-                                                                       'CacheMisses': {
-                                                                               id: 'CacheMisses',                                                      // the unique id of the dimension
-                                                                               name: 'misses',                                                         // the name of the dimension
-                                                                               algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
-                                                                               multiplier: -1,                                                         // the multiplier
-                                                                               divisor: 1,                                                                     // the divisor
-                                                                               hidden: false                                                           // is hidden (boolean)
-                                                                       }
-                                                               }
-                                                       };
-
-                                                       chart = service.chart(id, chart);
-                                                       named.charts[id] = chart;
-                                               }
-
-                                               service.begin(chart);
-                                               service.set('CacheHits', resolver.cachestats['CacheHits']);
-                                               service.set('CacheMisses', resolver.cachestats['CacheMisses']);
-                                               service.end();
-                                       }
-
-                                       // this is wrong, it contains many types of info:
-                                       // 1. CacheHits, CacheMisses - incremental (added above)
-                                       // 2. QueryHits, QueryMisses - incremental
-                                       // 3. DeleteLRU, DeleteTTL - incremental
-                                       // 4. CacheNodes, CacheBuckets - absolute
-                                       // 5. TreeMemTotal, TreeMemInUse - absolute
-                                       // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
-                                       //if(typeof resolver.cachestats !== 'undefined')
-                                       //      service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'view_' + x, 'named.resolver.cache.stats', netdata.chartTypes.line, named.base_priority + 1001, netdata.chartAlgorithms.incremental, 1, 1);
-
-                                       //if(typeof resolver.adb !== 'undefined')
-                                       //      service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'view_' + x, 'named.resolver.adb', netdata.chartTypes.line, named.base_priority + 1002, netdata.chartAlgorithms.absolute, 1, 1);
-                               }
-                       }
-               }
-       },
-
-       // module.serviceExecute()
-       // this function is called only from this module
-       // its purpose is to prepare the request and call
-       // netdata.serviceExecute()
-       serviceExecute: function(name, a_url, update_every) {
-               if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
-               var service = netdata.service({
-                       name: name,
-                       request: netdata.requestFromURL(a_url),
-                       update_every: update_every,
-                       module: this
-               });
-
-               service.execute(this.processResponse);
-       },
-
-       configure: function(config) {
-               var added = 0;
-
-               if(this.enable_autodetect === true) {
-                       this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
-                       added++;
-               }
-               
-               if(typeof(config.servers) !== 'undefined') {
-                       var len = config.servers.length;
-                       while(len--) {
-                               if(typeof config.servers[len].update_every === 'undefined')
-                                       config.servers[len].update_every = this.update_every;
-
-                               this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
-                               added++;
-                       }
-               }
-
-               return added;
-       },
-
-       // module.update()
-       // this is called repeatidly to collect data, by calling
-       // netdata.serviceExecute()
-       update: function(service, callback) {
-               service.execute(function(serv, data) {
-                       service.module.processResponse(serv, data);
-                       callback();
-               });
-       },
+    name: __filename,
+    enable_autodetect: true,
+    update_every: 1,
+    base_priority: 60000,
+    charts: {},
+
+    chartFromMembersCreate: function(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
+        var chart = {
+            id: id,                                         // the unique id of the chart
+            name: '',                                       // the unique name of the chart
+            title: service.name + ' ' + title_suffix,       // the title of the chart
+            units: units,                                   // the units of the chart dimensions
+            family: family,                                 // the family of the chart
+            context: context,                               // the context of the chart
+            type: type,                                     // the type of the chart
+            priority: priority,                             // the priority relative to others in the same family
+            update_every: service.update_every,             // the expected update frequency of the chart
+            dimensions: {}
+        }
+
+        var found = 0;
+        for(var x in obj) {
+            if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
+                found++;
+                chart.dimensions[x] = {
+                    id: x,                  // the unique id of the dimension
+                    name: x,                // the name of the dimension
+                    algorithm: algorithm,   // the id of the netdata algorithm
+                    multiplier: multiplier, // the multiplier
+                    divisor: divisor,       // the divisor
+                    hidden: false           // is hidden (boolean)
+                }
+            }
+        }
+
+        if(found === false)
+            return null;
+
+        chart = service.chart(id, chart);
+        this.charts[id] = chart;
+        return chart;
+    },
+
+    chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
+        var id = 'named_' + service.name + '.' + id_suffix;
+        var chart = this.charts[id];
+
+        if(typeof chart === 'undefined') {
+            chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
+            if(chart === null) return false;
+        }
+        else {
+            // check if we need to re-generate the chart
+            for(var x in obj) {
+                if(typeof(chart.dimensions[x]) === 'undefined') {
+                    chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
+                    if(chart === null) return false;
+                    break;
+                }
+            }
+        }
+
+        var found = 0;
+        service.begin(chart);
+        for(var x in obj) {
+            if(typeof(chart.dimensions[x]) !== 'undefined') {
+                found++;
+                service.set(x, obj[x]);
+            }
+        }
+        service.end();
+
+        if(found > 0) return true;
+        return false;
+    },
+
+    // an index to map values to different charts
+    lookups: {
+        nsstats: {},
+        resolver_stats: {},
+        numfetch: {}
+    },
+
+    // transform the XML response of bind
+    // to the JSON response of bind
+    xml2js: function(service, data_xml) {
+        var d = XML.parse(data_xml);
+        if(d === null) return null;
+
+        var data = {};
+        var len = d.server.counters.length;
+        while(len--) {
+            var a = d.server.counters[len];
+            if(typeof a.counter === 'undefined') continue;
+            if(a.type === 'opcode') a.type = 'opcodes';
+            else if(a.type === 'qtype') a.type = 'qtypes';
+            else if(a.type === 'nsstat') a.type = 'nsstats';
+            var aa = data[a.type] = {};
+            var alen = 0
+            var alen2 = a.counter.length;
+            while(alen < alen2) {
+                aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
+                alen++;
+            }
+        }
+
+        data.views = {};
+        var vlen = d.views.view.length;
+        while(vlen--) {
+            var vname = d.views.view[vlen].name;
+            data.views[vname] = { resolver: {} };
+            var len = d.views.view[vlen].counters.length;
+            while(len--) {
+                var a = d.views.view[vlen].counters[len];
+                if(typeof a.counter === 'undefined') continue;
+                if(a.type === 'resstats') a.type = 'stats';
+                else if(a.type === 'resqtype') a.type = 'qtypes';
+                else if(a.type === 'adbstat') a.type = 'adb';
+                var aa = data.views[vname].resolver[a.type] = {};
+                var alen = 0;
+                var alen2 = a.counter.length;
+                while(alen < alen2) {
+                    aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
+                    alen++;
+                }
+            }
+        }
+
+        return data;
+    },
+
+    processResponse: function(service, data) {
+        if(data !== null) {
+            var r;
+
+            // parse XML or JSON
+            // pepending on the URL given
+            if(service.request.path.match(/^\/xml/) !== null)
+                r = named.xml2js(service, data);
+            else
+                r = JSON.parse(data);
+
+            if(typeof r === 'undefined' || r === null) {
+                netdata.serviceError(service, "Cannot parse these data: " + data);
+                return;
+            }
+
+            if(service.added !== true)
+                service.commit();
+
+            if(typeof r.nsstats !== 'undefined') {
+                // we split the nsstats object to several others
+                var global_requests = {}, global_requests_enable = false;
+                var global_failures = {}, global_failures_enable = false;
+                var global_failures_detail = {}, global_failures_detail_enable = false;
+                var global_updates = {}, global_updates_enable = false;
+                var protocol_queries = {}, protocol_queries_enable = false;
+                var global_queries = {}, global_queries_enable = false;
+                var global_queries_success = {}, global_queries_success_enable = false;
+                var default_enable = false;
+                var RecursClients = 0;
+
+                // RecursClients is an absolute value
+                if(typeof r.nsstats['RecursClients'] !== 'undefined') {
+                    RecursClients = r.nsstats['RecursClients'];
+                    delete r.nsstats['RecursClients'];
+                }
+
+                for( var x in r.nsstats ) {
+                    // we maintain an index of the values found
+                    // mapping them to objects splitted
+
+                    var look = named.lookups.nsstats[x];
+                    if(typeof look === 'undefined') {
+                        // a new value, not found in the index
+                        // index it:
+                        if(x === 'Requestv4') {
+                            named.lookups.nsstats[x] = {
+                                name: 'IPv4',
+                                type: 'global_requests'
+                            };
+                        }
+                        else if(x === 'Requestv6') {
+                            named.lookups.nsstats[x] = {
+                                name: 'IPv6',
+                                type: 'global_requests'
+                            };
+                        }
+                        else if(x === 'QryFailure') {
+                            named.lookups.nsstats[x] = {
+                                name: 'failures',
+                                type: 'global_failures'
+                            };
+                        }
+                        else if(x === 'QryUDP') {
+                            named.lookups.nsstats[x] = {
+                                name: 'UDP',
+                                type: 'protocol_queries'
+                            };
+                        }
+                        else if(x === 'QryTCP') {
+                            named.lookups.nsstats[x] = {
+                                name: 'TCP',
+                                type: 'protocol_queries'
+                            };
+                        }
+                        else if(x === 'QrySuccess') {
+                            named.lookups.nsstats[x] = {
+                                name: 'queries',
+                                type: 'global_queries_success'
+                            };
+                        }
+                        else if(x.match(/QryRej$/) !== null) {
+                            named.lookups.nsstats[x] = {
+                                name: x,
+                                type: 'global_failures_detail'
+                            };
+                        }
+                        else if(x.match(/^Qry/) !== null) {
+                            named.lookups.nsstats[x] = {
+                                name: x,
+                                type: 'global_queries'
+                            };
+                        }
+                        else if(x.match(/^Update/) !== null) {
+                            named.lookups.nsstats[x] = {
+                                name: x,
+                                type: 'global_updates'
+                            };
+                        }
+                        else {
+                            // values not mapped, will remain
+                            // in the default map
+                            named.lookups.nsstats[x] = {
+                                name: x,
+                                type: 'default'
+                            };
+                        }
+
+                        look = named.lookups.nsstats[x];
+                        // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
+                    }
+
+                    switch(look.type) {
+                        case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
+                        case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
+                        case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
+                        case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
+                        case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
+                        case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
+                        case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
+                        default: default_enable = true; break;
+                    }
+                }
+
+                if(global_requests_enable == true)
+                    service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'requests', 'named.requests', netdata.chartTypes.stacked, named.base_priority + 1, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(global_queries_success_enable == true)
+                    service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'queries', 'named.queries.succcess', netdata.chartTypes.line, named.base_priority + 2, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(protocol_queries_enable == true)
+                    service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'queries', 'named.protocol.queries', netdata.chartTypes.stacked, named.base_priority + 3, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(global_queries_enable == true)
+                    service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'queries', 'named.global.queries', netdata.chartTypes.stacked, named.base_priority + 4, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(global_updates_enable == true)
+                    service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'updates', 'named.global.updates', netdata.chartTypes.stacked, named.base_priority + 5, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(global_failures_enable == true)
+                    service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'failures', 'named.global.failures', netdata.chartTypes.line, named.base_priority + 6, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(global_failures_detail_enable == true)
+                    service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'failures', 'named.global.failures.detail', netdata.chartTypes.stacked, named.base_priority + 7, netdata.chartAlgorithms.incremental, 1, 1);
+
+                if(default_enable === true)
+                    service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'other', 'named.nsstats', netdata.chartTypes.line, named.base_priority + 8, netdata.chartAlgorithms.incremental, 1, 1);
+
+                // RecursClients chart
+                {
+                    var id = 'named_' + service.name + '.recursive_clients';
+                    var chart = named.charts[id];
+
+                    if(typeof chart === 'undefined') {
+                        chart = {
+                            id: id,                                         // the unique id of the chart
+                            name: '',                                       // the unique name of the chart
+                            title: service.name + ' Bind, Current Recursive Clients',       // the title of the chart
+                            units: 'clients',                               // the units of the chart dimensions
+                            family: 'clients',                              // the family of the chart
+                            context: 'named.recursive.clients',             // the context of the chart
+                            type: netdata.chartTypes.line,                  // the type of the chart
+                            priority: named.base_priority + 1,              // the priority relative to others in the same family
+                            update_every: service.update_every,             // the expected update frequency of the chart
+                            dimensions: {
+                                'clients': {
+                                    id: 'clients',                              // the unique id of the dimension
+                                    name: '',                                   // the name of the dimension
+                                    algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+                                    multiplier: 1,                              // the multiplier
+                                    divisor: 1,                                 // the divisor
+                                    hidden: false                               // is hidden (boolean)
+                                }
+                            }
+                        };
+
+                        chart = service.chart(id, chart);
+                        named.charts[id] = chart;
+                    }
+
+                    service.begin(chart);
+                    service.set('clients', RecursClients);
+                    service.end();
+                }
+            }
+
+            if(typeof r.opcodes !== 'undefined')
+                service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'requests', 'named.in.opcodes', netdata.chartTypes.stacked, named.base_priority + 9, netdata.chartAlgorithms.incremental, 1, 1);
+
+            if(typeof r.qtypes !== 'undefined')
+                service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'requests', 'named.in.qtypes', netdata.chartTypes.stacked, named.base_priority + 10, netdata.chartAlgorithms.incremental, 1, 1);
+
+            if(typeof r.sockstats !== 'undefined')
+                service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'sockets', 'named.in.sockstats', netdata.chartTypes.line, named.base_priority + 11, netdata.chartAlgorithms.incremental, 1, 1);
+
+            if(typeof r.views !== 'undefined') {
+                for( var x in r.views ) {
+                    var resolver = r.views[x].resolver;
+
+                    if(typeof resolver !== 'undefined') {
+                        if(typeof resolver.stats !== 'undefined') {
+                            var NumFetch = 0;
+                            var key = service.name + '.' + x;
+                            var default_enable = false;
+                            var rtt = {}, rtt_enable = false;
+
+                            // NumFetch is an absolute value
+                            if(typeof resolver.stats['NumFetch'] !== 'undefined') {
+                                named.lookups.numfetch[key] = true;
+                                NumFetch = resolver.stats['NumFetch'];
+                                delete resolver.stats['NumFetch'];
+                            }
+                            if(typeof resolver.stats['BucketSize'] !== 'undefined') {
+                                delete resolver.stats['BucketSize'];
+                            }
+
+                            // split the QryRTT* from the main chart
+                            for( var y in resolver.stats ) {
+                                // we maintain an index of the values found
+                                // mapping them to objects splitted
+
+                                var look = named.lookups.resolver_stats[y];
+                                if(typeof look === 'undefined') {
+                                    if(y.match(/^QryRTT/) !== null) {
+                                        named.lookups.resolver_stats[y] = {
+                                            name: y,
+                                            type: 'rtt'
+                                        };
+                                    }
+                                    else {
+                                        named.lookups.resolver_stats[y] = {
+                                            name: y,
+                                            type: 'default'
+                                        };
+                                    }
+
+                                    look = named.lookups.resolver_stats[y];
+                                    // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
+                                }
+
+                                switch(look.type) {
+                                    case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
+                                    default: default_enable = true; break;
+                                }
+                            }
+
+                            if(rtt_enable)
+                                service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'view_' + x, 'named.resolver.rtt', netdata.chartTypes.stacked, named.base_priority + 12, netdata.chartAlgorithms.incremental, 1, 1);
+
+                            if(default_enable)
+                                service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'view_' + x, 'named.resolver.stats', netdata.chartTypes.line, named.base_priority + 13, netdata.chartAlgorithms.incremental, 1, 1);
+
+                            // NumFetch chart
+                            if(typeof named.lookups.numfetch[key] !== 'undefined') {
+                                var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
+                                var chart = named.charts[id];
+
+                                if(typeof chart === 'undefined') {
+                                    chart = {
+                                        id: id,                                         // the unique id of the chart
+                                        name: '',                                       // the unique name of the chart
+                                        title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries',     // the title of the chart
+                                        units: 'queries',                               // the units of the chart dimensions
+                                        family: 'view_' + x,                            // the family of the chart
+                                        context: 'named.resolver.active.queries',       // the context of the chart
+                                        type: netdata.chartTypes.line,                  // the type of the chart
+                                        priority: named.base_priority + 1001,           // the priority relative to others in the same family
+                                        update_every: service.update_every,             // the expected update frequency of the chart
+                                        dimensions: {
+                                            'queries': {
+                                                id: 'queries',                              // the unique id of the dimension
+                                                name: '',                                   // the name of the dimension
+                                                algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+                                                multiplier: 1,                              // the multiplier
+                                                divisor: 1,                                 // the divisor
+                                                hidden: false                               // is hidden (boolean)
+                                            }
+                                        }
+                                    };
+
+                                    chart = service.chart(id, chart);
+                                    named.charts[id] = chart;
+                                }
+
+                                service.begin(chart);
+                                service.set('queries', NumFetch);
+                                service.end();
+                            }
+                        }
+                    }
+
+                    if(typeof resolver.qtypes !== 'undefined')
+                        service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'view_' + x, 'named.resolver.qtypes', netdata.chartTypes.stacked, named.base_priority + 14, netdata.chartAlgorithms.incremental, 1, 1);
+
+                    //if(typeof resolver.cache !== 'undefined')
+                    //  service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'view_' + x, 'named.resolver.cache', netdata.chartTypes.stacked, named.base_priority + 15, netdata.chartAlgorithms.absolute, 1, 1);
+
+                    if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
+                        var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
+                        var chart = named.charts[id];
+
+                        if(typeof chart === 'undefined') {
+                            chart = {
+                                id: id,                                         // the unique id of the chart
+                                name: '',                                       // the unique name of the chart
+                                title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits',     // the title of the chart
+                                units: 'operations/s',                          // the units of the chart dimensions
+                                family: 'view_' + x,                            // the family of the chart
+                                context: 'named.resolver.cache.hits',           // the context of the chart
+                                type: netdata.chartTypes.area,                  // the type of the chart
+                                priority: named.base_priority + 1100,           // the priority relative to others in the same family
+                                update_every: service.update_every,             // the expected update frequency of the chart
+                                dimensions: {
+                                    'CacheHits': {
+                                        id: 'CacheHits',                            // the unique id of the dimension
+                                        name: 'hits',                               // the name of the dimension
+                                        algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
+                                        multiplier: 1,                              // the multiplier
+                                        divisor: 1,                                 // the divisor
+                                        hidden: false                               // is hidden (boolean)
+                                    },
+                                    'CacheMisses': {
+                                        id: 'CacheMisses',                          // the unique id of the dimension
+                                        name: 'misses',                             // the name of the dimension
+                                        algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
+                                        multiplier: -1,                             // the multiplier
+                                        divisor: 1,                                 // the divisor
+                                        hidden: false                               // is hidden (boolean)
+                                    }
+                                }
+                            };
+
+                            chart = service.chart(id, chart);
+                            named.charts[id] = chart;
+                        }
+
+                        service.begin(chart);
+                        service.set('CacheHits', resolver.cachestats['CacheHits']);
+                        service.set('CacheMisses', resolver.cachestats['CacheMisses']);
+                        service.end();
+                    }
+
+                    // this is wrong, it contains many types of info:
+                    // 1. CacheHits, CacheMisses - incremental (added above)
+                    // 2. QueryHits, QueryMisses - incremental
+                    // 3. DeleteLRU, DeleteTTL - incremental
+                    // 4. CacheNodes, CacheBuckets - absolute
+                    // 5. TreeMemTotal, TreeMemInUse - absolute
+                    // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
+                    //if(typeof resolver.cachestats !== 'undefined')
+                    //  service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'view_' + x, 'named.resolver.cache.stats', netdata.chartTypes.line, named.base_priority + 1001, netdata.chartAlgorithms.incremental, 1, 1);
+
+                    //if(typeof resolver.adb !== 'undefined')
+                    //  service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'view_' + x, 'named.resolver.adb', netdata.chartTypes.line, named.base_priority + 1002, netdata.chartAlgorithms.absolute, 1, 1);
+                }
+            }
+        }
+    },
+
+    // module.serviceExecute()
+    // this function is called only from this module
+    // its purpose is to prepare the request and call
+    // netdata.serviceExecute()
+    serviceExecute: function(name, a_url, update_every) {
+        if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
+        var service = netdata.service({
+            name: name,
+            request: netdata.requestFromURL(a_url),
+            update_every: update_every,
+            module: this
+        });
+
+        service.execute(this.processResponse);
+    },
+
+    configure: function(config) {
+        var added = 0;
+
+        if(this.enable_autodetect === true) {
+            this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
+            added++;
+        }
+        
+        if(typeof(config.servers) !== 'undefined') {
+            var len = config.servers.length;
+            while(len--) {
+                if(typeof config.servers[len].update_every === 'undefined')
+                    config.servers[len].update_every = this.update_every;
+
+                this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
+                added++;
+            }
+        }
+
+        return added;
+    },
+
+    // module.update()
+    // this is called repeatidly to collect data, by calling
+    // netdata.serviceExecute()
+    update: function(service, callback) {
+        service.execute(function(serv, data) {
+            service.module.processResponse(serv, data);
+            callback();
+        });
+    },
 };
 
 module.exports = named;
index 5ed1c55a7c8e1e37dc29362bc5a30d2d37c1310e..a6ce12052a61e34d640458ca09fd3b4c8a32a712 100644 (file)
@@ -6,20 +6,20 @@
 // example configuration in /etc/netdata/sma_webbox.conf
 /*
 {
-       "enable_autodetect": false,
-       "update_every": 5,
-       "servers": [
-               {
-                       "name": "plant1",
-                       "hostname": "10.0.1.1",
-                       "update_every": 10
-               },
-               {
-                       "name": "plant2",
-                       "hostname": "10.0.2.1",
-                       "update_every": 15
-               }
-       ]
+    "enable_autodetect": false,
+    "update_every": 5,
+    "servers": [
+        {
+            "name": "plant1",
+            "hostname": "10.0.1.1",
+            "update_every": 10
+        },
+        {
+            "name": "plant2",
+            "hostname": "10.0.2.1",
+            "update_every": 15
+        }
+    ]
 }
 */
 
@@ -30,208 +30,208 @@ var netdata = require('netdata');
 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
 
 var webbox = {
-       name: __filename,
-       enable_autodetect: true,
-       update_every: 1,
-       base_priority: 60000,
-       charts: {},
-
-       processResponse: function(service, data) {
-               if(data !== null) {
-                       var r = JSON.parse(data);
-
-                       var d = {
-                               'GriPwr': {
-                                       unit: null,
-                                       value: null
-                               },
-                               'GriEgyTdy': {
-                                       unit: null,
-                                       value: null
-                               },
-                               'GriEgyTot': {
-                                       unit: null,
-                                       value: null
-                               }
-                       };
-
-                       // parse the webbox response
-                       // and put it in our d object
-                       var found = 0;
-                       var len = r.result.overview.length;
-                       while(len--) {
-                               var e = r.result.overview[len];
-                               if(typeof(d[e.meta]) !== 'undefined') {
-                                       found++;
-                                       d[e.meta].value = e.value;
-                                       d[e.meta].unit = e.unit;
-                               }
-                       }
-
-                       // add the service
-                       if(found > 0 && service.added !== true)
-                               service.commit();
-
-                       // Grid Current Power Chart
-                       if(d['GriPwr'].value !== null) {
-                               var id = 'sma_webbox_' + service.name + '.current';
-                               var chart = webbox.charts[id];
-
-                               if(typeof chart === 'undefined') {
-                                       chart = {
-                                               id: id,                                                                                 // the unique id of the chart
-                                               name: '',                                                                               // the unique name of the chart
-                                               title: service.name + ' Current Grid Power',    // the title of the chart
-                                               units: d['GriPwr'].unit,                                                // the units of the chart dimensions
-                                               family: 'now',                                                                  // the family of the chart
-                                               context: 'sma_webbox.grid.power',                               // the context of the chart
-                                               type: netdata.chartTypes.area,                                  // the type of the chart
-                                               priority: webbox.base_priority + 1,                             // the priority relative to others in the same family
-                                               update_every: service.update_every,                             // the expected update frequency of the chart
-                                               dimensions: {
-                                                       'GriPwr': {
-                                                               id: 'GriPwr',                                                           // the unique id of the dimension
-                                                               name: 'power',                                                          // the name of the dimension
-                                                               algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
-                                                               multiplier: 1,                                                          // the multiplier
-                                                               divisor: 1,                                                                     // the divisor
-                                                               hidden: false                                                           // is hidden (boolean)
-                                                       }
-                                               }
-                                       };
-
-                                       chart = service.chart(id, chart);
-                                       webbox.charts[id] = chart;
-                               }
-
-                               service.begin(chart);
-                               service.set('GriPwr', Math.round(d['GriPwr'].value));
-                               service.end();
-                       }
-
-                       if(d['GriEgyTdy'].value !== null) {
-                               var id = 'sma_webbox_' + service.name + '.today';
-                               var chart = webbox.charts[id];
-
-                               if(typeof chart === 'undefined') {
-                                       chart = {
-                                               id: id,                                                                                 // the unique id of the chart
-                                               name: '',                                                                               // the unique name of the chart
-                                               title: service.name + ' Today Grid Power',              // the title of the chart
-                                               units: d['GriEgyTdy'].unit,                                             // the units of the chart dimensions
-                                               family: 'today',                                                                // the family of the chart
-                                               context: 'sma_webbox.grid.power.today',                 // the context of the chart
-                                               type: netdata.chartTypes.area,                                  // the type of the chart
-                                               priority: webbox.base_priority + 2,                             // the priority relative to others in the same family
-                                               update_every: service.update_every,                             // the expected update frequency of the chart
-                                               dimensions: {
-                                                       'GriEgyTdy': {
-                                                               id: 'GriEgyTdy',                                                                // the unique id of the dimension
-                                                               name: 'power',                                                          // the name of the dimension
-                                                               algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
-                                                               multiplier: 1,                                                          // the multiplier
-                                                               divisor: 1000,                                                          // the divisor
-                                                               hidden: false                                                           // is hidden (boolean)
-                                                       }
-                                               }
-                                       };
-
-                                       chart = service.chart(id, chart);
-                                       webbox.charts[id] = chart;
-                               }
-
-                               service.begin(chart);
-                               service.set('GriEgyTdy', Math.round(d['GriEgyTdy'].value * 1000));
-                               service.end();
-                       }
-
-                       if(d['GriEgyTot'].value !== null) {
-                               var id = 'sma_webbox_' + service.name + '.total';
-                               var chart = webbox.charts[id];
-
-                               if(typeof chart === 'undefined') {
-                                       chart = {
-                                               id: id,                                                                                 // the unique id of the chart
-                                               name: '',                                                                               // the unique name of the chart
-                                               title: service.name + ' Total Grid Power',              // the title of the chart
-                                               units: d['GriEgyTot'].unit,                                             // the units of the chart dimensions
-                                               family: 'total',                                                                // the family of the chart
-                                               context: 'sma_webbox.grid.power.total',                 // the context of the chart
-                                               type: netdata.chartTypes.area,                                  // the type of the chart
-                                               priority: webbox.base_priority + 3,                             // the priority relative to others in the same family
-                                               update_every: service.update_every,                             // the expected update frequency of the chart
-                                               dimensions: {
-                                                       'GriEgyTot': {
-                                                               id: 'GriEgyTot',                                                                // the unique id of the dimension
-                                                               name: 'power',                                                          // the name of the dimension
-                                                               algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
-                                                               multiplier: 1,                                                          // the multiplier
-                                                               divisor: 1000,                                                          // the divisor
-                                                               hidden: false                                                           // is hidden (boolean)
-                                                       }
-                                               }
-                                       };
-
-                                       chart = service.chart(id, chart);
-                                       webbox.charts[id] = chart;
-                               }
-
-                               service.begin(chart);
-                               service.set('GriEgyTot', Math.round(d['GriEgyTot'].value * 1000));
-                               service.end();
-                       }
-               }
-       },
-
-       // module.serviceExecute()
-       // this function is called only from this module
-       // its purpose is to prepare the request and call
-       // netdata.serviceExecute()
-       serviceExecute: function(name, hostname, update_every) {
-               if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every);
-
-               var service = netdata.service({
-                       name: name,
-                       request: netdata.requestFromURL('http://' + hostname + '/rpc'),
-                       update_every: update_every,
-                       module: this
-               });
-               service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}';
-               service.request.method = 'POST';
-               service.request.headers['Content-Length'] = service.postData.length;
-
-               service.execute(this.processResponse);
-       },
-
-       configure: function(config) {
-               var added = 0;
-
-               if(typeof(config.servers) !== 'undefined') {
-                       var len = config.servers.length;
-                       while(len--) {
-                               if(typeof config.servers[len].update_every === 'undefined')
-                                       config.servers[len].update_every = this.update_every;
-
-                               if(config.servers[len].update_every < 5)
-                                       config.servers[len].update_every = 5;
-
-                               this.serviceExecute(config.servers[len].name, config.servers[len].hostname, config.servers[len].update_every);
-                               added++;
-                       }
-               }
-
-               return added;
-       },
-
-       // module.update()
-       // this is called repeatidly to collect data, by calling
-       // netdata.serviceExecute()
-       update: function(service, callback) {
-               service.execute(function(serv, data) {
-                       service.module.processResponse(serv, data);
-                       callback();
-               });
-       },
+    name: __filename,
+    enable_autodetect: true,
+    update_every: 1,
+    base_priority: 60000,
+    charts: {},
+
+    processResponse: function(service, data) {
+        if(data !== null) {
+            var r = JSON.parse(data);
+
+            var d = {
+                'GriPwr': {
+                    unit: null,
+                    value: null
+                },
+                'GriEgyTdy': {
+                    unit: null,
+                    value: null
+                },
+                'GriEgyTot': {
+                    unit: null,
+                    value: null
+                }
+            };
+
+            // parse the webbox response
+            // and put it in our d object
+            var found = 0;
+            var len = r.result.overview.length;
+            while(len--) {
+                var e = r.result.overview[len];
+                if(typeof(d[e.meta]) !== 'undefined') {
+                    found++;
+                    d[e.meta].value = e.value;
+                    d[e.meta].unit = e.unit;
+                }
+            }
+
+            // add the service
+            if(found > 0 && service.added !== true)
+                service.commit();
+
+            // Grid Current Power Chart
+            if(d['GriPwr'].value !== null) {
+                var id = 'sma_webbox_' + service.name + '.current';
+                var chart = webbox.charts[id];
+
+                if(typeof chart === 'undefined') {
+                    chart = {
+                        id: id,                                         // the unique id of the chart
+                        name: '',                                       // the unique name of the chart
+                        title: service.name + ' Current Grid Power',    // the title of the chart
+                        units: d['GriPwr'].unit,                        // the units of the chart dimensions
+                        family: 'now',                                  // the family of the chart
+                        context: 'sma_webbox.grid.power',               // the context of the chart
+                        type: netdata.chartTypes.area,                  // the type of the chart
+                        priority: webbox.base_priority + 1,             // the priority relative to others in the same family
+                        update_every: service.update_every,             // the expected update frequency of the chart
+                        dimensions: {
+                            'GriPwr': {
+                                id: 'GriPwr',                               // the unique id of the dimension
+                                name: 'power',                              // the name of the dimension
+                                algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+                                multiplier: 1,                              // the multiplier
+                                divisor: 1,                                 // the divisor
+                                hidden: false                               // is hidden (boolean)
+                            }
+                        }
+                    };
+
+                    chart = service.chart(id, chart);
+                    webbox.charts[id] = chart;
+                }
+
+                service.begin(chart);
+                service.set('GriPwr', Math.round(d['GriPwr'].value));
+                service.end();
+            }
+
+            if(d['GriEgyTdy'].value !== null) {
+                var id = 'sma_webbox_' + service.name + '.today';
+                var chart = webbox.charts[id];
+
+                if(typeof chart === 'undefined') {
+                    chart = {
+                        id: id,                                         // the unique id of the chart
+                        name: '',                                       // the unique name of the chart
+                        title: service.name + ' Today Grid Power',      // the title of the chart
+                        units: d['GriEgyTdy'].unit,                     // the units of the chart dimensions
+                        family: 'today',                                // the family of the chart
+                        context: 'sma_webbox.grid.power.today',         // the context of the chart
+                        type: netdata.chartTypes.area,                  // the type of the chart
+                        priority: webbox.base_priority + 2,             // the priority relative to others in the same family
+                        update_every: service.update_every,             // the expected update frequency of the chart
+                        dimensions: {
+                            'GriEgyTdy': {
+                                id: 'GriEgyTdy',                                // the unique id of the dimension
+                                name: 'power',                              // the name of the dimension
+                                algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+                                multiplier: 1,                              // the multiplier
+                                divisor: 1000,                              // the divisor
+                                hidden: false                               // is hidden (boolean)
+                            }
+                        }
+                    };
+
+                    chart = service.chart(id, chart);
+                    webbox.charts[id] = chart;
+                }
+
+                service.begin(chart);
+                service.set('GriEgyTdy', Math.round(d['GriEgyTdy'].value * 1000));
+                service.end();
+            }
+
+            if(d['GriEgyTot'].value !== null) {
+                var id = 'sma_webbox_' + service.name + '.total';
+                var chart = webbox.charts[id];
+
+                if(typeof chart === 'undefined') {
+                    chart = {
+                        id: id,                                         // the unique id of the chart
+                        name: '',                                       // the unique name of the chart
+                        title: service.name + ' Total Grid Power',      // the title of the chart
+                        units: d['GriEgyTot'].unit,                     // the units of the chart dimensions
+                        family: 'total',                                // the family of the chart
+                        context: 'sma_webbox.grid.power.total',         // the context of the chart
+                        type: netdata.chartTypes.area,                  // the type of the chart
+                        priority: webbox.base_priority + 3,             // the priority relative to others in the same family
+                        update_every: service.update_every,             // the expected update frequency of the chart
+                        dimensions: {
+                            'GriEgyTot': {
+                                id: 'GriEgyTot',                                // the unique id of the dimension
+                                name: 'power',                              // the name of the dimension
+                                algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+                                multiplier: 1,                              // the multiplier
+                                divisor: 1000,                              // the divisor
+                                hidden: false                               // is hidden (boolean)
+                            }
+                        }
+                    };
+
+                    chart = service.chart(id, chart);
+                    webbox.charts[id] = chart;
+                }
+
+                service.begin(chart);
+                service.set('GriEgyTot', Math.round(d['GriEgyTot'].value * 1000));
+                service.end();
+            }
+        }
+    },
+
+    // module.serviceExecute()
+    // this function is called only from this module
+    // its purpose is to prepare the request and call
+    // netdata.serviceExecute()
+    serviceExecute: function(name, hostname, update_every) {
+        if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every);
+
+        var service = netdata.service({
+            name: name,
+            request: netdata.requestFromURL('http://' + hostname + '/rpc'),
+            update_every: update_every,
+            module: this
+        });
+        service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}';
+        service.request.method = 'POST';
+        service.request.headers['Content-Length'] = service.postData.length;
+
+        service.execute(this.processResponse);
+    },
+
+    configure: function(config) {
+        var added = 0;
+
+        if(typeof(config.servers) !== 'undefined') {
+            var len = config.servers.length;
+            while(len--) {
+                if(typeof config.servers[len].update_every === 'undefined')
+                    config.servers[len].update_every = this.update_every;
+
+                if(config.servers[len].update_every < 5)
+                    config.servers[len].update_every = 5;
+
+                this.serviceExecute(config.servers[len].name, config.servers[len].hostname, config.servers[len].update_every);
+                added++;
+            }
+        }
+
+        return added;
+    },
+
+    // module.update()
+    // this is called repeatidly to collect data, by calling
+    // netdata.serviceExecute()
+    update: function(service, callback) {
+        service.execute(function(serv, data) {
+            service.module.processResponse(serv, data);
+            callback();
+        });
+    },
 };
 
 module.exports = webbox;
index 21615f6237e9e9564a3f309dbccf4443ef9db28d..ddc8985270be68ebd6c4e3a8d17e415f8273fdef 100644 (file)
@@ -5,60 +5,60 @@
 // example configuration in /etc/netdata/snmp.conf
 /*
 {
-       "enable_autodetect": false,
-       "update_every": 5,
-       "max_request_size": 50,
-       "servers": [
-               {
-                       "hostname": "10.11.12.8",
-                       "community": "public",
-                       "update_every": 10,
-                       "max_request_size": 50,
-                       "options": { "timeout": 10000 },
-                       "charts": {
-                               "snmp_switch.bandwidth_port1": {
-                                       "title": "Switch Bandwidth for port 1",
-                                       "units": "kilobits/s",
-                                       "type": "area",
-                                       "priority": 1,
-                                       "dimensions": {
-                                               "in": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.10.1",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": 8,
-                                                       "divisor": 1024
-                                               },
-                                               "out": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.16.1",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": -8,
-                                                       "divisor": 1024
-                                               }
-                                       }
-                               },
-                               "snmp_switch.bandwidth_port2": {
-                                       "title": "Switch Bandwidth for port 2",
-                                       "units": "kilobits/s",
-                                       "type": "area",
-                                       "priority": 1,
-                                       "dimensions": {
-                                               "in": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.10.2",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": 8,
-                                                       "divisor": 1024
-                                               },
-                                               "out": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.16.2",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": -8,
-                                                       "divisor": 1024
-                                               }
-                                       }
-                               }
-                       }
-               }
-       ]
+    "enable_autodetect": false,
+    "update_every": 5,
+    "max_request_size": 50,
+    "servers": [
+        {
+            "hostname": "10.11.12.8",
+            "community": "public",
+            "update_every": 10,
+            "max_request_size": 50,
+            "options": { "timeout": 10000 },
+            "charts": {
+                "snmp_switch.bandwidth_port1": {
+                    "title": "Switch Bandwidth for port 1",
+                    "units": "kilobits/s",
+                    "type": "area",
+                    "priority": 1,
+                    "dimensions": {
+                        "in": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.10.1",
+                            "algorithm": "incremental",
+                            "multiplier": 8,
+                            "divisor": 1024
+                        },
+                        "out": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.16.1",
+                            "algorithm": "incremental",
+                            "multiplier": -8,
+                            "divisor": 1024
+                        }
+                    }
+                },
+                "snmp_switch.bandwidth_port2": {
+                    "title": "Switch Bandwidth for port 2",
+                    "units": "kilobits/s",
+                    "type": "area",
+                    "priority": 1,
+                    "dimensions": {
+                        "in": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.10.2",
+                            "algorithm": "incremental",
+                            "multiplier": 8,
+                            "divisor": 1024
+                        },
+                        "out": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.16.2",
+                            "algorithm": "incremental",
+                            "multiplier": -8,
+                            "divisor": 1024
+                        }
+                    }
+                }
+            }
+        }
+    ]
 }
 */
 
 // so that 24 charts will be created.
 /*
 {
-       "enable_autodetect": false,
-       "update_every": 10,
-       "max_request_size": 50,
-       "servers": [
-               {
-                       "hostname": "10.11.12.8",
-                       "community": "public",
-                       "update_every": 10,
-                       "max_request_size": 50,
-                       "options": { "timeout": 20000 },
-                       "charts": {
-                               "snmp_switch.bandwidth_port": {
-                                       "title": "Switch Bandwidth for port ",
-                                       "units": "kilobits/s",
-                                       "type": "area",
-                                       "priority": 1,
-                                       "multiply_range": [ 1, 24 ],
-                                       "dimensions": {
-                                               "in": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.10.",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": 8,
-                                                       "divisor": 1024
-                                               },
-                                               "out": {
-                                                       "oid": ".1.3.6.1.2.1.2.2.1.16.",
-                                                       "algorithm": "incremental",
-                                                       "multiplier": -8,
-                                                       "divisor": 1024
-                                               }
-                                       }
-                               }
-                       }
-               }
-       ]
+    "enable_autodetect": false,
+    "update_every": 10,
+    "max_request_size": 50,
+    "servers": [
+        {
+            "hostname": "10.11.12.8",
+            "community": "public",
+            "update_every": 10,
+            "max_request_size": 50,
+            "options": { "timeout": 20000 },
+            "charts": {
+                "snmp_switch.bandwidth_port": {
+                    "title": "Switch Bandwidth for port ",
+                    "units": "kilobits/s",
+                    "type": "area",
+                    "priority": 1,
+                    "multiply_range": [ 1, 24 ],
+                    "dimensions": {
+                        "in": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.10.",
+                            "algorithm": "incremental",
+                            "multiplier": 8,
+                            "divisor": 1024
+                        },
+                        "out": {
+                            "oid": ".1.3.6.1.2.1.2.2.1.16.",
+                            "algorithm": "incremental",
+                            "multiplier": -8,
+                            "divisor": 1024
+                        }
+                    }
+                }
+            }
+        }
+    ]
 }
 */
 
@@ -112,325 +112,325 @@ var netdata = require('netdata');
 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
 
 netdata.processors.snmp = {
-       name: 'snmp',
-
-       fixoid: function(oid) {
-               if(typeof oid !== 'string')
-                       return oid;
-
-               if(oid.charAt(0) === '.')
-                       return oid.substring(1, oid.length);
-
-               return oid;
-       },
-
-       prepare: function(service) {
-               if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
-                       // this is the first time we see this service
-
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
-
-                       // build an index of all OIDs
-                       service.snmp_oids_index = {};
-                       for(var c in service.request.charts) {
-                               // for each chart
-
-                               if(netdata.options.DEBUG === true)
-                                       netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
-
-                               if(typeof service.request.charts[c].titleoid !== 'undefined') {
-                                               service.snmp_oids_index[this.fixoid(service.request.charts[c].titleoid)] = {
-                                                       type: 'title',
-                                                       link: service.request.charts[c]
-                                               };
-                                       }
-
-                               for(var d in service.request.charts[c].dimensions) {
-                                       // for each dimension in the chart
-
-                                       var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
-                                       var oidname = this.fixoid(service.request.charts[c].dimensions[d].oidname);
-                                       
-                                       if(netdata.options.DEBUG === true)
-                                               netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
-
-                                       // link it to the point we need to set the value to
-                                       service.snmp_oids_index[oid] = {
-                                               type: 'value',
-                                               link: service.request.charts[c].dimensions[d]
-                                       };
-
-                                       if(typeof oidname !== 'undefined')
-                                               service.snmp_oids_index[oidname] = {
-                                                       type: 'name',
-                                                       link: service.request.charts[c].dimensions[d]
-                                               };
-
-                                       // and set the value to null
-                                       service.request.charts[c].dimensions[d].value = null;
-                               }
-                       }
-
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
-
-                       // now create the array of OIDs needed by net-snmp
-                       service.snmp_oids = new Array();
-                       for(var o in service.snmp_oids_index)
-                               service.snmp_oids.push(o);
-
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
-
-                       service.snmp_oids_cleaned = 0;
-               }
-               else if(service.snmp_oids_cleaned === 0) {
-                       service.snmp_oids_cleaned = 1;
-
-                       // the second time, keep only values
-                       service.snmp_oids = new Array();
-                       for(var o in service.snmp_oids_index)
-                               if(service.snmp_oids_index[o].type === 'value')
-                                       service.snmp_oids.push(o);
-               }
-       },
-
-       getdata: function(service, index, ok, failed, callback) {
-               var that = this;
-
-               if(index >= service.snmp_oids.length) {
-                       callback((ok > 0)?{ ok: ok, failed: failed }:null);
-                       return;
-               }
-
-               var slice;
-               if(service.snmp_oids.length <= service.request.max_request_size) {
-                       slice = service.snmp_oids;
-                       index = service.snmp_oids.length;
-               }
-               else if(service.snmp_oids.length - index <= service.request.max_request_size) {
-                       slice = service.snmp_oids.slice(index, service.snmp_oids.length);
-                       index = service.snmp_oids.length;
-               }
-               else {
-                       slice = service.snmp_oids.slice(index, index + service.request.max_request_size);
-                       index += service.request.max_request_size;
-               }
-
-               if(netdata.options.DEBUG === true)
-                       netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size);
-
-               service.snmp_session.get(slice, function(error, varbinds) {
-                       if(error) {
-                               service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
-
-                               // make all values null
-                               var len = slice.length;
-                               while(len--)
-                                       service.snmp_oids_index[slice[len]].value = null;
-                       }
-                       else {
-                               if(netdata.options.DEBUG === true)
-                                       netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
-
-                               for(var i = 0; i < varbinds.length; i++) {
-                                       var value = null;
-
-                                       if(net_snmp.isVarbindError(varbinds[i])) {
-                                               if(netdata.options.DEBUG === true)
-                                                       netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
-
-                                               service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
-                                               value = null;
-                                               failed++;
-                                       }
-                                       else {
-                                               if(netdata.options.DEBUG === true)
-                                                       netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
-
-                                               value = varbinds[i].value;
-                                               ok++;
-                                       }
-
-                                       if(value !== null) {
-                                               switch(service.snmp_oids_index[varbinds[i].oid].type) {
-                                                       case 'title': service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; break;
-                                                       case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value; break;
-                                                       case 'value': service.snmp_oids_index[varbinds[i].oid].link.value = value; break;
-                                               }
-                                       }
-                               }
-
-                               if(netdata.options.DEBUG === true)
-                                       netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
-                       }
-                       that.getdata(service, index, ok, failed, callback);
-               });
-       },
-
-       process: function(service, callback) {
-               this.prepare(service);
-
-               if(service.snmp_oids.length === 0) {
-                       // no OIDs found for this service
-
-                       if(netdata.options.DEBUG === true)
-                               service.error('no OIDs to process.');
-
-                       callback(null);
-                       return;
-               }
-
-               if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
-                       // no SNMP session has been created for this service
-                       // the SNMP session is just the initialization of NET-SNMP
-
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
-
-                       // create the SNMP session
-                       service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
-
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
-
-                       // if we later need traps, this is how to do it:
-                       //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
-                       //      if(error) console.error('trap error: ' + netdata.stringify(error));
-                       //});
-               }
-
-               // do it, get the SNMP values for the sessions we need
-               this.getdata(service, 0, 0, 0, callback);
-       }
+    name: 'snmp',
+
+    fixoid: function(oid) {
+        if(typeof oid !== 'string')
+            return oid;
+
+        if(oid.charAt(0) === '.')
+            return oid.substring(1, oid.length);
+
+        return oid;
+    },
+
+    prepare: function(service) {
+        if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
+            // this is the first time we see this service
+
+            if(netdata.options.DEBUG === true)
+                netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
+
+            // build an index of all OIDs
+            service.snmp_oids_index = {};
+            for(var c in service.request.charts) {
+                // for each chart
+
+                if(netdata.options.DEBUG === true)
+                    netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
+
+                if(typeof service.request.charts[c].titleoid !== 'undefined') {
+                        service.snmp_oids_index[this.fixoid(service.request.charts[c].titleoid)] = {
+                            type: 'title',
+                            link: service.request.charts[c]
+                        };
+                    }
+
+                for(var d in service.request.charts[c].dimensions) {
+                    // for each dimension in the chart
+
+                    var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
+                    var oidname = this.fixoid(service.request.charts[c].dimensions[d].oidname);
+                    
+                    if(netdata.options.DEBUG === true)
+                        netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
+
+                    // link it to the point we need to set the value to
+                    service.snmp_oids_index[oid] = {
+                        type: 'value',
+                        link: service.request.charts[c].dimensions[d]
+                    };
+
+                    if(typeof oidname !== 'undefined')
+                        service.snmp_oids_index[oidname] = {
+                            type: 'name',
+                            link: service.request.charts[c].dimensions[d]
+                        };
+
+                    // and set the value to null
+                    service.request.charts[c].dimensions[d].value = null;
+                }
+            }
+
+            if(netdata.options.DEBUG === true)
+                netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
+
+            // now create the array of OIDs needed by net-snmp
+            service.snmp_oids = new Array();
+            for(var o in service.snmp_oids_index)
+                service.snmp_oids.push(o);
+
+            if(netdata.options.DEBUG === true)
+                netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
+
+            service.snmp_oids_cleaned = 0;
+        }
+        else if(service.snmp_oids_cleaned === 0) {
+            service.snmp_oids_cleaned = 1;
+
+            // the second time, keep only values
+            service.snmp_oids = new Array();
+            for(var o in service.snmp_oids_index)
+                if(service.snmp_oids_index[o].type === 'value')
+                    service.snmp_oids.push(o);
+        }
+    },
+
+    getdata: function(service, index, ok, failed, callback) {
+        var that = this;
+
+        if(index >= service.snmp_oids.length) {
+            callback((ok > 0)?{ ok: ok, failed: failed }:null);
+            return;
+        }
+
+        var slice;
+        if(service.snmp_oids.length <= service.request.max_request_size) {
+            slice = service.snmp_oids;
+            index = service.snmp_oids.length;
+        }
+        else if(service.snmp_oids.length - index <= service.request.max_request_size) {
+            slice = service.snmp_oids.slice(index, service.snmp_oids.length);
+            index = service.snmp_oids.length;
+        }
+        else {
+            slice = service.snmp_oids.slice(index, index + service.request.max_request_size);
+            index += service.request.max_request_size;
+        }
+
+        if(netdata.options.DEBUG === true)
+            netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size);
+
+        service.snmp_session.get(slice, function(error, varbinds) {
+            if(error) {
+                service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
+
+                // make all values null
+                var len = slice.length;
+                while(len--)
+                    service.snmp_oids_index[slice[len]].value = null;
+            }
+            else {
+                if(netdata.options.DEBUG === true)
+                    netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
+
+                for(var i = 0; i < varbinds.length; i++) {
+                    var value = null;
+
+                    if(net_snmp.isVarbindError(varbinds[i])) {
+                        if(netdata.options.DEBUG === true)
+                            netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
+
+                        service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
+                        value = null;
+                        failed++;
+                    }
+                    else {
+                        if(netdata.options.DEBUG === true)
+                            netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
+
+                        value = varbinds[i].value;
+                        ok++;
+                    }
+
+                    if(value !== null) {
+                        switch(service.snmp_oids_index[varbinds[i].oid].type) {
+                            case 'title': service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; break;
+                            case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value; break;
+                            case 'value': service.snmp_oids_index[varbinds[i].oid].link.value = value; break;
+                        }
+                    }
+                }
+
+                if(netdata.options.DEBUG === true)
+                    netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
+            }
+            that.getdata(service, index, ok, failed, callback);
+        });
+    },
+
+    process: function(service, callback) {
+        this.prepare(service);
+
+        if(service.snmp_oids.length === 0) {
+            // no OIDs found for this service
+
+            if(netdata.options.DEBUG === true)
+                service.error('no OIDs to process.');
+
+            callback(null);
+            return;
+        }
+
+        if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
+            // no SNMP session has been created for this service
+            // the SNMP session is just the initialization of NET-SNMP
+
+            if(netdata.options.DEBUG === true)
+                netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
+
+            // create the SNMP session
+            service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
+
+            if(netdata.options.DEBUG === true)
+                netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
+
+            // if we later need traps, this is how to do it:
+            //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
+            //  if(error) console.error('trap error: ' + netdata.stringify(error));
+            //});
+        }
+
+        // do it, get the SNMP values for the sessions we need
+        this.getdata(service, 0, 0, 0, callback);
+    }
 };
 
 var snmp = {
-       name: __filename,
-       enable_autodetect: true,
-       update_every: 1,
-       base_priority: 50000,
-
-       charts: {},
-
-       processResponse: function(service, data) {
-               if(data !== null) {
-                       if(service.added !== true)
-                               service.commit();
-
-                       for(var c in service.request.charts) {
-                               var chart = snmp.charts[c];
-
-                               if(typeof chart === 'undefined') {
-                                       chart = service.chart(c, service.request.charts[c]);
-                                       snmp.charts[c] = chart;
-                               }
-
-                               service.begin(chart);
-                               
-                               for( var d in service.request.charts[c].dimensions )
-                                       if(service.request.charts[c].dimensions[d].value !== null)
-                                               service.set(d, service.request.charts[c].dimensions[d].value);
-
-                               service.end();
-                       }
-               }
-       },
-
-       // module.serviceExecute()
-       // this function is called only from this module
-       // its purpose is to prepare the request and call
-       // netdata.serviceExecute()
-       serviceExecute: function(conf) {
-               if(netdata.options.DEBUG === true)
-                       netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
-
-               var service = netdata.service({
-                       name: conf.hostname,
-                       request: conf,
-                       update_every: conf.update_every,
-                       module: this,
-                       processor: netdata.processors.snmp
-               });
-
-               // multiply the charts, if required
-               for(var c in service.request.charts) {
-                       if(netdata.options.DEBUG === true)
-                               netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
-
-                       if(typeof service.request.charts[c].update_every === 'undefined')
-                               service.request.charts[c].update_every = service.update_every;
-
-                       if(typeof service.request.charts[c].multiply_range !== 'undefined') {
-                               var from = service.request.charts[c].multiply_range[0];
-                               var to = service.request.charts[c].multiply_range[1];
-                               var prio = service.request.charts[c].priority || 1;
-
-                               if(prio < snmp.base_priority) prio += snmp.base_priority;
-
-                               while(from <= to) {
-                                       var id = c + from.toString();
-                                       var chart = extend(true, {}, service.request.charts[c]);
-                                       chart.title += from.toString();
-                                       
-                                       if(typeof chart.titleoid !== 'undefined')
-                                               chart.titleoid += from.toString();
-
-                                       chart.priority = prio++;
-                                       for(var d in chart.dimensions) {
-                                               chart.dimensions[d].oid += from.toString();
-
-                                               if(typeof chart.dimensions[d].oidname !== 'undefined')
-                                                       chart.dimensions[d].oidname += from.toString();
-                                       }
-                                       service.request.charts[id] = chart;
-                                       from++;
-                               }
-
-                               delete service.request.charts[c];
-                       }
-                       else {
-                               if(service.request.charts[c].priority < snmp.base_priority)
-                                       service.request.charts[c].priority += snmp.base_priority;
-                       }
-               }
-
-               service.execute(this.processResponse);
-       },
-
-       configure: function(config) {
-               var added = 0;
-
-               if(typeof config.max_request_size === 'undefined')
-                       config.max_request_size = 50;
-
-               if(typeof(config.servers) !== 'undefined') {
-                       var len = config.servers.length;
-                       while(len--) {
-                               if(typeof config.servers[len].update_every === 'undefined')
-                                       config.servers[len].update_every = this.update_every;
-
-                               if(typeof config.servers[len].max_request_size === 'undefined')
-                                       config.servers[len].max_request_size = config.max_request_size;
-
-                               this.serviceExecute(config.servers[len]);
-                               added++;
-                       }
-               }
-
-               return added;
-       },
-
-       // module.update()
-       // this is called repeatidly to collect data, by calling
-       // service.execute()
-       update: function(service, callback) {
-               service.execute(function(serv, data) {
-                       service.module.processResponse(serv, data);
-                       callback();
-               });
-       },
+    name: __filename,
+    enable_autodetect: true,
+    update_every: 1,
+    base_priority: 50000,
+
+    charts: {},
+
+    processResponse: function(service, data) {
+        if(data !== null) {
+            if(service.added !== true)
+                service.commit();
+
+            for(var c in service.request.charts) {
+                var chart = snmp.charts[c];
+
+                if(typeof chart === 'undefined') {
+                    chart = service.chart(c, service.request.charts[c]);
+                    snmp.charts[c] = chart;
+                }
+
+                service.begin(chart);
+                
+                for( var d in service.request.charts[c].dimensions )
+                    if(service.request.charts[c].dimensions[d].value !== null)
+                        service.set(d, service.request.charts[c].dimensions[d].value);
+
+                service.end();
+            }
+        }
+    },
+
+    // module.serviceExecute()
+    // this function is called only from this module
+    // its purpose is to prepare the request and call
+    // netdata.serviceExecute()
+    serviceExecute: function(conf) {
+        if(netdata.options.DEBUG === true)
+            netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
+
+        var service = netdata.service({
+            name: conf.hostname,
+            request: conf,
+            update_every: conf.update_every,
+            module: this,
+            processor: netdata.processors.snmp
+        });
+
+        // multiply the charts, if required
+        for(var c in service.request.charts) {
+            if(netdata.options.DEBUG === true)
+                netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
+
+            if(typeof service.request.charts[c].update_every === 'undefined')
+                service.request.charts[c].update_every = service.update_every;
+
+            if(typeof service.request.charts[c].multiply_range !== 'undefined') {
+                var from = service.request.charts[c].multiply_range[0];
+                var to = service.request.charts[c].multiply_range[1];
+                var prio = service.request.charts[c].priority || 1;
+
+                if(prio < snmp.base_priority) prio += snmp.base_priority;
+
+                while(from <= to) {
+                    var id = c + from.toString();
+                    var chart = extend(true, {}, service.request.charts[c]);
+                    chart.title += from.toString();
+                    
+                    if(typeof chart.titleoid !== 'undefined')
+                        chart.titleoid += from.toString();
+
+                    chart.priority = prio++;
+                    for(var d in chart.dimensions) {
+                        chart.dimensions[d].oid += from.toString();
+
+                        if(typeof chart.dimensions[d].oidname !== 'undefined')
+                            chart.dimensions[d].oidname += from.toString();
+                    }
+                    service.request.charts[id] = chart;
+                    from++;
+                }
+
+                delete service.request.charts[c];
+            }
+            else {
+                if(service.request.charts[c].priority < snmp.base_priority)
+                    service.request.charts[c].priority += snmp.base_priority;
+            }
+        }
+
+        service.execute(this.processResponse);
+    },
+
+    configure: function(config) {
+        var added = 0;
+
+        if(typeof config.max_request_size === 'undefined')
+            config.max_request_size = 50;
+
+        if(typeof(config.servers) !== 'undefined') {
+            var len = config.servers.length;
+            while(len--) {
+                if(typeof config.servers[len].update_every === 'undefined')
+                    config.servers[len].update_every = this.update_every;
+
+                if(typeof config.servers[len].max_request_size === 'undefined')
+                    config.servers[len].max_request_size = config.max_request_size;
+
+                this.serviceExecute(config.servers[len]);
+                added++;
+            }
+        }
+
+        return added;
+    },
+
+    // module.update()
+    // this is called repeatidly to collect data, by calling
+    // service.execute()
+    update: function(service, callback) {
+        service.execute(function(serv, data) {
+            service.module.processResponse(serv, data);
+            callback();
+        });
+    },
 };
 
 module.exports = snmp;
index 3cd3cfab5e51a38c26c148dc20cc8aa360d7c6fd..90611905ceda43828ef218cf8134181811f054a8 100755 (executable)
@@ -9,66 +9,66 @@ CGROUP="${1}"
 NAME=
 
 if [ -z "${CGROUP}" ]
-       then
-       echo >&2 "${0}: called without a cgroup name. Nothing to do."
-       exit 1
+    then
+    echo >&2 "${0}: called without a cgroup name. Nothing to do."
+    exit 1
 fi
 
 if [ -f "${CONFIG}" ]
-       then
-       NAME="$(cat "${CONFIG}" | grep "^${CGROUP} " | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
-       if [ -z "${NAME}" ]
-               then
-               echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
-       fi
+    then
+    NAME="$(cat "${CONFIG}" | grep "^${CGROUP} " | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
+    if [ -z "${NAME}" ]
+        then
+        echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
+    fi
 #else
-#      echo >&2 "${0}: configuration file '${CONFIG}' is not available."
+#   echo >&2 "${0}: configuration file '${CONFIG}' is not available."
 fi
 
 function get_name_classic {
-       DOCKERID=$1
-       echo >&2 "Running command: docker ps --filter=id=\"${DOCKERID}\" --format=\"{{.Names}}\""
-       NAME="$( docker ps --filter=id="${DOCKERID}" --format="{{.Names}}" )"
+    DOCKERID=$1
+    echo >&2 "Running command: docker ps --filter=id=\"${DOCKERID}\" --format=\"{{.Names}}\""
+    NAME="$( docker ps --filter=id="${DOCKERID}" --format="{{.Names}}" )"
 }
 
 function get_name_api {
-       DOCKERID=$1
-       if [ ! -S "/var/run/docker.sock" ]
-               then
-               echo >&2 "Can't find /var/run/docker.sock"
-               return
-       fi
-       echo >&2 "Running API command: /containers/${DOCKERID}/json"
-       JSON=$(echo -e "GET /containers/${DOCKERID}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | egrep '^{.*')
-       NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
+    DOCKERID=$1
+    if [ ! -S "/var/run/docker.sock" ]
+        then
+        echo >&2 "Can't find /var/run/docker.sock"
+        return
+    fi
+    echo >&2 "Running API command: /containers/${DOCKERID}/json"
+    JSON=$(echo -e "GET /containers/${DOCKERID}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | egrep '^{.*')
+    NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
 }
 
 if [ -z "${NAME}" ]
-       then
-       if [[ "${CGROUP}" =~ ^.*docker[-/\.][a-fA-F0-9]+[-\.]?.*$ ]]
-               then
-               DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-/]\([a-fA-F0-9]\+\)[-\.]\?.*$|\1|" )"
+    then
+    if [[ "${CGROUP}" =~ ^.*docker[-/\.][a-fA-F0-9]+[-\.]?.*$ ]]
+        then
+        DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-/]\([a-fA-F0-9]\+\)[-\.]\?.*$|\1|" )"
 
-               if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
-                       then
-                       if hash docker 2>/dev/null
-                               then
-                               get_name_classic $DOCKERID
-                       else
-                               get_name_api $DOCKERID
-                       fi
-                       if [ -z "${NAME}" ]
-                               then
-                               echo >&2 "Cannot find the name of docker container '${DOCKERID}'"
-                               NAME="${DOCKERID:0:12}"
-                       else
-                               echo >&2 "Docker container '${DOCKERID}' is named '${NAME}'"
-                       fi
-               fi
-       fi
+        if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
+            then
+            if hash docker 2>/dev/null
+                then
+                get_name_classic $DOCKERID
+            else
+                get_name_api $DOCKERID
+            fi
+            if [ -z "${NAME}" ]
+                then
+                echo >&2 "Cannot find the name of docker container '${DOCKERID}'"
+                NAME="${DOCKERID:0:12}"
+            else
+                echo >&2 "Docker container '${DOCKERID}' is named '${NAME}'"
+            fi
+        fi
+    fi
 
-       [ -z "${NAME}" ] && NAME="${CGROUP}"
-       [ ${#NAME} -gt 50 ] && NAME="${NAME:0:50}"
+    [ -z "${NAME}" ] && NAME="${CGROUP}"
+    [ ${#NAME} -gt 50 ] && NAME="${NAME:0:50}"
 fi
 
 echo >&2 "${0}: cgroup '${CGROUP}' is called '${NAME}'"
index 9f024f6321ce4157750f12da632e3f4ae7a422b3..8142f9882b6aa79573d45eb744ba04496f9a0085 100755 (executable)
@@ -14,7 +14,7 @@ tmp1="`mktemp`"
 tmp2="`mktemp`"
 
 myset() {
-       set | grep -v "^_="     | grep -v "^PIPESTATUS=" | grep -v "^BASH_LINENO="
+    set | grep -v "^_=" | grep -v "^PIPESTATUS=" | grep -v "^BASH_LINENO="
 }
 
 # save 2 'set'
@@ -25,9 +25,9 @@ myset >"$tmp2"
 diff "$tmp1" "$tmp2" >/dev/null 2>&1
 if [ $? -ne 0 ]
 then
-       # they differ, we cannot do the check
-       echo >&2 "$me: cannot check with diff."
-       can_diff=0
+    # they differ, we cannot do the check
+    echo >&2 "$me: cannot check with diff."
+    can_diff=0
 fi
 
 # do it again, now including the script
@@ -36,21 +36,21 @@ myset >"$tmp1"
 # include the plugin and its config
 if [ -f "$conf" ]
 then
-       . "$conf"
-       if [ $? -ne 0 ]
-       then
-               echo >&2 "$me: cannot load config file $conf"
-               rm "$tmp1" "$tmp2"
-               exit 1
-       fi
+    . "$conf"
+    if [ $? -ne 0 ]
+    then
+        echo >&2 "$me: cannot load config file $conf"
+        rm "$tmp1" "$tmp2"
+        exit 1
+    fi
 fi
 
 . "$chart"
 if [ $? -ne 0 ]
 then
-       echo >&2 "$me: cannot load chart file $chart"
-       rm "$tmp1" "$tmp2"
-       exit 1
+    echo >&2 "$me: cannot load chart file $chart"
+    rm "$tmp1" "$tmp2"
+    exit 1
 fi
 
 # remove all variables starting with the plugin name
@@ -58,15 +58,15 @@ myset | grep -v "^$name" >"$tmp2"
 
 if [ $can_diff -eq 1 ]
 then
-       # check if they are different
-       # make sure they don't differ
-       diff "$tmp1" "$tmp2" >&2
-       if [ $? -ne 0 ]
-       then
-               # they differ
-               rm "$tmp1" "$tmp2"
-               exit 1
-       fi
+    # check if they are different
+    # make sure they don't differ
+    diff "$tmp1" "$tmp2" >&2
+    if [ $? -ne 0 ]
+    then
+        # they differ
+        rm "$tmp1" "$tmp2"
+        exit 1
+    fi
 fi
 
 rm "$tmp1" "$tmp2"
index 8721e4c333de3191a4f16c6f6fdc2c0cf76202c6..9aaadc168547e35d2a895436292da6746f13695a 100755 (executable)
@@ -14,24 +14,24 @@ echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
 
 if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
 then
-       echo >&2
-       echo >&2 "$PROGRAM_NAME: ERROR"
-       echo >&2 "BASH version 4 or later is required."
-       echo >&2 "You are running version: ${BASH_VERSION}"
-       echo >&2 "Please upgrade."
-       echo >&2
-       exit 1
+    echo >&2
+    echo >&2 "$PROGRAM_NAME: ERROR"
+    echo >&2 "BASH version 4 or later is required."
+    echo >&2 "You are running version: ${BASH_VERSION}"
+    echo >&2 "Please upgrade."
+    echo >&2
+    exit 1
 fi
 
 # check a few commands
 require_cmd() {
-       which "$1" >/dev/null
-       if [ $? -ne 0 ]
-               then
-               echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
-               return 1
-       fi
-       return 0
+    which "$1" >/dev/null
+    if [ $? -ne 0 ]
+        then
+        echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
+        return 1
+    fi
+    return 0
 }
 
 require_cmd date || exit 1
@@ -61,7 +61,7 @@ chartsd="$pluginsd/../charts.d"
 myconfig="$confd/$PROGRAM_NAME.conf"
 
 minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
-update_every=${minimum_update_frequency}       # this will be overwritten by the command line
+update_every=${minimum_update_frequency}    # this will be overwritten by the command line
 
 # work around for non BASH shells
 charts_create="_create"
@@ -106,50 +106,50 @@ check=0
 chart_only=
 while [ ! -z "$1" ]
 do
-       if [ "$1" = "check" ]
-       then
-               check=1
-               shift
-               continue
-       fi
-
-       if [ "$1" = "debug" -o "$1" = "all" ]
-       then
-               debug=1
-               shift
-               continue
-       fi
-
-       if [ -f "$chartsd/$1.chart.sh" ]
-       then
-               debug=1
-               chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
-               shift
-               continue
-       fi
-
-       if [ -f "$chartsd/$1" ]
-       then
-               debug=1
-               chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
-               shift
-               continue
-       fi
-
-       # number check
-       n="$1"
-       x=$(( n ))
-       if [ "$x" = "$n" ]
-       then
-               shift
-               update_every=$x
-               [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
-               continue
-       fi
-
-       echo >&2 "Cannot understand parameter $1. Aborting."
-       echo "DISABLE"
-       exit 1
+    if [ "$1" = "check" ]
+    then
+        check=1
+        shift
+        continue
+    fi
+
+    if [ "$1" = "debug" -o "$1" = "all" ]
+    then
+        debug=1
+        shift
+        continue
+    fi
+
+    if [ -f "$chartsd/$1.chart.sh" ]
+    then
+        debug=1
+        chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
+        shift
+        continue
+    fi
+
+    if [ -f "$chartsd/$1" ]
+    then
+        debug=1
+        chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
+        shift
+        continue
+    fi
+
+    # number check
+    n="$1"
+    x=$(( n ))
+    if [ "$x" = "$n" ]
+    then
+        shift
+        update_every=$x
+        [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
+        continue
+    fi
+
+    echo >&2 "Cannot understand parameter $1. Aborting."
+    echo "DISABLE"
+    exit 1
 done
 
 
@@ -157,26 +157,26 @@ done
 # load my configuration
 
 if [ -f "$myconfig" ]
-       then
-       . "$myconfig"
-       if [ $? -ne 0 ]
-       then
-               echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
-               echo "DISABLE"
-               exit 1
-       fi
-       time_divisor=$((time_divisor))
-       [ $time_divisor -lt 10 ] && time_divisor=10
-       [ $time_divisor -gt 100 ] && time_divisor=100
+    then
+    . "$myconfig"
+    if [ $? -ne 0 ]
+    then
+        echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
+        echo "DISABLE"
+        exit 1
+    fi
+    time_divisor=$((time_divisor))
+    [ $time_divisor -lt 10 ] && time_divisor=10
+    [ $time_divisor -gt 100 ] && time_divisor=100
 else
-       echo >&2 "$PROGRAM_NAME: configuration file '$myconfig' not found. Using defaults."
+    echo >&2 "$PROGRAM_NAME: configuration file '$myconfig' not found. Using defaults."
 fi
 
 if [ "$pause_method" = "suspend" ]
 then
-       # enable bash job control
-       # this is required for suspend to work
-       set -m
+    # enable bash job control
+    # this is required for suspend to work
+    set -m
 fi
 
 # we check for the timeout command, after we load our
@@ -185,22 +185,22 @@ fi
 # can emulate the timeout command we need:
 # > timeout SECONDS command ...
 if [ $check_for_timeout -eq 1 ]
-       then
-       require_cmd timeout || exit 1
+    then
+    require_cmd timeout || exit 1
 fi
 
 # -----------------------------------------------------------------------------
 # internal checks
 
 # netdata passes the requested update frequency as the first argument
-update_every=$(( update_every + 1 - 1))        # makes sure it is a number
+update_every=$(( update_every + 1 - 1)) # makes sure it is a number
 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
 
 # check the charts.d directory
 if [ ! -d "$chartsd" ]
-       then
-       echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
-       echo "DISABLE"
+    then
+    echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
+    echo "DISABLE"
 fi
 
 
@@ -210,13 +210,13 @@ fi
 # default sleep function
 LOOPSLEEPMS_HIGHRES=0
 loopsleepms() {
-       [ "$1" = "tellwork" ] && shift
-       sleep $1
+    [ "$1" = "tellwork" ] && shift
+    sleep $1
 }
 
 now_ms=
 current_time_ms() {
-       now_ms="$(date +'%s')000"
+    now_ms="$(date +'%s')000"
 }
 
 # if found and included, this file overwrites loopsleepms()
@@ -229,10 +229,10 @@ current_time_ms() {
 # library functions
 
 fixid() {
-       echo "$*" |\
-               tr -c "[A-Z][a-z][0-9]" "_" |\
-               sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
-               tr "[A-Z]" "[a-z]"
+    echo "$*" |\
+        tr -c "[A-Z][a-z][0-9]" "_" |\
+        sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
+        tr "[A-Z]" "[a-z]"
 }
 
 # convert any floating point number
@@ -241,57 +241,57 @@ fixid() {
 # so that no fork is necessary
 # the multiplier must be a power of 10
 float2int() {
-       local f m="$2" a b l v=($1)
-       f=${v[0]}
-
-       # echo >&2 "value='${1}' f='${f}', m='${m}'"
-
-       # the length of the multiplier - 1
-       l=$(( ${#m} - 1 ))
-
-       # check if the number is in scientific notation
-       if [[ ${f} =~ ^[[:space:]]*(-)?[0-9.]+(e|E)(\+|-)[0-9]+ ]]
-               then
-               # convert it to decimal
-               # unfortunately, this fork cannot be avoided
-               # if you know of a way to avoid it, please let me know
-               f=$(printf "%0.${l}f" ${f})
-       fi
-
-       # split the floating point number
-       # in integer (a) and decimal (b)
-       a=${f/.*/}
-       b=${f/*./}
-
-       # if the integer part is missing
-       # set it to zero
-       [ -z "${a}" ] && a="0"
-
-       # strip leading zeros from the integer part
-       # base 10 convertion
-       a=$((10#$a))
-
-       # check the length of the decimal part
-       # against the length of the multiplier
-       if [ ${#b} -gt ${l} ]
-               then
-               # too many digits - take the most significant
-               b=${b:0:${l}}
-
-       elif [ ${#b} -lt ${l} ]
-               then
-               # too few digits - pad with zero on the right
-               local z="00000000000000000000000" r=$((l - ${#b}))
-               b="${b}${z:0:${r}}"
-       fi
-
-       # strip leading zeros from the decimal part
-       # base 10 convertion
-       b=$((10#$b))
-
-       # store the result
-       FLOAT2INT_RESULT=$(( (a * m) + b ))
-       #echo >&2 "FLOAT2INT_RESULT='${FLOAT2INT_RESULT}'"
+    local f m="$2" a b l v=($1)
+    f=${v[0]}
+
+    # echo >&2 "value='${1}' f='${f}', m='${m}'"
+
+    # the length of the multiplier - 1
+    l=$(( ${#m} - 1 ))
+
+    # check if the number is in scientific notation
+    if [[ ${f} =~ ^[[:space:]]*(-)?[0-9.]+(e|E)(\+|-)[0-9]+ ]]
+        then
+        # convert it to decimal
+        # unfortunately, this fork cannot be avoided
+        # if you know of a way to avoid it, please let me know
+        f=$(printf "%0.${l}f" ${f})
+    fi
+
+    # split the floating point number
+    # in integer (a) and decimal (b)
+    a=${f/.*/}
+    b=${f/*./}
+
+    # if the integer part is missing
+    # set it to zero
+    [ -z "${a}" ] && a="0"
+
+    # strip leading zeros from the integer part
+    # base 10 convertion
+    a=$((10#$a))
+
+    # check the length of the decimal part
+    # against the length of the multiplier
+    if [ ${#b} -gt ${l} ]
+        then
+        # too many digits - take the most significant
+        b=${b:0:${l}}
+
+    elif [ ${#b} -lt ${l} ]
+        then
+        # too few digits - pad with zero on the right
+        local z="00000000000000000000000" r=$((l - ${#b}))
+        b="${b}${z:0:${r}}"
+    fi
+
+    # strip leading zeros from the decimal part
+    # base 10 convertion
+    b=$((10#$b))
+
+    # store the result
+    FLOAT2INT_RESULT=$(( (a * m) + b ))
+    #echo >&2 "FLOAT2INT_RESULT='${FLOAT2INT_RESULT}'"
 }
 
 
@@ -299,105 +299,105 @@ float2int() {
 # charts check functions
 
 all_charts() {
-       cd "$chartsd"
-       [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
+    cd "$chartsd"
+    [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
 
-       ls *.chart.sh | sed "s/\.chart\.sh$//g"
+    ls *.chart.sh | sed "s/\.chart\.sh$//g"
 }
 
 declare -A charts_enable_keyword=(
-             ['apache']="force"
-           ['cpu_apps']="force"
-            ['cpufreq']="force"
-            ['example']="force"
-               ['exim']="force"
-            ['hddtemp']="force"
-       ['load_average']="force"
-           ['mem_apps']="force"
-              ['mysql']="force"
-              ['nginx']="force"
-             ['phpfpm']="force"
-            ['postfix']="force"
-            ['sensors']="force"
-              ['squid']="force"
-             ['tomcat']="force"
-       )
+          ['apache']="force"
+        ['cpu_apps']="force"
+         ['cpufreq']="force"
+         ['example']="force"
+            ['exim']="force"
+         ['hddtemp']="force"
+    ['load_average']="force"
+        ['mem_apps']="force"
+           ['mysql']="force"
+           ['nginx']="force"
+          ['phpfpm']="force"
+         ['postfix']="force"
+         ['sensors']="force"
+           ['squid']="force"
+          ['tomcat']="force"
+    )
 
 all_enabled_charts() {
-       local charts= enabled= required=
-
-       # find all enabled charts
-
-       for chart in $( all_charts )
-       do
-               eval "enabled=\$$chart"
-               if [ -z "${enabled}" ]
-                       then
-                       enabled="${enable_all_charts}"
-               fi
-
-               required="${charts_enable_keyword[${chart}]}"
-               [ -z "${required}" ] && required="yes"
-
-               if [ ! "${enabled}" = "${required}" ]
-               then
-                       echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=$required in $myconfig to enable it (or remove the line that disables it)."
-               else
-                       [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
-                       local charts="$charts $chart"
-               fi
-       done
-
-       local charts2=
-       for chart in $charts
-       do
-               # check the enabled charts
-               local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
-               if [ -z "$check" ]
-               then
-                       echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
-                       continue
-               fi
-
-               local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
-               if [ -z "$create" ]
-               then
-                       echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
-                       continue
-               fi
-
-               local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
-               if [ -z "$update" ]
-               then
-                       echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
-                       continue
-               fi
-
-               # check its config
-               #if [ -f "$confd/$chart.conf" ]
-               #then
-               #       if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
-               #       then
-               #               echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
-               #               continue
-               #       fi
-               #fi
-
-               #if [ $dryrunner -eq 1 ]
-               #       then
-               #       "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
-               #       if [ $? -ne 0 ]
-               #       then
-               #               echo >&2 "$PROGRAM_NAME: chart's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
-               #               continue
-               #       fi
-               #fi
-
-               local charts2="$charts2 $chart"
-       done
-
-       echo $charts2
-       [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
+    local charts= enabled= required=
+
+    # find all enabled charts
+
+    for chart in $( all_charts )
+    do
+        eval "enabled=\$$chart"
+        if [ -z "${enabled}" ]
+            then
+            enabled="${enable_all_charts}"
+        fi
+
+        required="${charts_enable_keyword[${chart}]}"
+        [ -z "${required}" ] && required="yes"
+
+        if [ ! "${enabled}" = "${required}" ]
+        then
+            echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=$required in $myconfig to enable it (or remove the line that disables it)."
+        else
+            [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
+            local charts="$charts $chart"
+        fi
+    done
+
+    local charts2=
+    for chart in $charts
+    do
+        # check the enabled charts
+        local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
+        if [ -z "$check" ]
+        then
+            echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
+            continue
+        fi
+
+        local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
+        if [ -z "$create" ]
+        then
+            echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
+            continue
+        fi
+
+        local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
+        if [ -z "$update" ]
+        then
+            echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
+            continue
+        fi
+
+        # check its config
+        #if [ -f "$confd/$chart.conf" ]
+        #then
+        #   if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
+        #   then
+        #       echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
+        #       continue
+        #   fi
+        #fi
+
+        #if [ $dryrunner -eq 1 ]
+        #   then
+        #   "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
+        #   if [ $? -ne 0 ]
+        #   then
+        #       echo >&2 "$PROGRAM_NAME: chart's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
+        #       continue
+        #   fi
+        #fi
+
+        local charts2="$charts2 $chart"
+    done
+
+    echo $charts2
+    [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
 }
 
 
@@ -408,36 +408,36 @@ suffix_update_every="_update_every"
 active_charts=
 for chart in $( all_enabled_charts )
 do
-       [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
-       . "$chartsd/$chart.chart.sh"
-
-       if [ -f "$confd/charts.d/$chart.conf" ]
-       then
-               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/charts.d/$chart.conf'"
-               . "$confd/charts.d/$chart.conf"
-       elif [ -f "$confd/$chart.conf" ]
-       then
-               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
-               . "$confd/$chart.conf"
-       else
-               echo >&2 "$PROGRAM_NAME: $chart: configuration file '$confd/charts.d/$chart.conf' not found. Using defaults."
-       fi
-
-       eval "dt=\$$chart$suffix_update_every"
-       dt=$(( dt + 1 - 1 )) # make sure it is a number
-       if [ $dt -lt $update_every ]
-       then
-               eval "$chart$suffix_update_every=$update_every"
-       fi
-
-       $chart$charts_check
-       if [ $? -eq 0 ]
-       then
-               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
-               active_charts="$active_charts $chart"
-       else
-               echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
-       fi
+    [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
+    . "$chartsd/$chart.chart.sh"
+
+    if [ -f "$confd/charts.d/$chart.conf" ]
+    then
+        [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/charts.d/$chart.conf'"
+        . "$confd/charts.d/$chart.conf"
+    elif [ -f "$confd/$chart.conf" ]
+    then
+        [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
+        . "$confd/$chart.conf"
+    else
+        echo >&2 "$PROGRAM_NAME: $chart: configuration file '$confd/charts.d/$chart.conf' not found. Using defaults."
+    fi
+
+    eval "dt=\$$chart$suffix_update_every"
+    dt=$(( dt + 1 - 1 )) # make sure it is a number
+    if [ $dt -lt $update_every ]
+    then
+        eval "$chart$suffix_update_every=$update_every"
+    fi
+
+    $chart$charts_check
+    if [ $? -eq 0 ]
+    then
+        [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
+        active_charts="$active_charts $chart"
+    else
+        echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
+    fi
 done
 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
 
@@ -452,26 +452,26 @@ test $debug -eq 1 && debug_time=tellwork
 # if we only need a specific chart, remove all the others
 if [ ! -z "${chart_only}" ]
 then
-       [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
-       check_charts=
-       for chart in $active_charts
-       do
-               if [ "$chart" = "$chart_only" ]
-               then
-                       check_charts="$chart"
-                       break
-               fi
-       done
-       active_charts="$check_charts"
+    [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
+    check_charts=
+    for chart in $active_charts
+    do
+        if [ "$chart" = "$chart_only" ]
+        then
+            check_charts="$chart"
+            break
+        fi
+    done
+    active_charts="$check_charts"
 fi
 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
 
 # stop if we just need a pre-check
 if [ $check -eq 1 ]
 then
-       echo >&2 "CHECK RESULT"
-       echo >&2 "Will run the charts: $active_charts"
-       exit 0
+    echo >&2 "CHECK RESULT"
+    echo >&2 "Will run the charts: $active_charts"
+    exit 0
 fi
 
 # -----------------------------------------------------------------------------
@@ -479,13 +479,13 @@ fi
 
 TMP_DIR=
 chartsd_cleanup() {
-       cd /tmp
-       if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
-       then
-               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
-               rm -rf "$TMP_DIR"
-       fi
-       exit 0
+    cd /tmp
+    if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
+    then
+        [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
+        rm -rf "$TMP_DIR"
+    fi
+    exit 0
 }
 trap chartsd_cleanup EXIT
 trap chartsd_cleanup SIGHUP
@@ -493,9 +493,9 @@ trap chartsd_cleanup INT
 
 if [ $UID = "0" ]
 then
-       TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
+    TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
 else
-       TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
+    TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
 fi
 
 cd "$TMP_DIR" || exit 1
@@ -506,15 +506,15 @@ cd "$TMP_DIR" || exit 1
 run_charts=
 for chart in $active_charts
 do
-       [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
-       $chart$charts_create
-       if [ $? -eq 0 ]
-       then
-               run_charts="$run_charts $chart"
-               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
-       else
-               echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
-       fi
+    [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
+    $chart$charts_create
+    if [ $? -eq 0 ]
+    then
+        run_charts="$run_charts $chart"
+        [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
+    else
+        echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
+    fi
 done
 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
 
@@ -523,131 +523,131 @@ done
 # update dimensions
 
 if [ -z "$run_charts" ]
-       then
-       echo >&2 "$PROGRAM_NAME: No charts to collect data from."
-       echo "DISABLE"
-       exit 1
+    then
+    echo >&2 "$PROGRAM_NAME: No charts to collect data from."
+    echo "DISABLE"
+    exit 1
 fi
 
 declare -A charts_last_update=() charts_update_every=() charts_next_update=() charts_run_counter=() charts_serial_failures=()
 global_update() {
-       local exit_at \
-               c=0 dt ret last_ms exec_start_ms exec_end_ms \
-               chart now_charts=() next_charts=($run_charts) \
-               next_ms x seconds millis
-
-       # return the current time in ms in $now_ms
-       current_time_ms
-
-       exit_at=$(( now_ms + (restart_timeout * 1000) ))
-
-       for chart in $run_charts
-       do
-               eval "charts_update_every[$chart]=\$$chart$suffix_update_every"
-               test -z "${charts_update_every[$chart]}" && charts_update_every[$charts]=$update_every
-               charts_last_update[$chart]=$((now_ms - (now_ms % (charts_update_every[$chart] * 1000) ) ))
-               charts_next_update[$chart]=$(( charts_last_update[$chart] + (charts_update_every[$chart] * 1000) ))
-               charts_run_counter[$chart]=0
-               charts_serial_failures[$chart]=0
-
-               echo "CHART netdata.plugin_chartsd_$chart '' 'Execution time for $chart plugin' 'milliseconds / run' charts.d netdata.plugin_charts area 145000 ${charts_update_every[$chart]}"
-               echo "DIMENSION run_time 'run time' absolute 1 1"
-       done
-
-       # the main loop
-       while [ "${#next_charts[@]}" -gt 0 ]
-       do
-               c=$((c + 1))
-               now_charts=("${next_charts[@]}")
-               next_charts=()
-
-               # return the current time in ms in $now_ms
-               current_time_ms
-
-               for chart in "${now_charts[@]}"
-               do
-                       # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}"
-                       if [ ${now_ms} -ge ${charts_next_update[$chart]} ]
-                       then
-                               last_ms=${charts_last_update[$chart]}
-                               dt=$(( (now_ms - last_ms) ))
-                               # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}, dt: ${dt}"
-
-                               charts_last_update[$chart]=${now_ms}
-
-                               while [ ${charts_next_update[$chart]} -lt ${now_ms} ]
-                               do
-                                       charts_next_update[$chart]=$(( charts_next_update[$chart] + (charts_update_every[$chart] * 1000) ))
-                               done
-
-                               # the first call should not give a duration
-                               # so that netdata calibrates to current time
-                               dt=$(( dt * 1000 ))
-                               charts_run_counter[$chart]=$(( charts_run_counter[$chart] + 1 ))
-                               if [ ${charts_run_counter[$chart]} -eq 1 ]
-                                       then
-                                       dt=
-                               fi
-
-                               exec_start_ms=$now_ms
-                               $chart$charts_update $dt
-                               ret=$?
-
-                               # return the current time in ms in $now_ms
-                               current_time_ms; exec_end_ms=$now_ms
-
-                               echo "BEGIN netdata.plugin_chartsd_$chart $dt"
-                               echo "SET run_time = $(( exec_end_ms - exec_start_ms ))"
-                               echo "END"
-
-                               if [ $ret -eq 0 ]
-                               then
-                                       charts_serial_failures[$chart]=0
-                                       next_charts+=($chart)
-                               else
-                                       charts_serial_failures[$chart]=$(( charts_serial_failures[$chart] + 1 ))
-
-                                       if [ ${charts_serial_failures[$chart]} -gt 10 ]
-                                               then
-                                               echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reported failure ${charts_serial_failures[$chart]} times. Disabling it."
-                                       else
-                                               echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Will keep trying for a while."
-                                               next_charts+=($chart)
-                                       fi
-                               fi
-                       else
-                               next_charts+=($chart)
-                       fi
-               done
-
-               if [ "$pause_method" = "suspend" ]
-               then
-                       echo "STOPPING_WAKE_ME_UP_PLEASE"
-                       suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every $time_divisor)
-               else
-                       # wait the time you are required to
-                       next_ms=$((now_ms + (update_every * 1000 * 100) ))
-                       for x in "${charts_next_update[@]}"; do [ ${x} -lt ${next_ms} ] && next_ms=${x}; done
-                       next_ms=$((next_ms - now_ms))
-
-                       if [ ${LOOPSLEEPMS_HIGHRES} -eq 1 -a ${next_ms} -gt 0 ]
-                               then
-                               seconds=$(( next_ms / 1000 ))
-                               millis=$(( next_ms % 1000 ))
-                               [ ${millis} -lt 10  ] && millis="0${millis}"
-                               [ ${millis} -lt 100 ] && millis="0${millis}"
-                               [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: sleeping for ${seconds}.${millis} seconds."
-                               sleep ${seconds}.${millis}
-                       else
-                               sleep $update_every
-                       fi
-               fi
-
-               test ${now_ms} -ge ${exit_at} && exit 0
-       done
-
-       echo >&2 "$PROGRAM_NAME: Nothing left to do. Disabling charts.d.plugin."
-       echo "DISABLE"
+    local exit_at \
+        c=0 dt ret last_ms exec_start_ms exec_end_ms \
+        chart now_charts=() next_charts=($run_charts) \
+        next_ms x seconds millis
+
+    # return the current time in ms in $now_ms
+    current_time_ms
+
+    exit_at=$(( now_ms + (restart_timeout * 1000) ))
+
+    for chart in $run_charts
+    do
+        eval "charts_update_every[$chart]=\$$chart$suffix_update_every"
+        test -z "${charts_update_every[$chart]}" && charts_update_every[$charts]=$update_every
+        charts_last_update[$chart]=$((now_ms - (now_ms % (charts_update_every[$chart] * 1000) ) ))
+        charts_next_update[$chart]=$(( charts_last_update[$chart] + (charts_update_every[$chart] * 1000) ))
+        charts_run_counter[$chart]=0
+        charts_serial_failures[$chart]=0
+
+        echo "CHART netdata.plugin_chartsd_$chart '' 'Execution time for $chart plugin' 'milliseconds / run' charts.d netdata.plugin_charts area 145000 ${charts_update_every[$chart]}"
+        echo "DIMENSION run_time 'run time' absolute 1 1"
+    done
+
+    # the main loop
+    while [ "${#next_charts[@]}" -gt 0 ]
+    do
+        c=$((c + 1))
+        now_charts=("${next_charts[@]}")
+        next_charts=()
+
+        # return the current time in ms in $now_ms
+        current_time_ms
+
+        for chart in "${now_charts[@]}"
+        do
+            # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}"
+            if [ ${now_ms} -ge ${charts_next_update[$chart]} ]
+            then
+                last_ms=${charts_last_update[$chart]}
+                dt=$(( (now_ms - last_ms) ))
+                # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}, dt: ${dt}"
+
+                charts_last_update[$chart]=${now_ms}
+
+                while [ ${charts_next_update[$chart]} -lt ${now_ms} ]
+                do
+                    charts_next_update[$chart]=$(( charts_next_update[$chart] + (charts_update_every[$chart] * 1000) ))
+                done
+
+                # the first call should not give a duration
+                # so that netdata calibrates to current time
+                dt=$(( dt * 1000 ))
+                charts_run_counter[$chart]=$(( charts_run_counter[$chart] + 1 ))
+                if [ ${charts_run_counter[$chart]} -eq 1 ]
+                    then
+                    dt=
+                fi
+
+                exec_start_ms=$now_ms
+                $chart$charts_update $dt
+                ret=$?
+
+                # return the current time in ms in $now_ms
+                current_time_ms; exec_end_ms=$now_ms
+
+                echo "BEGIN netdata.plugin_chartsd_$chart $dt"
+                echo "SET run_time = $(( exec_end_ms - exec_start_ms ))"
+                echo "END"
+
+                if [ $ret -eq 0 ]
+                then
+                    charts_serial_failures[$chart]=0
+                    next_charts+=($chart)
+                else
+                    charts_serial_failures[$chart]=$(( charts_serial_failures[$chart] + 1 ))
+
+                    if [ ${charts_serial_failures[$chart]} -gt 10 ]
+                        then
+                        echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reported failure ${charts_serial_failures[$chart]} times. Disabling it."
+                    else
+                        echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Will keep trying for a while."
+                        next_charts+=($chart)
+                    fi
+                fi
+            else
+                next_charts+=($chart)
+            fi
+        done
+
+        if [ "$pause_method" = "suspend" ]
+        then
+            echo "STOPPING_WAKE_ME_UP_PLEASE"
+            suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every $time_divisor)
+        else
+            # wait the time you are required to
+            next_ms=$((now_ms + (update_every * 1000 * 100) ))
+            for x in "${charts_next_update[@]}"; do [ ${x} -lt ${next_ms} ] && next_ms=${x}; done
+            next_ms=$((next_ms - now_ms))
+
+            if [ ${LOOPSLEEPMS_HIGHRES} -eq 1 -a ${next_ms} -gt 0 ]
+                then
+                seconds=$(( next_ms / 1000 ))
+                millis=$(( next_ms % 1000 ))
+                [ ${millis} -lt 10  ] && millis="0${millis}"
+                [ ${millis} -lt 100 ] && millis="0${millis}"
+                [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: sleeping for ${seconds}.${millis} seconds."
+                sleep ${seconds}.${millis}
+            else
+                sleep $update_every
+            fi
+        fi
+
+        test ${now_ms} -ge ${exit_at} && exit 0
+    done
+
+    echo >&2 "$PROGRAM_NAME: Nothing left to do. Disabling charts.d.plugin."
+    echo "DISABLE"
 }
 
 global_update
index e98584e5d852d3643e5df7fbc3c4183f68bf5582..02ab694d26dd53af3a2981a9fc5a3c929201edd6 100644 (file)
@@ -7,9 +7,9 @@
 
 LOOPSLEEP_DATE="$(which date)"
 if [ -z "$LOOPSLEEP_DATE" ]
-       then
-       echo >&2 "$0: ERROR: Cannot find the command 'date' in the system path."
-       exit 1
+    then
+    echo >&2 "$0: ERROR: Cannot find the command 'date' in the system path."
+    exit 1
 fi
 
 LOOPSLEEPMS_LASTRUN=0
@@ -21,70 +21,70 @@ test "$($LOOPSLEEP_DATE +%N)" = "%N" && LOOPSLEEPMS_HIGHRES=0
 
 now_ms=
 current_time_ms() {
-       # if high resolution is not supported
-       # just sleep the time requested, in seconds
-       if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
-       then
-               now_ms="$($LOOPSLEEP_DATE +'%s')000"
-       else
-               now_ms="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
-       fi
+    # if high resolution is not supported
+    # just sleep the time requested, in seconds
+    if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
+    then
+        now_ms="$($LOOPSLEEP_DATE +'%s')000"
+    else
+        now_ms="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
+    fi
 }
 
 loopsleepms() {
-       local tellwork=0 t="$1" div s m now mstosleep
+    local tellwork=0 t="$1" div s m now mstosleep
 
-       if [ "$t" = "tellwork" ]
-       then
-               tellwork=1
-               shift
-               t="$1"
-       fi
-       div="${2-100}"
+    if [ "$t" = "tellwork" ]
+    then
+        tellwork=1
+        shift
+        t="$1"
+    fi
+    div="${2-100}"
 
-       # $t = the time in seconds to wait
+    # $t = the time in seconds to wait
 
-       # if high resolution is not supported
-       # just sleep the time requested, in seconds
-       if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
-       then
-               sleep $t
-               return
-       fi
+    # if high resolution is not supported
+    # just sleep the time requested, in seconds
+    if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
+    then
+        sleep $t
+        return
+    fi
 
-       # get the current time, in ms
-       # milliseconds since epoch (1-1-1970)
-       now="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
+    # get the current time, in ms
+    # milliseconds since epoch (1-1-1970)
+    now="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
 
-       # calculate required sleep in ms
-       t=$((t * 1000 * div / 100))
+    # calculate required sleep in ms
+    t=$((t * 1000 * div / 100))
 
-       # this is our first run
-       # just wait the requested time
-       test $LOOPSLEEPMS_LASTRUN -eq 0 && LOOPSLEEPMS_LASTRUN=$now
+    # this is our first run
+    # just wait the requested time
+    test $LOOPSLEEPMS_LASTRUN -eq 0 && LOOPSLEEPMS_LASTRUN=$now
 
-       # calculate ms since last run
-       LOOPSLEEPMS_LASTWORK=$((now - LOOPSLEEPMS_LASTRUN - LOOPSLEEPMS_LASTSLEEP))
-       # echo "# last loop's work took $LOOPSLEEPMS_LASTWORK ms"
+    # calculate ms since last run
+    LOOPSLEEPMS_LASTWORK=$((now - LOOPSLEEPMS_LASTRUN - LOOPSLEEPMS_LASTSLEEP))
+    # echo "# last loop's work took $LOOPSLEEPMS_LASTWORK ms"
 
-       # calculate ms to sleep
-       mstosleep=$(( t - LOOPSLEEPMS_LASTWORK ))
-       # echo "# mstosleep is $mstosleep ms"
+    # calculate ms to sleep
+    mstosleep=$(( t - LOOPSLEEPMS_LASTWORK ))
+    # echo "# mstosleep is $mstosleep ms"
 
-       # if we are too slow, sleep some time
-       test $mstosleep -lt 200 && mstosleep=200
+    # if we are too slow, sleep some time
+    test $mstosleep -lt 200 && mstosleep=200
 
-       s=$((mstosleep / 1000))
-       m=$((mstosleep - (s * 1000)))
+    s=$((mstosleep / 1000))
+    m=$((mstosleep - (s * 1000)))
 
-       test $tellwork -eq 1 && echo >&2 " >>> PERFORMANCE >>> WORK TOOK $LOOPSLEEPMS_LASTWORK ms ( $((LOOPSLEEPMS_LASTWORK * 100 / 1000)).$((LOOPSLEEPMS_LASTWORK % 10))% cpu ) >>> SLEEPING $mstosleep ms"
+    test $tellwork -eq 1 && echo >&2 " >>> PERFORMANCE >>> WORK TOOK $LOOPSLEEPMS_LASTWORK ms ( $((LOOPSLEEPMS_LASTWORK * 100 / 1000)).$((LOOPSLEEPMS_LASTWORK % 10))% cpu ) >>> SLEEPING $mstosleep ms"
 
-       # echo "# sleeping $s.$m"
-       # echo
-       sleep $s.$m
+    # echo "# sleeping $s.$m"
+    # echo
+    sleep $s.$m
 
-       # keep the values we need
-       # for our next run
-       LOOPSLEEPMS_LASTRUN=$now
-       LOOPSLEEPMS_LASTSLEEP=$mstosleep
+    # keep the values we need
+    # for our next run
+    LOOPSLEEPMS_LASTRUN=$now
+    LOOPSLEEPMS_LASTSLEEP=$mstosleep
 }
index 270351e4e5582cada1876edd54eb71d481d0c71b..21b04384e8ca87607e36cd747e9966d59351c3fa 100755 (executable)
@@ -40,60 +40,60 @@ var netdata = require('netdata');
 // configuration
 
 function pluginConfig(filename) {
-       var f = path.basename(filename);
+    var f = path.basename(filename);
 
-       // node.d.plugin configuration
-       var m = f.match('.plugin' + '$');
-       if(m !== null)
-               return netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
+    // node.d.plugin configuration
+    var m = f.match('.plugin' + '$');
+    if(m !== null)
+        return netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
 
-       // node.d modules configuration
-       m = f.match('.node.js' + '$');
-       if(m !== null)
-               return netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
+    // node.d modules configuration
+    m = f.match('.node.js' + '$');
+    if(m !== null)
+        return netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
 
-       return netdata.options.paths.config + '/node.d/' + f + '.conf';
+    return netdata.options.paths.config + '/node.d/' + f + '.conf';
 }
 
 // internal defaults
 extend(true, netdata.options, {
-       filename: path.basename(__filename),
+    filename: path.basename(__filename),
 
-       update_every: NETDATA_UPDATE_EVERY,
+    update_every: NETDATA_UPDATE_EVERY,
 
-       exit_after_ms: 3600 * 4 * 1000,
+    exit_after_ms: 3600 * 4 * 1000,
 
-       paths: {
-               plugins: NETDATA_PLUGINS_DIR,
-               config: NETDATA_CONFIG_DIR,
-               modules: [],
-       },
+    paths: {
+        plugins: NETDATA_PLUGINS_DIR,
+        config: NETDATA_CONFIG_DIR,
+        modules: [],
+    },
 
-       modules_enable_autodetect: true,
-       modules_enable_all: true,
-       modules: {},
+    modules_enable_autodetect: true,
+    modules_enable_all: true,
+    modules: {},
 });
 netdata.options.config_filename = pluginConfig(__filename);
 
 // load configuration file
 try {
-       netdata.options_loaded = JSON.parse(fs.readFileSync(netdata.options.config_filename, 'utf8'));
-       extend(true, netdata.options, netdata.options_loaded);
-       console.error('merged netdata object:');
-       console.error(netdata);
+    netdata.options_loaded = JSON.parse(fs.readFileSync(netdata.options.config_filename, 'utf8'));
+    extend(true, netdata.options, netdata.options_loaded);
+    console.error('merged netdata object:');
+    console.error(netdata);
 }
 catch(e) {
-       netdata.error('Cannot read configuration file ' + netdata.options.config_filename + ': ' + e.message + ', using internal defaults.');
-       netdata.options_loaded = undefined;
-       dumpError(e);
+    netdata.error('Cannot read configuration file ' + netdata.options.config_filename + ': ' + e.message + ', using internal defaults.');
+    netdata.options_loaded = undefined;
+    dumpError(e);
 }
 
 
 // apply module paths to node.js process
 function applyModulePaths() {
-       var len = netdata.options.paths.modules.length;
-       while(len--)
-               process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
+    var len = netdata.options.paths.modules.length;
+    while(len--)
+        process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
 }
 applyModulePaths();
 
@@ -102,165 +102,165 @@ applyModulePaths();
 // tracing
 
 function dumpError(err) {
-       if (typeof err === 'object') {
-               if (err.stack) {
-                       netdata.debug(err.stack);
-               }
-       }
+    if (typeof err === 'object') {
+        if (err.stack) {
+            netdata.debug(err.stack);
+        }
+    }
 }
 
 // --------------------------------------------------------------------------------------------------------------------
 // get command line arguments
 {
-       var found_myself = false;
-       var found_number = false;
-       var found_modules = false;
-       process.argv.forEach(function (val, index, array) {
-               netdata.debug('PARAM: ' + val);
-
-               if(!found_myself) {
-                       if(val === __filename)
-                               found_myself = true;
-               }
-               else {
-                       switch(val) {
-                               case 'debug':
-                                       netdata.options.DEBUG = true;
-                                       netdata.debug('DEBUG enabled');
-                                       break;
-
-                               default:
-                                       if(found_number === true) {
-                                               if(found_modules === false) {
-                                                       for(var i in netdata.options.modules)
-                                                               netdata.options.modules[i].enabled = false;
-                                               }
-
-                                               if(typeof netdata.options.modules[val] === 'undefined')
-                                                       netdata.options.modules[val] = {};
-
-                                               netdata.options.modules[val].enabled = true;
-                                               netdata.options.modules_enable_all = false;
-                                               netdata.debug('enabled module ' + val);
-                                       }
-                                       else {
-                                               try {
-                                                       var x = parseInt(val);
-                                                       if(x > 0) {
-                                                               netdata.options.update_every = x;
-                                                               if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
-                                                                       netdata.options.update_every = NETDATA_UPDATE_EVERY;
-                                                                       netdata.debug('Update frequency ' + x + 's is too low');
-                                                               }
-
-                                                               found_number = true;
-                                                               netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
-                                                       }
-                                                       else netdata.error('Ignoring parameter: ' + val);
-                                               }
-                                               catch(e) {
-                                                       netdata.error('Cannot get value of parameter: ' + val);
-                                                       dumpError(e);
-                                               }
-                                       }
-                                       break;
-                       }
-               }
-       });
+    var found_myself = false;
+    var found_number = false;
+    var found_modules = false;
+    process.argv.forEach(function (val, index, array) {
+        netdata.debug('PARAM: ' + val);
+
+        if(!found_myself) {
+            if(val === __filename)
+                found_myself = true;
+        }
+        else {
+            switch(val) {
+                case 'debug':
+                    netdata.options.DEBUG = true;
+                    netdata.debug('DEBUG enabled');
+                    break;
+
+                default:
+                    if(found_number === true) {
+                        if(found_modules === false) {
+                            for(var i in netdata.options.modules)
+                                netdata.options.modules[i].enabled = false;
+                        }
+
+                        if(typeof netdata.options.modules[val] === 'undefined')
+                            netdata.options.modules[val] = {};
+
+                        netdata.options.modules[val].enabled = true;
+                        netdata.options.modules_enable_all = false;
+                        netdata.debug('enabled module ' + val);
+                    }
+                    else {
+                        try {
+                            var x = parseInt(val);
+                            if(x > 0) {
+                                netdata.options.update_every = x;
+                                if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
+                                    netdata.options.update_every = NETDATA_UPDATE_EVERY;
+                                    netdata.debug('Update frequency ' + x + 's is too low');
+                                }
+
+                                found_number = true;
+                                netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
+                            }
+                            else netdata.error('Ignoring parameter: ' + val);
+                        }
+                        catch(e) {
+                            netdata.error('Cannot get value of parameter: ' + val);
+                            dumpError(e);
+                        }
+                    }
+                    break;
+            }
+        }
+    });
 }
 
 if(netdata.options.update_every < 1) {
-       netdata.debug('Adjusting update frequency to 1 second');
-       netdata.options.update_every = 1;
+    netdata.debug('Adjusting update frequency to 1 second');
+    netdata.options.update_every = 1;
 }
 
 // --------------------------------------------------------------------------------------------------------------------
 // find modules
 
 function findModules() {
-       var found = 0;
-
-       var files = fs.readdirSync(NODE_D_DIR);
-       var len = files.length;
-       while(len--) {
-               var m = files[len].match('.node.js' + '$');
-               if(m !== null) {
-                       var n = files[len].substring(0, m.index);
-
-                       if(typeof(netdata.options.modules[n]) === 'undefined')
-                               netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };
-
-                       if(netdata.options.modules[n].enabled === true) {
-                               netdata.options.modules[n].name = n;
-                               netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
-                               netdata.options.modules[n].loaded = false;
-
-                               if(typeof(netdata.options.modules[n].config_filename) !== 'string')
-                                       netdata.options.modules[n].config_filename = pluginConfig(files[len]);
-
-                               // load the module
-                               try {
-                                       netdata.debug('loading module ' + netdata.options.modules[n].filename);
-                                       netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
-                                       netdata.options.modules[n].module.name = n;
-                                       netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
-                               }
-                               catch(e) {
-                                       netdata.options.modules[n].enabled = false;
-                                       netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
-                                       dumpError(e);
-                                       continue;
-                               }
-
-                               // load its configuration
-                               var c = {
-                                       enable_autodetect: netdata.options.modules_enable_autodetect,
-                                       update_every: netdata.options.update_every
-                               };
-                               try {
-                                       netdata.debug('loading module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
-                                       var c2 = JSON.parse(fs.readFileSync(netdata.options.modules[n].config_filename, 'utf8'));
-                                       extend(true, c, c2);
-                                       netdata.debug('loaded module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
-                               }
-                               catch(e) {
-                                       netdata.error('Cannot load module\'s ' + netdata.options.modules[n].name + ' config from ' + netdata.options.modules[n].config_filename + ' exception: ' + e + ', using internal defaults.');
-                                       dumpError(e);
-                               }
-
-                               // call module auto-detection / configuration
-                               try {
-                                       netdata.modules_configuring++;
-                                       netdata.debug('Configuring module ' + netdata.options.modules[n].name);
-                                       var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
-                                               netdata.debug('Configured module ' + netdata.options.modules[n].name);
-                                               netdata.modules_configuring--;
-                                       });
-
-                                       netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
-                               }
-                               catch(e) {
-                                       netdata.modules_configuring--;
-                                       netdata.options.modules[n].enabled = false;
-                                       netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
-                                       dumpError(e);
-                                       continue;
-                               }
-
-                               netdata.options.modules[n].loaded = true;
-                               found++;
-                       }
-               }
-       }
-
-       // netdata.debug(netdata.options.modules);
-       return found;
+    var found = 0;
+
+    var files = fs.readdirSync(NODE_D_DIR);
+    var len = files.length;
+    while(len--) {
+        var m = files[len].match('.node.js' + '$');
+        if(m !== null) {
+            var n = files[len].substring(0, m.index);
+
+            if(typeof(netdata.options.modules[n]) === 'undefined')
+                netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };
+
+            if(netdata.options.modules[n].enabled === true) {
+                netdata.options.modules[n].name = n;
+                netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
+                netdata.options.modules[n].loaded = false;
+
+                if(typeof(netdata.options.modules[n].config_filename) !== 'string')
+                    netdata.options.modules[n].config_filename = pluginConfig(files[len]);
+
+                // load the module
+                try {
+                    netdata.debug('loading module ' + netdata.options.modules[n].filename);
+                    netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
+                    netdata.options.modules[n].module.name = n;
+                    netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
+                }
+                catch(e) {
+                    netdata.options.modules[n].enabled = false;
+                    netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
+                    dumpError(e);
+                    continue;
+                }
+
+                // load its configuration
+                var c = {
+                    enable_autodetect: netdata.options.modules_enable_autodetect,
+                    update_every: netdata.options.update_every
+                };
+                try {
+                    netdata.debug('loading module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
+                    var c2 = JSON.parse(fs.readFileSync(netdata.options.modules[n].config_filename, 'utf8'));
+                    extend(true, c, c2);
+                    netdata.debug('loaded module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
+                }
+                catch(e) {
+                    netdata.error('Cannot load module\'s ' + netdata.options.modules[n].name + ' config from ' + netdata.options.modules[n].config_filename + ' exception: ' + e + ', using internal defaults.');
+                    dumpError(e);
+                }
+
+                // call module auto-detection / configuration
+                try {
+                    netdata.modules_configuring++;
+                    netdata.debug('Configuring module ' + netdata.options.modules[n].name);
+                    var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
+                        netdata.debug('Configured module ' + netdata.options.modules[n].name);
+                        netdata.modules_configuring--;
+                    });
+
+                    netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
+                }
+                catch(e) {
+                    netdata.modules_configuring--;
+                    netdata.options.modules[n].enabled = false;
+                    netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
+                    dumpError(e);
+                    continue;
+                }
+
+                netdata.options.modules[n].loaded = true;
+                found++;
+            }
+        }
+    }
+
+    // netdata.debug(netdata.options.modules);
+    return found;
 }
 
 if(findModules() === 0) {
-       netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
-       netdata.disableNodePlugin();
-       process.exit(1);
+    netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
+    netdata.disableNodePlugin();
+    process.exit(1);
 }
 
 
@@ -268,14 +268,14 @@ if(findModules() === 0) {
 // start
 
 function start_when_configuring_ends() {
-       if(netdata.modules_configuring > 0) {
-               netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
-               setTimeout(start_when_configuring_ends, 500);
-               return;
-       }
-
-       netdata.modules_configuring = 0;
-       netdata.start();
+    if(netdata.modules_configuring > 0) {
+        netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
+        setTimeout(start_when_configuring_ends, 500);
+        return;
+    }
+
+    netdata.modules_configuring = 0;
+    netdata.start();
 }
 start_when_configuring_ends();
 
index a0edadac34605027fd90fd702b2cca4e7125810a..bff5217d28a449e81d96ec0fb55e34a14631045d 100755 (executable)
@@ -23,21 +23,21 @@ update_every=$((t))
 
 # allow the user to override our defaults
 if [ -f "${config_dir}/tc-qos-helper.conf" ]
-       then
-       source "${config_dir}/tc-qos-helper.conf"
+    then
+    source "${config_dir}/tc-qos-helper.conf"
 fi
 
 # default time function
 now_ms=
 current_time_ms() {
-       now_ms="$(date +'%s')000"
+    now_ms="$(date +'%s')000"
 }
 
 # default sleep function
 LOOPSLEEPMS_LASTWORK=0
 loopsleepms() {
-       [ "$1" = "tellwork" ] && shift
-       sleep $1
+    [ "$1" = "tellwork" ] && shift
+    sleep $1
 }
 
 # if found and included, this file overwrites loopsleepms()
@@ -45,49 +45,49 @@ loopsleepms() {
 . "${plugins_dir}/loopsleepms.sh.inc"
 
 if [ -z "${tc}" -o ! -x "${tc}" ]
-       then
-       echo >&2 "${PROGRAM_NAME}: Cannot find command 'tc' in this system."
-       exit 1
+    then
+    echo >&2 "${PROGRAM_NAME}: Cannot find command 'tc' in this system."
+    exit 1
 fi
 
 devices=
 fix_names=
 
 setclassname() {
-       echo "SETCLASSNAME $3 $2"
+    echo "SETCLASSNAME $3 $2"
 }
 
 show_tc() {
-       local x="${1}" interface_dev interface_classes interface_classes_monitor
-
-       echo "BEGIN ${x}"
-       ${tc} -s class show dev ${x}
-
-       # check FireQOS names for classes
-       if [ ! -z "${fix_names}" -a -f "${fireqos_run_dir}/ifaces/${x}" ]
-       then
-               name="$(<"${fireqos_run_dir}/ifaces/${x}")"
-               echo "SETDEVICENAME ${name}"
-
-               interface_dev=
-               interface_classes=
-               interface_classes_monitor=
-               source "${fireqos_run_dir}/${name}.conf"
-               for n in ${interface_classes_monitor}
-               do
-                       setclassname ${n//|/ }
-               done
-               [ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
-       fi
-       echo "END ${x}"
+    local x="${1}" interface_dev interface_classes interface_classes_monitor
+
+    echo "BEGIN ${x}"
+    ${tc} -s class show dev ${x}
+
+    # check FireQOS names for classes
+    if [ ! -z "${fix_names}" -a -f "${fireqos_run_dir}/ifaces/${x}" ]
+    then
+        name="$(<"${fireqos_run_dir}/ifaces/${x}")"
+        echo "SETDEVICENAME ${name}"
+
+        interface_dev=
+        interface_classes=
+        interface_classes_monitor=
+        source "${fireqos_run_dir}/${name}.conf"
+        for n in ${interface_classes_monitor}
+        do
+            setclassname ${n//|/ }
+        done
+        [ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
+    fi
+    echo "END ${x}"
 }
 
 all_devices() {
-       cat /proc/net/dev | grep ":" | cut -d ':' -f 1 | while read dev
-       do
-               l=$(${tc} class show dev ${dev} | wc -l)
-               [ $l -ne 0 ] && echo ${dev}
-       done
+    cat /proc/net/dev | grep ":" | cut -d ':' -f 1 | while read dev
+    do
+        l=$(${tc} class show dev ${dev} | wc -l)
+        [ $l -ne 0 ] && echo ${dev}
+    done
 }
 
 # update devices and class names
@@ -102,25 +102,25 @@ c=0
 gc=0
 while [ 1 ]
 do
-       fix_names=
-       c=$((c + 1))
-       gc=$((gc + 1))
+    fix_names=
+    c=$((c + 1))
+    gc=$((gc + 1))
 
-       if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
-       then
-               c=1
-               fix_names="YES"
-               devices="$( all_devices )"
-       fi
+    if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
+    then
+        c=1
+        fix_names="YES"
+        devices="$( all_devices )"
+    fi
 
-       for d in ${devices}
-       do
-               show_tc ${d}
-       done
+    for d in ${devices}
+    do
+        show_tc ${d}
+    done
 
-       echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
+    echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
 
-       loopsleepms ${update_every}
+    loopsleepms ${update_every}
 
-       [ ${gc} -gt ${exit_after} ] && exit 0
+    [ ${gc} -gt ${exit_after} ] && exit 0
 done
index c43f4cd731c433ee4380fb9d921232a6a17147b6..51d714c20a74cc4e39044a6300bd7f59f25f01c4 100644 (file)
@@ -13,33 +13,33 @@ pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
 #define CONFIG_VALUE_CHECKED 0x08 // has been checked if the value is different from the default
 
 struct config_value {
-       avl avl;                                // the index - this has to be first!
+    avl avl;                // the index - this has to be first!
 
-       uint8_t flags;
-       uint32_t hash;                  // a simple hash to speed up searching
-                                                       // we first compare hashes, and only if the hashes are equal we do string comparisons
+    uint8_t flags;
+    uint32_t hash;          // a simple hash to speed up searching
+                            // we first compare hashes, and only if the hashes are equal we do string comparisons
 
-       char *name;
-       char *value;
+    char *name;
+    char *value;
 
-       struct config_value *next; // config->mutex protects just this
+    struct config_value *next; // config->mutex protects just this
 };
 
 struct config {
-       avl avl;
+    avl avl;
 
-       uint32_t hash;                  // a simple hash to speed up searching
-                                                       // we first compare hashes, and only if the hashes are equal we do string comparisons
+    uint32_t hash;          // a simple hash to speed up searching
+                            // we first compare hashes, and only if the hashes are equal we do string comparisons
 
-       char *name;
+    char *name;
 
-       struct config *next;    // gloabl config_mutex protects just this
+    struct config *next;    // gloabl config_mutex protects just this
 
-       struct config_value *values;
-       avl_tree_lock values_index;
+    struct config_value *values;
+    avl_tree_lock values_index;
 
-       pthread_mutex_t mutex;  // this locks only the writers, to ensure atomic updates
-                                                       // readers are protected using the rwlock in avl_tree_lock
+    pthread_mutex_t mutex;  // this locks only the writers, to ensure atomic updates
+                            // readers are protected using the rwlock in avl_tree_lock
 } *config_root = NULL;
 
 
@@ -47,19 +47,19 @@ struct config {
 // locking
 
 static inline void config_global_write_lock(void) {
-       pthread_mutex_lock(&config_mutex);
+    pthread_mutex_lock(&config_mutex);
 }
 
 static inline void config_global_unlock(void) {
-       pthread_mutex_unlock(&config_mutex);
+    pthread_mutex_unlock(&config_mutex);
 }
 
 static inline void config_section_write_lock(struct config *co) {
-       pthread_mutex_lock(&co->mutex);
+    pthread_mutex_lock(&co->mutex);
 }
 
 static inline void config_section_unlock(struct config *co) {
-       pthread_mutex_unlock(&co->mutex);
+    pthread_mutex_unlock(&co->mutex);
 }
 
 
@@ -67,20 +67,20 @@ static inline void config_section_unlock(struct config *co) {
 // config name-value index
 
 static int config_value_compare(void* a, void* b) {
-       if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
-       else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
-       else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
+    if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
+    else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
+    else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
 }
 
 #define config_value_index_add(co, cv) avl_insert_lock(&((co)->values_index), (avl *)(cv))
 #define config_value_index_del(co, cv) avl_remove_lock(&((co)->values_index), (avl *)(cv))
 
 static struct config_value *config_value_index_find(struct config *co, const char *name, uint32_t hash) {
-       struct config_value tmp;
-       tmp.hash = (hash)?hash:simple_hash(name);
-       tmp.name = (char *)name;
+    struct config_value tmp;
+    tmp.hash = (hash)?hash:simple_hash(name);
+    tmp.name = (char *)name;
 
-       return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
+    return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
 }
 
 
@@ -88,25 +88,25 @@ static struct config_value *config_value_index_find(struct config *co, const cha
 // config sections index
 
 static int config_compare(void* a, void* b) {
-       if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
-       else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
-       else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
+    if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
+    else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
+    else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
 }
 
 avl_tree_lock config_root_index = {
-               { NULL, config_compare },
-               AVL_LOCK_INITIALIZER
+        { NULL, config_compare },
+        AVL_LOCK_INITIALIZER
 };
 
 #define config_index_add(cfg) avl_insert_lock(&config_root_index, (avl *)(cfg))
 #define config_index_del(cfg) avl_remove_lock(&config_root_index, (avl *)(cfg))
 
 static struct config *config_index_find(const char *name, uint32_t hash) {
-       struct config tmp;
-       tmp.hash = (hash)?hash:simple_hash(name);
-       tmp.name = (char *)name;
+    struct config tmp;
+    tmp.hash = (hash)?hash:simple_hash(name);
+    tmp.name = (char *)name;
 
-       return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
+    return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
 }
 
 
@@ -114,31 +114,31 @@ static struct config *config_index_find(const char *name, uint32_t hash) {
 // config section methods
 
 static inline struct config *config_section_find(const char *section) {
-       return config_index_find(section, 0);
+    return config_index_find(section, 0);
 }
 
 static inline struct config *config_section_create(const char *section)
 {
-       debug(D_CONFIG, "Creating section '%s'.", section);
+    debug(D_CONFIG, "Creating section '%s'.", section);
 
-       struct config *co = callocz(1, sizeof(struct config));
-       co->name = strdupz(section);
-       co->hash = simple_hash(co->name);
+    struct config *co = callocz(1, sizeof(struct config));
+    co->name = strdupz(section);
+    co->hash = simple_hash(co->name);
 
-       avl_init_lock(&co->values_index, config_value_compare);
+    avl_init_lock(&co->values_index, config_value_compare);
 
-       config_index_add(co);
+    config_index_add(co);
 
-       config_global_write_lock();
-       struct config *co2 = config_root;
-       if(co2) {
-               while (co2->next) co2 = co2->next;
-               co2->next = co;
-       }
-       else config_root = co;
-       config_global_unlock();
+    config_global_write_lock();
+    struct config *co2 = config_root;
+    if(co2) {
+        while (co2->next) co2 = co2->next;
+        co2->next = co;
+    }
+    else config_root = co;
+    config_global_unlock();
 
-       return co;
+    return co;
 }
 
 
@@ -147,221 +147,221 @@ static inline struct config *config_section_create(const char *section)
 
 static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
 {
-       debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
+    debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
 
-       struct config_value *cv = callocz(1, sizeof(struct config_value));
-       cv->name = strdupz(name);
-       cv->hash = simple_hash(cv->name);
-       cv->value = strdupz(value);
+    struct config_value *cv = callocz(1, sizeof(struct config_value));
+    cv->name = strdupz(name);
+    cv->hash = simple_hash(cv->name);
+    cv->value = strdupz(value);
 
-       config_value_index_add(co, cv);
+    config_value_index_add(co, cv);
 
-       config_section_write_lock(co);
-       struct config_value *cv2 = co->values;
-       if(cv2) {
-               while (cv2->next) cv2 = cv2->next;
-               cv2->next = cv;
-       }
-       else co->values = cv;
-       config_section_unlock(co);
+    config_section_write_lock(co);
+    struct config_value *cv2 = co->values;
+    if(cv2) {
+        while (cv2->next) cv2 = cv2->next;
+        cv2->next = cv;
+    }
+    else co->values = cv;
+    config_section_unlock(co);
 
-       return cv;
+    return cv;
 }
 
 int config_exists(const char *section, const char *name) {
-       struct config_value *cv;
+    struct config_value *cv;
 
-       debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
+    debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
 
-       struct config *co = config_section_find(section);
-       if(!co) return 0;
+    struct config *co = config_section_find(section);
+    if(!co) return 0;
 
-       cv = config_value_index_find(co, name, 0);
-       if(!cv) return 0;
+    cv = config_value_index_find(co, name, 0);
+    if(!cv) return 0;
 
-       return 1;
+    return 1;
 }
 
 int config_rename(const char *section, const char *old, const char *new) {
-       struct config_value *cv, *cv2;
+    struct config_value *cv, *cv2;
 
-       debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
+    debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
 
-       struct config *co = config_section_find(section);
-       if(!co) return -1;
+    struct config *co = config_section_find(section);
+    if(!co) return -1;
 
-       config_section_write_lock(co);
+    config_section_write_lock(co);
 
-       cv = config_value_index_find(co, old, 0);
-       if(!cv) goto cleanup;
+    cv = config_value_index_find(co, old, 0);
+    if(!cv) goto cleanup;
 
-       cv2 = config_value_index_find(co, new, 0);
-       if(cv2) goto cleanup;
+    cv2 = config_value_index_find(co, new, 0);
+    if(cv2) goto cleanup;
 
-       config_value_index_del(co, cv);
+    config_value_index_del(co, cv);
 
-       freez(cv->name);
-       cv->name = strdupz(new);
+    freez(cv->name);
+    cv->name = strdupz(new);
 
-       cv->hash = simple_hash(cv->name);
+    cv->hash = simple_hash(cv->name);
 
-       config_value_index_add(co, cv);
-       config_section_unlock(co);
+    config_value_index_add(co, cv);
+    config_section_unlock(co);
 
-       return 0;
+    return 0;
 
 cleanup:
-       config_section_unlock(co);
-       return -1;
+    config_section_unlock(co);
+    return -1;
 }
 
 char *config_get(const char *section, const char *name, const char *default_value)
 {
-       struct config_value *cv;
-
-       debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
-
-       struct config *co = config_section_find(section);
-       if(!co) co = config_section_create(section);
-
-       cv = config_value_index_find(co, name, 0);
-       if(!cv) {
-               cv = config_value_create(co, name, default_value);
-               if(!cv) return NULL;
-       }
-       cv->flags |= CONFIG_VALUE_USED;
-
-       if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
-               // this is a loaded value from the config file
-               // if it is different that the default, mark it
-               if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
-                       if(strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
-                       cv->flags |= CONFIG_VALUE_CHECKED;
-               }
-       }
-
-       return(cv->value);
+    struct config_value *cv;
+
+    debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
+
+    struct config *co = config_section_find(section);
+    if(!co) co = config_section_create(section);
+
+    cv = config_value_index_find(co, name, 0);
+    if(!cv) {
+        cv = config_value_create(co, name, default_value);
+        if(!cv) return NULL;
+    }
+    cv->flags |= CONFIG_VALUE_USED;
+
+    if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
+        // this is a loaded value from the config file
+        // if it is different that the default, mark it
+        if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
+            if(strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
+            cv->flags |= CONFIG_VALUE_CHECKED;
+        }
+    }
+
+    return(cv->value);
 }
 
 long long config_get_number(const char *section, const char *name, long long value)
 {
-       char buffer[100], *s;
-       sprintf(buffer, "%lld", value);
+    char buffer[100], *s;
+    sprintf(buffer, "%lld", value);
 
-       s = config_get(section, name, buffer);
-       if(!s) return value;
+    s = config_get(section, name, buffer);
+    if(!s) return value;
 
-       return strtoll(s, NULL, 0);
+    return strtoll(s, NULL, 0);
 }
 
 int config_get_boolean(const char *section, const char *name, int value)
 {
-       char *s;
-       if(value) s = "yes";
-       else s = "no";
+    char *s;
+    if(value) s = "yes";
+    else s = "no";
 
-       s = config_get(section, name, s);
-       if(!s) return value;
+    s = config_get(section, name, s);
+    if(!s) return value;
 
-       if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
-       return 0;
+    if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
+    return 0;
 }
 
 int config_get_boolean_ondemand(const char *section, const char *name, int value)
 {
-       char *s;
+    char *s;
 
-       if(value == CONFIG_ONDEMAND_ONDEMAND)
-               s = "auto";
+    if(value == CONFIG_ONDEMAND_ONDEMAND)
+        s = "auto";
 
-       else if(value == CONFIG_ONDEMAND_NO)
-               s = "no";
+    else if(value == CONFIG_ONDEMAND_NO)
+        s = "no";
 
-       else
-               s = "yes";
+    else
+        s = "yes";
 
-       s = config_get(section, name, s);
-       if(!s) return value;
+    s = config_get(section, name, s);
+    if(!s) return value;
 
-       if(!strcmp(s, "yes"))
-               return CONFIG_ONDEMAND_YES;
-       else if(!strcmp(s, "no"))
-               return CONFIG_ONDEMAND_NO;
-       else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
-               return CONFIG_ONDEMAND_ONDEMAND;
+    if(!strcmp(s, "yes"))
+        return CONFIG_ONDEMAND_YES;
+    else if(!strcmp(s, "no"))
+        return CONFIG_ONDEMAND_NO;
+    else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
+        return CONFIG_ONDEMAND_ONDEMAND;
 
-       return value;
+    return value;
 }
 
 const char *config_set_default(const char *section, const char *name, const char *value)
 {
-       struct config_value *cv;
+    struct config_value *cv;
 
-       debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
+    debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
 
-       struct config *co = config_section_find(section);
-       if(!co) return config_set(section, name, value);
+    struct config *co = config_section_find(section);
+    if(!co) return config_set(section, name, value);
 
-       cv = config_value_index_find(co, name, 0);
-       if(!cv) return config_set(section, name, value);
+    cv = config_value_index_find(co, name, 0);
+    if(!cv) return config_set(section, name, value);
 
-       cv->flags |= CONFIG_VALUE_USED;
+    cv->flags |= CONFIG_VALUE_USED;
 
-       if(cv->flags & CONFIG_VALUE_LOADED)
-               return cv->value;
+    if(cv->flags & CONFIG_VALUE_LOADED)
+        return cv->value;
 
-       if(strcmp(cv->value, value) != 0) {
-               cv->flags |= CONFIG_VALUE_CHANGED;
+    if(strcmp(cv->value, value) != 0) {
+        cv->flags |= CONFIG_VALUE_CHANGED;
 
-               freez(cv->value);
-               cv->value = strdupz(value);
-       }
+        freez(cv->value);
+        cv->value = strdupz(value);
+    }
 
-       return cv->value;
+    return cv->value;
 }
 
 const char *config_set(const char *section, const char *name, const char *value)
 {
-       struct config_value *cv;
+    struct config_value *cv;
 
-       debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
+    debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
 
-       struct config *co = config_section_find(section);
-       if(!co) co = config_section_create(section);
+    struct config *co = config_section_find(section);
+    if(!co) co = config_section_create(section);
 
-       cv = config_value_index_find(co, name, 0);
-       if(!cv) cv = config_value_create(co, name, value);
-       cv->flags |= CONFIG_VALUE_USED;
+    cv = config_value_index_find(co, name, 0);
+    if(!cv) cv = config_value_create(co, name, value);
+    cv->flags |= CONFIG_VALUE_USED;
 
-       if(strcmp(cv->value, value) != 0) {
-               cv->flags |= CONFIG_VALUE_CHANGED;
+    if(strcmp(cv->value, value) != 0) {
+        cv->flags |= CONFIG_VALUE_CHANGED;
 
-               freez(cv->value);
-               cv->value = strdupz(value);
-       }
+        freez(cv->value);
+        cv->value = strdupz(value);
+    }
 
-       return value;
+    return value;
 }
 
 long long config_set_number(const char *section, const char *name, long long value)
 {
-       char buffer[100];
-       sprintf(buffer, "%lld", value);
+    char buffer[100];
+    sprintf(buffer, "%lld", value);
 
-       config_set(section, name, buffer);
+    config_set(section, name, buffer);
 
-       return value;
+    return value;
 }
 
 int config_set_boolean(const char *section, const char *name, int value)
 {
-       char *s;
-       if(value) s = "yes";
-       else s = "no";
+    char *s;
+    if(value) s = "yes";
+    else s = "no";
 
-       config_set(section, name, s);
+    config_set(section, name, s);
 
-       return value;
+    return value;
 }
 
 
@@ -370,151 +370,151 @@ int config_set_boolean(const char *section, const char *name, int value)
 
 int load_config(char *filename, int overwrite_used)
 {
-       int line = 0;
-       struct config *co = NULL;
-
-       char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
-
-       if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
-       FILE *fp = fopen(filename, "r");
-       if(!fp) {
-               error("Cannot open file '%s'", filename);
-               return 0;
-       }
-
-       while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
-               buffer[CONFIG_FILE_LINE_MAX] = '\0';
-               line++;
-
-               s = trim(buffer);
-               if(!s) {
-                       debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
-                       continue;
-               }
-
-               int len = (int) strlen(s);
-               if(*s == '[' && s[len - 1] == ']') {
-                       // new section
-                       s[len - 1] = '\0';
-                       s++;
-
-                       co = config_section_find(s);
-                       if(!co) co = config_section_create(s);
-
-                       continue;
-               }
-
-               if(!co) {
-                       // line outside a section
-                       error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
-                       continue;
-               }
-
-               char *name = s;
-               char *value = strchr(s, '=');
-               if(!value) {
-                       error("Ignoring line %d ('%s'), there is no = in it.", line, s);
-                       continue;
-               }
-               *value = '\0';
-               value++;
-
-               name = trim(name);
-               value = trim(value);
-
-               if(!name) {
-                       error("Ignoring line %d, name is empty.", line);
-                       continue;
-               }
-               if(!value) {
-                       debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
-                       continue;
-               }
-
-               struct config_value *cv = config_value_index_find(co, name, 0);
-
-               if(!cv) cv = config_value_create(co, name, value);
-               else {
-                       if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
-                               debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
-                               freez(cv->value);
-                               cv->value = strdupz(value);
-                       }
-                       else
-                               debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
-               }
-               cv->flags |= CONFIG_VALUE_LOADED;
-       }
-
-       fclose(fp);
-
-       return 1;
+    int line = 0;
+    struct config *co = NULL;
+
+    char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
+
+    if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
+    FILE *fp = fopen(filename, "r");
+    if(!fp) {
+        error("Cannot open file '%s'", filename);
+        return 0;
+    }
+
+    while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
+        buffer[CONFIG_FILE_LINE_MAX] = '\0';
+        line++;
+
+        s = trim(buffer);
+        if(!s) {
+            debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
+            continue;
+        }
+
+        int len = (int) strlen(s);
+        if(*s == '[' && s[len - 1] == ']') {
+            // new section
+            s[len - 1] = '\0';
+            s++;
+
+            co = config_section_find(s);
+            if(!co) co = config_section_create(s);
+
+            continue;
+        }
+
+        if(!co) {
+            // line outside a section
+            error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
+            continue;
+        }
+
+        char *name = s;
+        char *value = strchr(s, '=');
+        if(!value) {
+            error("Ignoring line %d ('%s'), there is no = in it.", line, s);
+            continue;
+        }
+        *value = '\0';
+        value++;
+
+        name = trim(name);
+        value = trim(value);
+
+        if(!name) {
+            error("Ignoring line %d, name is empty.", line);
+            continue;
+        }
+        if(!value) {
+            debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
+            continue;
+        }
+
+        struct config_value *cv = config_value_index_find(co, name, 0);
+
+        if(!cv) cv = config_value_create(co, name, value);
+        else {
+            if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
+                debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
+                freez(cv->value);
+                cv->value = strdupz(value);
+            }
+            else
+                debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
+        }
+        cv->flags |= CONFIG_VALUE_LOADED;
+    }
+
+    fclose(fp);
+
+    return 1;
 }
 
 void generate_config(BUFFER *wb, int only_changed)
 {
-       int i, pri;
-       struct config *co;
-       struct config_value *cv;
-
-       for(i = 0; i < 3 ;i++) {
-               switch(i) {
-                       case 0:
-                               buffer_strcat(wb,
-                                       "# NetData Configuration\n"
-                                       "# You can uncomment and change any of the options below.\n"
-                                       "# The value shown in the commented settings, is the default value.\n"
-                                       "\n# global netdata configuration\n");
-                               break;
-
-                       case 1:
-                               buffer_strcat(wb, "\n\n# per plugin configuration\n");
-                               break;
-
-                       case 2:
-                               buffer_strcat(wb, "\n\n# per chart configuration\n");
-                               break;
-               }
-
-               config_global_write_lock();
-               for(co = config_root; co ; co = co->next) {
-                       if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
-                       else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
-                       else pri = 2;
-
-                       if(i == pri) {
-                               int used = 0;
-                               int changed = 0;
-                               int count = 0;
-
-                               config_section_write_lock(co);
-                               for(cv = co->values; cv ; cv = cv->next) {
-                                       used += (cv->flags & CONFIG_VALUE_USED)?1:0;
-                                       changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
-                                       count++;
-                               }
-                               config_section_unlock(co);
-
-                               if(!count) continue;
-                               if(only_changed && !changed) continue;
-
-                               if(!used) {
-                                       buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
-                               }
-
-                               buffer_sprintf(wb, "\n[%s]\n", co->name);
-
-                               config_section_write_lock(co);
-                               for(cv = co->values; cv ; cv = cv->next) {
-
-                                       if(used && !(cv->flags & CONFIG_VALUE_USED)) {
-                                               buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
-                                       }
-                                       buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
-                               }
-                               config_section_unlock(co);
-                       }
-               }
-               config_global_unlock();
-       }
+    int i, pri;
+    struct config *co;
+    struct config_value *cv;
+
+    for(i = 0; i < 3 ;i++) {
+        switch(i) {
+            case 0:
+                buffer_strcat(wb,
+                    "# NetData Configuration\n"
+                    "# You can uncomment and change any of the options below.\n"
+                    "# The value shown in the commented settings, is the default value.\n"
+                    "\n# global netdata configuration\n");
+                break;
+
+            case 1:
+                buffer_strcat(wb, "\n\n# per plugin configuration\n");
+                break;
+
+            case 2:
+                buffer_strcat(wb, "\n\n# per chart configuration\n");
+                break;
+        }
+
+        config_global_write_lock();
+        for(co = config_root; co ; co = co->next) {
+            if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
+            else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
+            else pri = 2;
+
+            if(i == pri) {
+                int used = 0;
+                int changed = 0;
+                int count = 0;
+
+                config_section_write_lock(co);
+                for(cv = co->values; cv ; cv = cv->next) {
+                    used += (cv->flags & CONFIG_VALUE_USED)?1:0;
+                    changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
+                    count++;
+                }
+                config_section_unlock(co);
+
+                if(!count) continue;
+                if(only_changed && !changed) continue;
+
+                if(!used) {
+                    buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
+                }
+
+                buffer_sprintf(wb, "\n[%s]\n", co->name);
+
+                config_section_write_lock(co);
+                for(cv = co->values; cv ; cv = cv->next) {
+
+                    if(used && !(cv->flags & CONFIG_VALUE_USED)) {
+                        buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
+                    }
+                    buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
+                }
+                config_section_unlock(co);
+            }
+        }
+        config_global_unlock();
+    }
 }
index 01da625b7924043e6920d70e75c18e65286311aa..b55394198127e9f9df0f24b0a6aa1425d4594c6e 100644 (file)
@@ -36,7 +36,7 @@ int enable_guest_charts = 0;
 // ----------------------------------------------------------------------------
 
 void netdata_cleanup_and_exit(int ret) {
-       exit(ret);
+    exit(ret);
 }
 
 
@@ -45,55 +45,55 @@ void netdata_cleanup_and_exit(int ret) {
 // to retrieve settings of the system
 
 long get_system_cpus(void) {
-       procfile *ff = NULL;
+    procfile *ff = NULL;
 
-       int processors = 0;
+    int processors = 0;
 
-       char filename[FILENAME_MAX + 1];
-       snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
+    char filename[FILENAME_MAX + 1];
+    snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
 
-       ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
-       if(!ff) return 1;
+    ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) {
-               procfile_close(ff);
-               return 1;
-       }
+    ff = procfile_readall(ff);
+    if(!ff) {
+        procfile_close(ff);
+        return 1;
+    }
 
-       unsigned int i;
-       for(i = 0; i < procfile_lines(ff); i++) {
-               if(!procfile_linewords(ff, i)) continue;
+    unsigned int i;
+    for(i = 0; i < procfile_lines(ff); i++) {
+        if(!procfile_linewords(ff, i)) continue;
 
-               if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
-       }
-       processors--;
-       if(processors < 1) processors = 1;
+        if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
+    }
+    processors--;
+    if(processors < 1) processors = 1;
 
-       procfile_close(ff);
-       return processors;
+    procfile_close(ff);
+    return processors;
 }
 
 pid_t get_system_pid_max(void) {
-       procfile *ff = NULL;
-       pid_t mpid = 32768;
-
-       char filename[FILENAME_MAX + 1];
-       snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
-       ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
-       if(!ff) return mpid;
-
-       ff = procfile_readall(ff);
-       if(!ff) {
-               procfile_close(ff);
-               return mpid;
-       }
+    procfile *ff = NULL;
+    pid_t mpid = 32768;
+
+    char filename[FILENAME_MAX + 1];
+    snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
+    ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
+    if(!ff) return mpid;
+
+    ff = procfile_readall(ff);
+    if(!ff) {
+        procfile_close(ff);
+        return mpid;
+    }
 
-       mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
-       if(!mpid) mpid = 32768;
+    mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
+    if(!mpid) mpid = 32768;
 
-       procfile_close(ff);
-       return mpid;
+    procfile_close(ff);
+    return mpid;
 }
 
 // ----------------------------------------------------------------------------
@@ -101,68 +101,68 @@ pid_t get_system_pid_max(void) {
 // target is the structure that process data are aggregated
 
 struct target {
-       char compare[MAX_COMPARE_NAME + 1];
-       uint32_t comparehash;
-       size_t comparelen;
-
-       char id[MAX_NAME + 1];
-       uint32_t idhash;
-
-       char name[MAX_NAME + 1];
-
-       uid_t uid;
-       gid_t gid;
-
-       unsigned long long minflt;
-       unsigned long long cminflt;
-       unsigned long long majflt;
-       unsigned long long cmajflt;
-       unsigned long long utime;
-       unsigned long long stime;
-       unsigned long long gtime;
-       unsigned long long cutime;
-       unsigned long long cstime;
-       unsigned long long cgtime;
-       unsigned long long num_threads;
-       unsigned long long rss;
-
-       unsigned long long statm_size;
-       unsigned long long statm_resident;
-       unsigned long long statm_share;
-       unsigned long long statm_text;
-       unsigned long long statm_lib;
-       unsigned long long statm_data;
-       unsigned long long statm_dirty;
-
-       unsigned long long io_logical_bytes_read;
-       unsigned long long io_logical_bytes_written;
-       unsigned long long io_read_calls;
-       unsigned long long io_write_calls;
-       unsigned long long io_storage_bytes_read;
-       unsigned long long io_storage_bytes_written;
-       unsigned long long io_cancelled_write_bytes;
-
-       int *fds;
-       unsigned long long openfiles;
-       unsigned long long openpipes;
-       unsigned long long opensockets;
-       unsigned long long openinotifies;
-       unsigned long long openeventfds;
-       unsigned long long opentimerfds;
-       unsigned long long opensignalfds;
-       unsigned long long openeventpolls;
-       unsigned long long openother;
-
-       unsigned long processes;        // how many processes have been merged to this
-       int exposed;                            // if set, we have sent this to netdata
-       int hidden;                                     // if set, we set the hidden flag on the dimension
-       int debug;
-       int ends_with;
-       int starts_with;            // if set, the compare string matches only the
-                                                               // beginning of the command
-
-       struct target *target;          // the one that will be reported to netdata
-       struct target *next;
+    char compare[MAX_COMPARE_NAME + 1];
+    uint32_t comparehash;
+    size_t comparelen;
+
+    char id[MAX_NAME + 1];
+    uint32_t idhash;
+
+    char name[MAX_NAME + 1];
+
+    uid_t uid;
+    gid_t gid;
+
+    unsigned long long minflt;
+    unsigned long long cminflt;
+    unsigned long long majflt;
+    unsigned long long cmajflt;
+    unsigned long long utime;
+    unsigned long long stime;
+    unsigned long long gtime;
+    unsigned long long cutime;
+    unsigned long long cstime;
+    unsigned long long cgtime;
+    unsigned long long num_threads;
+    unsigned long long rss;
+
+    unsigned long long statm_size;
+    unsigned long long statm_resident;
+    unsigned long long statm_share;
+    unsigned long long statm_text;
+    unsigned long long statm_lib;
+    unsigned long long statm_data;
+    unsigned long long statm_dirty;
+
+    unsigned long long io_logical_bytes_read;
+    unsigned long long io_logical_bytes_written;
+    unsigned long long io_read_calls;
+    unsigned long long io_write_calls;
+    unsigned long long io_storage_bytes_read;
+    unsigned long long io_storage_bytes_written;
+    unsigned long long io_cancelled_write_bytes;
+
+    int *fds;
+    unsigned long long openfiles;
+    unsigned long long openpipes;
+    unsigned long long opensockets;
+    unsigned long long openinotifies;
+    unsigned long long openeventfds;
+    unsigned long long opentimerfds;
+    unsigned long long opensignalfds;
+    unsigned long long openeventpolls;
+    unsigned long long openother;
+
+    unsigned long processes;    // how many processes have been merged to this
+    int exposed;                // if set, we have sent this to netdata
+    int hidden;                 // if set, we set the hidden flag on the dimension
+    int debug;
+    int ends_with;
+    int starts_with;            // if set, the compare string matches only the
+                                // beginning of the command
+
+    struct target *target;      // the one that will be reported to netdata
+    struct target *next;
 };
 
 
@@ -179,214 +179,214 @@ struct target *groups_root_target = NULL;
 
 struct target *get_users_target(uid_t uid)
 {
-       struct target *w;
-       for(w = users_root_target ; w ; w = w->next)
-               if(w->uid == uid) return w;
+    struct target *w;
+    for(w = users_root_target ; w ; w = w->next)
+        if(w->uid == uid) return w;
 
-       w = callocz(sizeof(struct target), 1);
-       snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid);
-       w->comparehash = simple_hash(w->compare);
-       w->comparelen = strlen(w->compare);
+    w = callocz(sizeof(struct target), 1);
+    snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid);
+    w->comparehash = simple_hash(w->compare);
+    w->comparelen = strlen(w->compare);
 
-       snprintfz(w->id, MAX_NAME, "%u", uid);
-       w->idhash = simple_hash(w->id);
+    snprintfz(w->id, MAX_NAME, "%u", uid);
+    w->idhash = simple_hash(w->id);
 
-       struct passwd *pw = getpwuid(uid);
-       if(!pw)
-               snprintfz(w->name, MAX_NAME, "%u", uid);
-       else
-               snprintfz(w->name, MAX_NAME, "%s", pw->pw_name);
+    struct passwd *pw = getpwuid(uid);
+    if(!pw)
+        snprintfz(w->name, MAX_NAME, "%u", uid);
+    else
+        snprintfz(w->name, MAX_NAME, "%s", pw->pw_name);
 
-       netdata_fix_chart_name(w->name);
+    netdata_fix_chart_name(w->name);
 
-       w->uid = uid;
+    w->uid = uid;
 
-       w->next = users_root_target;
-       users_root_target = w;
+    w->next = users_root_target;
+    users_root_target = w;
 
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name);
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name);
 
-       return w;
+    return w;
 }
 
 struct target *get_groups_target(gid_t gid)
 {
-       struct target *w;
-       for(w = groups_root_target ; w ; w = w->next)
-               if(w->gid == gid) return w;
+    struct target *w;
+    for(w = groups_root_target ; w ; w = w->next)
+        if(w->gid == gid) return w;
 
-       w = callocz(sizeof(struct target), 1);
-       snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid);
-       w->comparehash = simple_hash(w->compare);
-       w->comparelen = strlen(w->compare);
+    w = callocz(sizeof(struct target), 1);
+    snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid);
+    w->comparehash = simple_hash(w->compare);
+    w->comparelen = strlen(w->compare);
 
-       snprintfz(w->id, MAX_NAME, "%u", gid);
-       w->idhash = simple_hash(w->id);
+    snprintfz(w->id, MAX_NAME, "%u", gid);
+    w->idhash = simple_hash(w->id);
 
-       struct group *gr = getgrgid(gid);
-       if(!gr)
-               snprintfz(w->name, MAX_NAME, "%u", gid);
-       else
-               snprintfz(w->name, MAX_NAME, "%s", gr->gr_name);
+    struct group *gr = getgrgid(gid);
+    if(!gr)
+        snprintfz(w->name, MAX_NAME, "%u", gid);
+    else
+        snprintfz(w->name, MAX_NAME, "%s", gr->gr_name);
 
-       netdata_fix_chart_name(w->name);
+    netdata_fix_chart_name(w->name);
 
-       w->gid = gid;
+    w->gid = gid;
 
-       w->next = groups_root_target;
-       groups_root_target = w;
+    w->next = groups_root_target;
+    groups_root_target = w;
 
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name);
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name);
 
-       return w;
+    return w;
 }
 
 // find or create a new target
 // there are targets that are just aggregated to other target (the second argument)
 struct target *get_apps_groups_target(const char *id, struct target *target) {
-       int tdebug = 0, thidden = 0, ends_with = 0;
-       const char *nid = id;
-
-       while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
-               if(nid[0] == '-') thidden = 1;
-               if(nid[0] == '+') tdebug = 1;
-               if(nid[0] == '*') ends_with = 1;
-               nid++;
-       }
-       uint32_t hash = simple_hash(id);
-
-       struct target *w, *last = apps_groups_root_target;
-       for(w = apps_groups_root_target ; w ; w = w->next) {
-               if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
-                       return w;
-
-               last = w;
-       }
-
-       w = callocz(sizeof(struct target), 1);
-       strncpyz(w->id, nid, MAX_NAME);
-       w->idhash = simple_hash(w->id);
-
-       strncpyz(w->name, nid, MAX_NAME);
-
-       strncpyz(w->compare, nid, MAX_COMPARE_NAME);
-       size_t len = strlen(w->compare);
-       if(w->compare[len - 1] == '*') {
-               w->compare[len - 1] = '\0';
-               w->starts_with = 1;
-       }
-       w->ends_with = ends_with;
-
-       if(w->starts_with && w->ends_with)
-               proc_pid_cmdline_is_needed = 1;
-
-       w->comparehash = simple_hash(w->compare);
-       w->comparelen = strlen(w->compare);
-
-       w->hidden = thidden;
-       w->debug = tdebug;
-       w->target = target;
-
-       // append it, to maintain the order in apps_groups.conf
-       if(last) last->next = w;
-       else apps_groups_root_target = w;
-
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
-                       , w->id
-                               , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
-                               , w->target?w->target->id:w->id
-                               , (w->hidden)?"hidden":"-"
-                               , (w->debug)?"debug":"-"
-               );
-
-       return w;
+    int tdebug = 0, thidden = 0, ends_with = 0;
+    const char *nid = id;
+
+    while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
+        if(nid[0] == '-') thidden = 1;
+        if(nid[0] == '+') tdebug = 1;
+        if(nid[0] == '*') ends_with = 1;
+        nid++;
+    }
+    uint32_t hash = simple_hash(id);
+
+    struct target *w, *last = apps_groups_root_target;
+    for(w = apps_groups_root_target ; w ; w = w->next) {
+        if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
+            return w;
+
+        last = w;
+    }
+
+    w = callocz(sizeof(struct target), 1);
+    strncpyz(w->id, nid, MAX_NAME);
+    w->idhash = simple_hash(w->id);
+
+    strncpyz(w->name, nid, MAX_NAME);
+
+    strncpyz(w->compare, nid, MAX_COMPARE_NAME);
+    size_t len = strlen(w->compare);
+    if(w->compare[len - 1] == '*') {
+        w->compare[len - 1] = '\0';
+        w->starts_with = 1;
+    }
+    w->ends_with = ends_with;
+
+    if(w->starts_with && w->ends_with)
+        proc_pid_cmdline_is_needed = 1;
+
+    w->comparehash = simple_hash(w->compare);
+    w->comparelen = strlen(w->compare);
+
+    w->hidden = thidden;
+    w->debug = tdebug;
+    w->target = target;
+
+    // append it, to maintain the order in apps_groups.conf
+    if(last) last->next = w;
+    else apps_groups_root_target = w;
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
+                , w->id
+                , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
+                , w->target?w->target->id:w->id
+                , (w->hidden)?"hidden":"-"
+                , (w->debug)?"debug":"-"
+        );
+
+    return w;
 }
 
 // read the apps_groups.conf file
 int read_apps_groups_conf(const char *name)
 {
-       char filename[FILENAME_MAX + 1];
-
-       snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
+    char filename[FILENAME_MAX + 1];
 
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
+    snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
 
-       // ----------------------------------------
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
 
-       procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
-       if(!ff) return 1;
+    // ----------------------------------------
 
-       procfile_set_quotes(ff, "'\"");
+    procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) {
-               procfile_close(ff);
-               return 1;
-       }
+    procfile_set_quotes(ff, "'\"");
 
-       unsigned long line, lines = procfile_lines(ff);
-
-       for(line = 0; line < lines ;line++) {
-               unsigned long word, words = procfile_linewords(ff, line);
-               struct target *w = NULL;
-
-               char *t = procfile_lineword(ff, line, 0);
-               if(!t || !*t) continue;
+    ff = procfile_readall(ff);
+    if(!ff) {
+        procfile_close(ff);
+        return 1;
+    }
 
-               for(word = 0; word < words ;word++) {
-                       char *s = procfile_lineword(ff, line, word);
-                       if(!s || !*s) continue;
-                       if(*s == '#') break;
+    unsigned long line, lines = procfile_lines(ff);
 
-                       if(t == s) continue;
+    for(line = 0; line < lines ;line++) {
+        unsigned long word, words = procfile_linewords(ff, line);
+        struct target *w = NULL;
 
-                       struct target *n = get_apps_groups_target(s, w);
-                       if(!n) {
-                               error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
-                               continue;
-                       }
+        char *t = procfile_lineword(ff, line, 0);
+        if(!t || !*t) continue;
 
-                       if(!w) w = n;
-               }
+        for(word = 0; word < words ;word++) {
+            char *s = procfile_lineword(ff, line, word);
+            if(!s || !*s) continue;
+            if(*s == '#') break;
 
-               if(w) {
-                       int tdebug = 0, thidden = 0;
+            if(t == s) continue;
 
-                       while(t[0] == '-' || t[0] == '+') {
-                               if(t[0] == '-') thidden = 1;
-                               if(t[0] == '+') tdebug = 1;
-                               t++;
-                       }
+            struct target *n = get_apps_groups_target(s, w);
+            if(!n) {
+                error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
+                continue;
+            }
 
-                       strncpyz(w->name, t, MAX_NAME);
-                       w->hidden = thidden;
-                       w->debug = tdebug;
+            if(!w) w = n;
+        }
 
-                       if(unlikely(debug))
-                               fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
-                                               , w->name
-                                               , w->id
-                                               , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
-                                               , w->target?w->target->id:w->id
-                                               , (w->hidden)?"hidden":"-"
-                                               , (w->debug)?"debug":"-"
-                               );
-               }
-       }
+        if(w) {
+            int tdebug = 0, thidden = 0;
+
+            while(t[0] == '-' || t[0] == '+') {
+                if(t[0] == '-') thidden = 1;
+                if(t[0] == '+') tdebug = 1;
+                t++;
+            }
+
+            strncpyz(w->name, t, MAX_NAME);
+            w->hidden = thidden;
+            w->debug = tdebug;
+
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
+                        , w->name
+                        , w->id
+                        , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
+                        , w->target?w->target->id:w->id
+                        , (w->hidden)?"hidden":"-"
+                        , (w->debug)?"debug":"-"
+                );
+        }
+    }
 
-       procfile_close(ff);
+    procfile_close(ff);
 
-       apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
-       if(!apps_groups_default_target)
-               error("Cannot create default target");
-       else
-               strncpyz(apps_groups_default_target->name, "other", MAX_NAME);
+    apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
+    if(!apps_groups_default_target)
+        error("Cannot create default target");
+    else
+        strncpyz(apps_groups_default_target->name, "other", MAX_NAME);
 
-       return 0;
+    return 0;
 }
 
 
@@ -395,174 +395,174 @@ int read_apps_groups_conf(const char *name)
 // see: man proc
 
 struct pid_stat {
-       int32_t pid;
-       char comm[MAX_COMPARE_NAME + 1];
-       char cmdline[MAX_CMDLINE + 1];
-
-       // char state;
-       int32_t ppid;
-       // int32_t pgrp;
-       // int32_t session;
-       // int32_t tty_nr;
-       // int32_t tpgid;
-       // uint64_t flags;
-
-       // these are raw values collected
-       unsigned long long minflt_raw;
-       unsigned long long cminflt_raw;
-       unsigned long long majflt_raw;
-       unsigned long long cmajflt_raw;
-       unsigned long long utime_raw;
-       unsigned long long stime_raw;
-       unsigned long long gtime_raw; // guest_time
-       unsigned long long cutime_raw;
-       unsigned long long cstime_raw;
-       unsigned long long cgtime_raw; // cguest_time
-
-       // these are rates
-       unsigned long long minflt;
-       unsigned long long cminflt;
-       unsigned long long majflt;
-       unsigned long long cmajflt;
-       unsigned long long utime;
-       unsigned long long stime;
-       unsigned long long gtime;
-       unsigned long long cutime;
-       unsigned long long cstime;
-       unsigned long long cgtime;
-
-       // int64_t priority;
-       // int64_t nice;
-       int32_t num_threads;
-       // int64_t itrealvalue;
-       // unsigned long long starttime;
-       // unsigned long long vsize;
-       unsigned long long rss;
-       // unsigned long long rsslim;
-       // unsigned long long starcode;
-       // unsigned long long endcode;
-       // unsigned long long startstack;
-       // unsigned long long kstkesp;
-       // unsigned long long kstkeip;
-       // uint64_t signal;
-       // uint64_t blocked;
-       // uint64_t sigignore;
-       // uint64_t sigcatch;
-       // uint64_t wchan;
-       // uint64_t nswap;
-       // uint64_t cnswap;
-       // int32_t exit_signal;
-       // int32_t processor;
-       // uint32_t rt_priority;
-       // uint32_t policy;
-       // unsigned long long delayacct_blkio_ticks;
-
-       uid_t uid;
-       gid_t gid;
-
-       unsigned long long statm_size;
-       unsigned long long statm_resident;
-       unsigned long long statm_share;
-       unsigned long long statm_text;
-       unsigned long long statm_lib;
-       unsigned long long statm_data;
-       unsigned long long statm_dirty;
-
-       unsigned long long io_logical_bytes_read_raw;
-       unsigned long long io_logical_bytes_written_raw;
-       unsigned long long io_read_calls_raw;
-       unsigned long long io_write_calls_raw;
-       unsigned long long io_storage_bytes_read_raw;
-       unsigned long long io_storage_bytes_written_raw;
-       unsigned long long io_cancelled_write_bytes_raw;
-
-       unsigned long long io_logical_bytes_read;
-       unsigned long long io_logical_bytes_written;
-       unsigned long long io_read_calls;
-       unsigned long long io_write_calls;
-       unsigned long long io_storage_bytes_read;
-       unsigned long long io_storage_bytes_written;
-       unsigned long long io_cancelled_write_bytes;
-
-       int *fds;                                               // array of fds it uses
-       int fds_size;                                   // the size of the fds array
-
-       int children_count;                             // number of processes directly referencing this
-       int keep;                                               // 1 when we need to keep this process in memory even after it exited
-       int keeploops;                                  // increases by 1 every time keep is 1 and updated 0
-       int updated;                                    // 1 when the process is currently running
-       int merged;                                             // 1 when it has been merged to its parent
-       int new_entry;                                  // 1 when this is a new process, just saw for the first time
-       int read;                                               // 1 when we have already read this process for this iteration
-       int sortlist;                                   // higher numbers = top on the process tree
-                                                                       // each process gets a unique number
-
-       struct target *target;                  // app_groups.conf targets
-       struct target *user_target;             // uid based targets
-       struct target *group_target;    // gid based targets
-
-       unsigned long long stat_collected_usec;
-       unsigned long long last_stat_collected_usec;
-
-       unsigned long long io_collected_usec;
-       unsigned long long last_io_collected_usec;
-
-       char *stat_filename;
-       char *statm_filename;
-       char *io_filename;
-       char *cmdline_filename;
-
-       struct pid_stat *parent;
-       struct pid_stat *prev;
-       struct pid_stat *next;
+    int32_t pid;
+    char comm[MAX_COMPARE_NAME + 1];
+    char cmdline[MAX_CMDLINE + 1];
+
+    // char state;
+    int32_t ppid;
+    // int32_t pgrp;
+    // int32_t session;
+    // int32_t tty_nr;
+    // int32_t tpgid;
+    // uint64_t flags;
+
+    // these are raw values collected
+    unsigned long long minflt_raw;
+    unsigned long long cminflt_raw;
+    unsigned long long majflt_raw;
+    unsigned long long cmajflt_raw;
+    unsigned long long utime_raw;
+    unsigned long long stime_raw;
+    unsigned long long gtime_raw; // guest_time
+    unsigned long long cutime_raw;
+    unsigned long long cstime_raw;
+    unsigned long long cgtime_raw; // cguest_time
+
+    // these are rates
+    unsigned long long minflt;
+    unsigned long long cminflt;
+    unsigned long long majflt;
+    unsigned long long cmajflt;
+    unsigned long long utime;
+    unsigned long long stime;
+    unsigned long long gtime;
+    unsigned long long cutime;
+    unsigned long long cstime;
+    unsigned long long cgtime;
+
+    // int64_t priority;
+    // int64_t nice;
+    int32_t num_threads;
+    // int64_t itrealvalue;
+    // unsigned long long starttime;
+    // unsigned long long vsize;
+    unsigned long long rss;
+    // unsigned long long rsslim;
+    // unsigned long long starcode;
+    // unsigned long long endcode;
+    // unsigned long long startstack;
+    // unsigned long long kstkesp;
+    // unsigned long long kstkeip;
+    // uint64_t signal;
+    // uint64_t blocked;
+    // uint64_t sigignore;
+    // uint64_t sigcatch;
+    // uint64_t wchan;
+    // uint64_t nswap;
+    // uint64_t cnswap;
+    // int32_t exit_signal;
+    // int32_t processor;
+    // uint32_t rt_priority;
+    // uint32_t policy;
+    // unsigned long long delayacct_blkio_ticks;
+
+    uid_t uid;
+    gid_t gid;
+
+    unsigned long long statm_size;
+    unsigned long long statm_resident;
+    unsigned long long statm_share;
+    unsigned long long statm_text;
+    unsigned long long statm_lib;
+    unsigned long long statm_data;
+    unsigned long long statm_dirty;
+
+    unsigned long long io_logical_bytes_read_raw;
+    unsigned long long io_logical_bytes_written_raw;
+    unsigned long long io_read_calls_raw;
+    unsigned long long io_write_calls_raw;
+    unsigned long long io_storage_bytes_read_raw;
+    unsigned long long io_storage_bytes_written_raw;
+    unsigned long long io_cancelled_write_bytes_raw;
+
+    unsigned long long io_logical_bytes_read;
+    unsigned long long io_logical_bytes_written;
+    unsigned long long io_read_calls;
+    unsigned long long io_write_calls;
+    unsigned long long io_storage_bytes_read;
+    unsigned long long io_storage_bytes_written;
+    unsigned long long io_cancelled_write_bytes;
+
+    int *fds;                       // array of fds it uses
+    int fds_size;                   // the size of the fds array
+
+    int children_count;             // number of processes directly referencing this
+    int keep;                       // 1 when we need to keep this process in memory even after it exited
+    int keeploops;                  // increases by 1 every time keep is 1 and updated 0
+    int updated;                    // 1 when the process is currently running
+    int merged;                     // 1 when it has been merged to its parent
+    int new_entry;                  // 1 when this is a new process, just saw for the first time
+    int read;                       // 1 when we have already read this process for this iteration
+    int sortlist;                   // higher numbers = top on the process tree
+                                    // each process gets a unique number
+
+    struct target *target;          // app_groups.conf targets
+    struct target *user_target;     // uid based targets
+    struct target *group_target;    // gid based targets
+
+    unsigned long long stat_collected_usec;
+    unsigned long long last_stat_collected_usec;
+
+    unsigned long long io_collected_usec;
+    unsigned long long last_io_collected_usec;
+
+    char *stat_filename;
+    char *statm_filename;
+    char *io_filename;
+    char *cmdline_filename;
+
+    struct pid_stat *parent;
+    struct pid_stat *prev;
+    struct pid_stat *next;
 } *root_of_pids = NULL, **all_pids;
 
 long all_pids_count = 0;
 
 struct pid_stat *get_pid_entry(pid_t pid) {
-       if(all_pids[pid]) {
-               all_pids[pid]->new_entry = 0;
-               return all_pids[pid];
-       }
+    if(all_pids[pid]) {
+        all_pids[pid]->new_entry = 0;
+        return all_pids[pid];
+    }
 
-       all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
-       all_pids[pid]->fds = callocz(sizeof(int), 100);
-       all_pids[pid]->fds_size = 100;
+    all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
+    all_pids[pid]->fds = callocz(sizeof(int), 100);
+    all_pids[pid]->fds_size = 100;
 
-       if(root_of_pids) root_of_pids->prev = all_pids[pid];
-       all_pids[pid]->next = root_of_pids;
-       root_of_pids = all_pids[pid];
+    if(root_of_pids) root_of_pids->prev = all_pids[pid];
+    all_pids[pid]->next = root_of_pids;
+    root_of_pids = all_pids[pid];
 
-       all_pids[pid]->pid = pid;
-       all_pids[pid]->new_entry = 1;
+    all_pids[pid]->pid = pid;
+    all_pids[pid]->new_entry = 1;
 
-       all_pids_count++;
+    all_pids_count++;
 
-       return all_pids[pid];
+    return all_pids[pid];
 }
 
 void del_pid_entry(pid_t pid) {
-       if(!all_pids[pid]) {
-               error("attempted to free pid %d that is not allocated.", pid);
-               return;
-       }
-
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
-
-       if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
-       if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
-       if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
-
-       if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
-       if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
-       if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
-       if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
-       if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
-       freez(all_pids[pid]);
-
-       all_pids[pid] = NULL;
-       all_pids_count--;
+    if(!all_pids[pid]) {
+        error("attempted to free pid %d that is not allocated.", pid);
+        return;
+    }
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
+
+    if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
+    if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
+    if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
+
+    if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
+    if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
+    if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
+    if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
+    if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
+    freez(all_pids[pid]);
+
+    all_pids[pid] = NULL;
+    all_pids_count--;
 }
 
 
@@ -570,160 +570,160 @@ void del_pid_entry(pid_t pid) {
 // update pids from proc
 
 int read_proc_pid_cmdline(struct pid_stat *p) {
-       
-       if(unlikely(!p->cmdline_filename)) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
-               p->cmdline_filename = strdupz(filename);
-       }
+    
+    if(unlikely(!p->cmdline_filename)) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
+        p->cmdline_filename = strdupz(filename);
+    }
 
-       int fd = open(p->cmdline_filename, O_RDONLY, 0666);
-       if(unlikely(fd == -1)) goto cleanup;
+    int fd = open(p->cmdline_filename, O_RDONLY, 0666);
+    if(unlikely(fd == -1)) goto cleanup;
 
-       ssize_t i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
-       close(fd);
+    ssize_t i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
+    close(fd);
 
-       if(unlikely(bytes <= 0)) goto cleanup;
+    if(unlikely(bytes <= 0)) goto cleanup;
 
-       p->cmdline[bytes] = '\0';
-       for(i = 0; i < bytes ; i++)
-               if(unlikely(!p->cmdline[i])) p->cmdline[i] = ' ';
+    p->cmdline[bytes] = '\0';
+    for(i = 0; i < bytes ; i++)
+        if(unlikely(!p->cmdline[i])) p->cmdline[i] = ' ';
 
-       if(unlikely(debug))
-               fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
+    if(unlikely(debug))
+        fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
 
-       return 0;
+    return 0;
 
 cleanup:
-       // copy the command to the command line
-       strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
-       return 0;
+    // copy the command to the command line
+    strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
+    return 0;
 }
 
 int read_proc_pid_ownership(struct pid_stat *p) {
-       if(unlikely(!p->stat_filename)) {
-               error("pid %d does not have a stat_filename", p->pid);
-               return 1;
-       }
+    if(unlikely(!p->stat_filename)) {
+        error("pid %d does not have a stat_filename", p->pid);
+        return 1;
+    }
 
-       // ----------------------------------------
-       // read uid and gid
+    // ----------------------------------------
+    // read uid and gid
 
-       struct stat st;
-       if(stat(p->stat_filename, &st) != 0) {
-               error("Cannot stat file '%s'", p->stat_filename);
-               return 1;
-       }
+    struct stat st;
+    if(stat(p->stat_filename, &st) != 0) {
+        error("Cannot stat file '%s'", p->stat_filename);
+        return 1;
+    }
 
-       p->uid = st.st_uid;
-       p->gid = st.st_gid;
+    p->uid = st.st_uid;
+    p->gid = st.st_gid;
 
-       return 0;
+    return 0;
 }
 
 int read_proc_pid_stat(struct pid_stat *p) {
-       static procfile *ff = NULL;
-
-       if(unlikely(!p->stat_filename)) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
-               p->stat_filename = strdupz(filename);
-       }
-
-       int set_quotes = (!ff)?1:0;
-
-       ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
-       if(unlikely(!ff)) goto cleanup;
-
-       // if(set_quotes) procfile_set_quotes(ff, "()");
-       if(set_quotes) procfile_set_open_close(ff, "(", ")");
-
-       ff = procfile_readall(ff);
-       if(unlikely(!ff)) goto cleanup;
-
-       p->last_stat_collected_usec = p->stat_collected_usec;
-       p->stat_collected_usec = time_usec();
-       file_counter++;
-
-       // p->pid                       = atol(procfile_lineword(ff, 0, 0+i));
-
-       strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
-
-       // p->state                     = *(procfile_lineword(ff, 0, 2));
-       p->ppid                         = (int32_t) atol(procfile_lineword(ff, 0, 3));
-       // p->pgrp                      = atol(procfile_lineword(ff, 0, 4));
-       // p->session           = atol(procfile_lineword(ff, 0, 5));
-       // p->tty_nr            = atol(procfile_lineword(ff, 0, 6));
-       // p->tpgid                     = atol(procfile_lineword(ff, 0, 7));
-       // p->flags                     = strtoull(procfile_lineword(ff, 0, 8), NULL, 10);
-
-       unsigned long long last;
-
-       last = p->minflt_raw;
-       p->minflt_raw           = strtoull(procfile_lineword(ff, 0, 9), NULL, 10);
-       p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->cminflt_raw;
-       p->cminflt_raw          = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
-       p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->majflt_raw;
-       p->majflt_raw           = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
-       p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->cmajflt_raw;
-       p->cmajflt_raw          = strtoull(procfile_lineword(ff, 0, 12), NULL, 10);
-       p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->utime_raw;
-       p->utime_raw            = strtoull(procfile_lineword(ff, 0, 13), NULL, 10);
-       p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->stime_raw;
-       p->stime_raw            = strtoull(procfile_lineword(ff, 0, 14), NULL, 10);
-       p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->cutime_raw;
-       p->cutime_raw           = strtoull(procfile_lineword(ff, 0, 15), NULL, 10);
-       p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       last = p->cstime_raw;
-       p->cstime_raw           = strtoull(procfile_lineword(ff, 0, 16), NULL, 10);
-       p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-       // p->priority          = strtoull(procfile_lineword(ff, 0, 17), NULL, 10);
-       // p->nice                      = strtoull(procfile_lineword(ff, 0, 18), NULL, 10);
-       p->num_threads          = (int32_t) atol(procfile_lineword(ff, 0, 19));
-       // p->itrealvalue       = strtoull(procfile_lineword(ff, 0, 20), NULL, 10);
-       // p->starttime         = strtoull(procfile_lineword(ff, 0, 21), NULL, 10);
-       // p->vsize                     = strtoull(procfile_lineword(ff, 0, 22), NULL, 10);
-       p->rss                          = strtoull(procfile_lineword(ff, 0, 23), NULL, 10);
-       // p->rsslim            = strtoull(procfile_lineword(ff, 0, 24), NULL, 10);
-       // p->starcode          = strtoull(procfile_lineword(ff, 0, 25), NULL, 10);
-       // p->endcode           = strtoull(procfile_lineword(ff, 0, 26), NULL, 10);
-       // p->startstack        = strtoull(procfile_lineword(ff, 0, 27), NULL, 10);
-       // p->kstkesp           = strtoull(procfile_lineword(ff, 0, 28), NULL, 10);
-       // p->kstkeip           = strtoull(procfile_lineword(ff, 0, 29), NULL, 10);
-       // p->signal            = strtoull(procfile_lineword(ff, 0, 30), NULL, 10);
-       // p->blocked           = strtoull(procfile_lineword(ff, 0, 31), NULL, 10);
-       // p->sigignore         = strtoull(procfile_lineword(ff, 0, 32), NULL, 10);
-       // p->sigcatch          = strtoull(procfile_lineword(ff, 0, 33), NULL, 10);
-       // p->wchan                     = strtoull(procfile_lineword(ff, 0, 34), NULL, 10);
-       // p->nswap                     = strtoull(procfile_lineword(ff, 0, 35), NULL, 10);
-       // p->cnswap            = strtoull(procfile_lineword(ff, 0, 36), NULL, 10);
-       // p->exit_signal       = atol(procfile_lineword(ff, 0, 37));
-       // p->processor         = atol(procfile_lineword(ff, 0, 38));
-       // p->rt_priority       = strtoul(procfile_lineword(ff, 0, 39), NULL, 10);
-       // p->policy            = strtoul(procfile_lineword(ff, 0, 40), NULL, 10);
-       // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10);
+    static procfile *ff = NULL;
+
+    if(unlikely(!p->stat_filename)) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
+        p->stat_filename = strdupz(filename);
+    }
+
+    int set_quotes = (!ff)?1:0;
+
+    ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+    if(unlikely(!ff)) goto cleanup;
+
+    // if(set_quotes) procfile_set_quotes(ff, "()");
+    if(set_quotes) procfile_set_open_close(ff, "(", ")");
+
+    ff = procfile_readall(ff);
+    if(unlikely(!ff)) goto cleanup;
+
+    p->last_stat_collected_usec = p->stat_collected_usec;
+    p->stat_collected_usec = time_usec();
+    file_counter++;
+
+    // p->pid           = atol(procfile_lineword(ff, 0, 0+i));
+
+    strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+
+    // p->state         = *(procfile_lineword(ff, 0, 2));
+    p->ppid             = (int32_t) atol(procfile_lineword(ff, 0, 3));
+    // p->pgrp          = atol(procfile_lineword(ff, 0, 4));
+    // p->session       = atol(procfile_lineword(ff, 0, 5));
+    // p->tty_nr        = atol(procfile_lineword(ff, 0, 6));
+    // p->tpgid         = atol(procfile_lineword(ff, 0, 7));
+    // p->flags         = strtoull(procfile_lineword(ff, 0, 8), NULL, 10);
+
+    unsigned long long last;
+
+    last = p->minflt_raw;
+    p->minflt_raw       = strtoull(procfile_lineword(ff, 0, 9), NULL, 10);
+    p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->cminflt_raw;
+    p->cminflt_raw      = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
+    p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->majflt_raw;
+    p->majflt_raw       = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
+    p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->cmajflt_raw;
+    p->cmajflt_raw      = strtoull(procfile_lineword(ff, 0, 12), NULL, 10);
+    p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->utime_raw;
+    p->utime_raw        = strtoull(procfile_lineword(ff, 0, 13), NULL, 10);
+    p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->stime_raw;
+    p->stime_raw        = strtoull(procfile_lineword(ff, 0, 14), NULL, 10);
+    p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->cutime_raw;
+    p->cutime_raw       = strtoull(procfile_lineword(ff, 0, 15), NULL, 10);
+    p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    last = p->cstime_raw;
+    p->cstime_raw       = strtoull(procfile_lineword(ff, 0, 16), NULL, 10);
+    p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+    // p->priority      = strtoull(procfile_lineword(ff, 0, 17), NULL, 10);
+    // p->nice          = strtoull(procfile_lineword(ff, 0, 18), NULL, 10);
+    p->num_threads      = (int32_t) atol(procfile_lineword(ff, 0, 19));
+    // p->itrealvalue   = strtoull(procfile_lineword(ff, 0, 20), NULL, 10);
+    // p->starttime     = strtoull(procfile_lineword(ff, 0, 21), NULL, 10);
+    // p->vsize         = strtoull(procfile_lineword(ff, 0, 22), NULL, 10);
+    p->rss              = strtoull(procfile_lineword(ff, 0, 23), NULL, 10);
+    // p->rsslim        = strtoull(procfile_lineword(ff, 0, 24), NULL, 10);
+    // p->starcode      = strtoull(procfile_lineword(ff, 0, 25), NULL, 10);
+    // p->endcode       = strtoull(procfile_lineword(ff, 0, 26), NULL, 10);
+    // p->startstack    = strtoull(procfile_lineword(ff, 0, 27), NULL, 10);
+    // p->kstkesp       = strtoull(procfile_lineword(ff, 0, 28), NULL, 10);
+    // p->kstkeip       = strtoull(procfile_lineword(ff, 0, 29), NULL, 10);
+    // p->signal        = strtoull(procfile_lineword(ff, 0, 30), NULL, 10);
+    // p->blocked       = strtoull(procfile_lineword(ff, 0, 31), NULL, 10);
+    // p->sigignore     = strtoull(procfile_lineword(ff, 0, 32), NULL, 10);
+    // p->sigcatch      = strtoull(procfile_lineword(ff, 0, 33), NULL, 10);
+    // p->wchan         = strtoull(procfile_lineword(ff, 0, 34), NULL, 10);
+    // p->nswap         = strtoull(procfile_lineword(ff, 0, 35), NULL, 10);
+    // p->cnswap        = strtoull(procfile_lineword(ff, 0, 36), NULL, 10);
+    // p->exit_signal   = atol(procfile_lineword(ff, 0, 37));
+    // p->processor     = atol(procfile_lineword(ff, 0, 38));
+    // p->rt_priority   = strtoul(procfile_lineword(ff, 0, 39), NULL, 10);
+    // p->policy        = strtoul(procfile_lineword(ff, 0, 40), NULL, 10);
+    // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10);
 
     if(enable_guest_charts) {
         last = p->gtime_raw;
-        p->gtime_raw           = strtoull(procfile_lineword(ff, 0, 42), NULL, 10);
+        p->gtime_raw        = strtoull(procfile_lineword(ff, 0, 42), NULL, 10);
         p->gtime = (p->gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
         last = p->cgtime_raw;
-        p->cgtime_raw          = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
+        p->cgtime_raw       = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
         p->cgtime = (p->cgtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
 
         if (show_guest_time || p->gtime || p->cgtime) {
@@ -733,150 +733,150 @@ int read_proc_pid_stat(struct pid_stat *p) {
         }
     }
 
-       if(unlikely(debug || (p->target && p->target->debug)))
-               fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
-
-       if(unlikely(global_iterations_counter == 1)) {
-               p->minflt                       = 0;
-               p->cminflt                      = 0;
-               p->majflt                       = 0;
-               p->cmajflt                      = 0;
-               p->utime                        = 0;
-               p->stime                        = 0;
-               p->gtime                        = 0;
-               p->cutime                       = 0;
-               p->cstime                       = 0;
-               p->cgtime                       = 0;
-       }
+    if(unlikely(debug || (p->target && p->target->debug)))
+        fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+
+    if(unlikely(global_iterations_counter == 1)) {
+        p->minflt           = 0;
+        p->cminflt          = 0;
+        p->majflt           = 0;
+        p->cmajflt          = 0;
+        p->utime            = 0;
+        p->stime            = 0;
+        p->gtime            = 0;
+        p->cutime           = 0;
+        p->cstime           = 0;
+        p->cgtime           = 0;
+    }
 
-       return 0;
+    return 0;
 
 cleanup:
-       p->minflt                       = 0;
-       p->cminflt                      = 0;
-       p->majflt                       = 0;
-       p->cmajflt                      = 0;
-       p->utime                        = 0;
-       p->stime                        = 0;
-       p->gtime                        = 0;
-       p->cutime                       = 0;
-       p->cstime                       = 0;
-       p->cgtime                       = 0;
-       p->num_threads          = 0;
-       p->rss                          = 0;
-       return 1;
+    p->minflt           = 0;
+    p->cminflt          = 0;
+    p->majflt           = 0;
+    p->cmajflt          = 0;
+    p->utime            = 0;
+    p->stime            = 0;
+    p->gtime            = 0;
+    p->cutime           = 0;
+    p->cstime           = 0;
+    p->cgtime           = 0;
+    p->num_threads      = 0;
+    p->rss              = 0;
+    return 1;
 }
 
 int read_proc_pid_statm(struct pid_stat *p) {
-       static procfile *ff = NULL;
+    static procfile *ff = NULL;
 
-       if(unlikely(!p->statm_filename)) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
-               p->statm_filename = strdupz(filename);
-       }
+    if(unlikely(!p->statm_filename)) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
+        p->statm_filename = strdupz(filename);
+    }
 
-       ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
-       if(unlikely(!ff)) goto cleanup;
+    ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+    if(unlikely(!ff)) goto cleanup;
 
-       ff = procfile_readall(ff);
-       if(unlikely(!ff)) goto cleanup;
+    ff = procfile_readall(ff);
+    if(unlikely(!ff)) goto cleanup;
 
-       file_counter++;
+    file_counter++;
 
-       p->statm_size                   = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
-       p->statm_resident               = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-       p->statm_share                  = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
-       p->statm_text                   = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
-       p->statm_lib                    = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
-       p->statm_data                   = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
-       p->statm_dirty                  = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
+    p->statm_size           = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
+    p->statm_resident       = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
+    p->statm_share          = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
+    p->statm_text           = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
+    p->statm_lib            = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
+    p->statm_data           = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
+    p->statm_dirty          = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
 
-       return 0;
+    return 0;
 
 cleanup:
-       p->statm_size                   = 0;
-       p->statm_resident               = 0;
-       p->statm_share                  = 0;
-       p->statm_text                   = 0;
-       p->statm_lib                    = 0;
-       p->statm_data                   = 0;
-       p->statm_dirty                  = 0;
-       return 1;
+    p->statm_size           = 0;
+    p->statm_resident       = 0;
+    p->statm_share          = 0;
+    p->statm_text           = 0;
+    p->statm_lib            = 0;
+    p->statm_data           = 0;
+    p->statm_dirty          = 0;
+    return 1;
 }
 
 int read_proc_pid_io(struct pid_stat *p) {
-       static procfile *ff = NULL;
+    static procfile *ff = NULL;
 
-       if(unlikely(!p->io_filename)) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
-               p->io_filename = strdupz(filename);
-       }
+    if(unlikely(!p->io_filename)) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
+        p->io_filename = strdupz(filename);
+    }
 
-       // open the file
-       ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
-       if(unlikely(!ff)) goto cleanup;
+    // open the file
+    ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+    if(unlikely(!ff)) goto cleanup;
 
-       ff = procfile_readall(ff);
-       if(unlikely(!ff)) goto cleanup;
+    ff = procfile_readall(ff);
+    if(unlikely(!ff)) goto cleanup;
 
-       file_counter++;
+    file_counter++;
 
-       p->last_io_collected_usec = p->io_collected_usec;
-       p->io_collected_usec = time_usec();
+    p->last_io_collected_usec = p->io_collected_usec;
+    p->io_collected_usec = time_usec();
 
-       unsigned long long last;
+    unsigned long long last;
 
-       last = p->io_logical_bytes_read_raw;
-       p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-       p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_logical_bytes_read_raw;
+    p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
+    p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_logical_bytes_written_raw;
-       p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
-       p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_logical_bytes_written_raw;
+    p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
+    p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_read_calls_raw;
-       p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
-       p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_read_calls_raw;
+    p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
+    p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_write_calls_raw;
-       p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
-       p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_write_calls_raw;
+    p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
+    p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_storage_bytes_read_raw;
-       p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
-       p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_storage_bytes_read_raw;
+    p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
+    p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_storage_bytes_written_raw;
-       p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
-       p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_storage_bytes_written_raw;
+    p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
+    p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       last = p->io_cancelled_write_bytes_raw;
-       p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
-       p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
+    last = p->io_cancelled_write_bytes_raw;
+    p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
+    p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
 
-       if(unlikely(global_iterations_counter == 1)) {
-               p->io_logical_bytes_read                = 0;
-               p->io_logical_bytes_written     = 0;
-               p->io_read_calls                                = 0;
-               p->io_write_calls                               = 0;
-               p->io_storage_bytes_read                = 0;
-               p->io_storage_bytes_written     = 0;
-               p->io_cancelled_write_bytes             = 0;
-       }
+    if(unlikely(global_iterations_counter == 1)) {
+        p->io_logical_bytes_read        = 0;
+        p->io_logical_bytes_written     = 0;
+        p->io_read_calls                = 0;
+        p->io_write_calls               = 0;
+        p->io_storage_bytes_read        = 0;
+        p->io_storage_bytes_written     = 0;
+        p->io_cancelled_write_bytes     = 0;
+    }
 
-       return 0;
+    return 0;
 
 cleanup:
-       p->io_logical_bytes_read                = 0;
-       p->io_logical_bytes_written     = 0;
-       p->io_read_calls                                = 0;
-       p->io_write_calls                               = 0;
-       p->io_storage_bytes_read                = 0;
-       p->io_storage_bytes_written     = 0;
-       p->io_cancelled_write_bytes             = 0;
-       return 1;
+    p->io_logical_bytes_read        = 0;
+    p->io_logical_bytes_written     = 0;
+    p->io_read_calls                = 0;
+    p->io_write_calls               = 0;
+    p->io_storage_bytes_read        = 0;
+    p->io_storage_bytes_written     = 0;
+    p->io_cancelled_write_bytes     = 0;
+    return 1;
 }
 
 unsigned long long global_utime = 0;
@@ -884,38 +884,38 @@ unsigned long long global_stime = 0;
 unsigned long long global_gtime = 0;
 
 int read_proc_stat() {
-       static char filename[FILENAME_MAX + 1] = "";
-       static procfile *ff = NULL;
-       static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0;
-
-       if(unlikely(!ff)) {
-               snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
-               ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
-               if(unlikely(!ff)) goto cleanup;
-       }
+    static char filename[FILENAME_MAX + 1] = "";
+    static procfile *ff = NULL;
+    static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0;
+
+    if(unlikely(!ff)) {
+        snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
+        ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
+        if(unlikely(!ff)) goto cleanup;
+    }
 
-       ff = procfile_readall(ff);
-       if(unlikely(!ff)) goto cleanup;
+    ff = procfile_readall(ff);
+    if(unlikely(!ff)) goto cleanup;
 
-       last_collected_usec = collected_usec;
-       collected_usec = time_usec();
+    last_collected_usec = collected_usec;
+    collected_usec = time_usec();
 
-       file_counter++;
+    file_counter++;
 
-       unsigned long long last;
+    unsigned long long last;
 
-       last = utime_raw;
-       utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
-       global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    last = utime_raw;
+    utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
+    global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     // nice time, on user time
-       last = ntime_raw;
-       ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
-       global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    last = ntime_raw;
+    ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
+    global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
-       last = stime_raw;
-       stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
-       global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
+    last = stime_raw;
+    stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
+    global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
 
     last = gtime_raw;
     gtime_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
@@ -931,19 +931,19 @@ int read_proc_stat() {
         global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
     }
 
-       if(unlikely(global_iterations_counter == 1)) {
-               global_utime = 0;
-               global_stime = 0;
-               global_gtime = 0;
-       }
+    if(unlikely(global_iterations_counter == 1)) {
+        global_utime = 0;
+        global_stime = 0;
+        global_gtime = 0;
+    }
 
-       return 0;
+    return 0;
 
 cleanup:
-       global_utime = 0;
-       global_stime = 0;
-       global_gtime = 0;
-       return 1;
+    global_utime = 0;
+    global_stime = 0;
+    global_gtime = 0;
+    return 1;
 }
 
 
@@ -955,15 +955,15 @@ cleanup:
 #define FILE_DESCRIPTORS_INCREASE_STEP 100
 
 struct file_descriptor {
-       avl avl;
+    avl avl;
 #ifdef NETDATA_INTERNAL_CHECKS
-       uint32_t magic;
+    uint32_t magic;
 #endif /* NETDATA_INTERNAL_CHECKS */
-       uint32_t hash;
-       const char *name;
-       int type;
-       int count;
-       int pos;
+    uint32_t hash;
+    const char *name;
+    int type;
+    int count;
+    int pos;
 } *all_files = NULL;
 
 int all_files_len = 0;
@@ -971,38 +971,38 @@ int all_files_size = 0;
 
 int file_descriptor_compare(void* a, void* b) {
 #ifdef NETDATA_INTERNAL_CHECKS
-       if(((struct file_descriptor *)a)->magic != 0x0BADCAFE || ((struct file_descriptor *)b)->magic != 0x0BADCAFE)
-               error("Corrupted index data detected. Please report this.");
+    if(((struct file_descriptor *)a)->magic != 0x0BADCAFE || ((struct file_descriptor *)b)->magic != 0x0BADCAFE)
+        error("Corrupted index data detected. Please report this.");
 #endif /* NETDATA_INTERNAL_CHECKS */
 
-       if(((struct file_descriptor *)a)->hash < ((struct file_descriptor *)b)->hash)
-               return -1;
+    if(((struct file_descriptor *)a)->hash < ((struct file_descriptor *)b)->hash)
+        return -1;
 
-       else if(((struct file_descriptor *)a)->hash > ((struct file_descriptor *)b)->hash)
-               return 1;
+    else if(((struct file_descriptor *)a)->hash > ((struct file_descriptor *)b)->hash)
+        return 1;
 
-       else
-               return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name);
+    else
+        return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name);
 }
 
 int file_descriptor_iterator(avl *a) { if(a) {}; return 0; }
 
 avl_tree all_files_index = {
-               NULL,
-               file_descriptor_compare
+        NULL,
+        file_descriptor_compare
 };
 
 static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) {
-       struct file_descriptor tmp;
-       tmp.hash = (hash)?hash:simple_hash(name);
-       tmp.name = name;
-       tmp.count = 0;
-       tmp.pos = 0;
+    struct file_descriptor tmp;
+    tmp.hash = (hash)?hash:simple_hash(name);
+    tmp.name = name;
+    tmp.count = 0;
+    tmp.pos = 0;
 #ifdef NETDATA_INTERNAL_CHECKS
-       tmp.magic = 0x0BADCAFE;
+    tmp.magic = 0x0BADCAFE;
 #endif /* NETDATA_INTERNAL_CHECKS */
 
-       return (struct file_descriptor *)avl_search(&all_files_index, (avl *) &tmp);
+    return (struct file_descriptor *)avl_search(&all_files_index, (avl *) &tmp);
 }
 
 #define file_descriptor_add(fd) avl_insert(&all_files_index, (avl *)(fd))
@@ -1020,526 +1020,526 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
 
 void file_descriptor_not_used(int id)
 {
-       if(id > 0 && id < all_files_size) {
+    if(id > 0 && id < all_files_size) {
 
 #ifdef NETDATA_INTERNAL_CHECKS
-               if(all_files[id].magic != 0x0BADCAFE) {
-                       error("Ignoring request to remove empty file id %d.", id);
-                       return;
-               }
+        if(all_files[id].magic != 0x0BADCAFE) {
+            error("Ignoring request to remove empty file id %d.", id);
+            return;
+        }
 #endif /* NETDATA_INTERNAL_CHECKS */
 
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
 
-               if(all_files[id].count > 0) {
-                       all_files[id].count--;
+        if(all_files[id].count > 0) {
+            all_files[id].count--;
 
-                       if(!all_files[id].count) {
-                               if(unlikely(debug))
-                                       fprintf(stderr, "apps.plugin:   >> slot %d is empty.\n", id);
+            if(!all_files[id].count) {
+                if(unlikely(debug))
+                    fprintf(stderr, "apps.plugin:   >> slot %d is empty.\n", id);
 
-                               file_descriptor_remove(&all_files[id]);
+                file_descriptor_remove(&all_files[id]);
 #ifdef NETDATA_INTERNAL_CHECKS
-                               all_files[id].magic = 0x00000000;
+                all_files[id].magic = 0x00000000;
 #endif /* NETDATA_INTERNAL_CHECKS */
-                               all_files_len--;
-                       }
-               }
-               else
-                       error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
-       }
-       else    error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
+                all_files_len--;
+            }
+        }
+        else
+            error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
+    }
+    else    error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
 }
 
 int file_descriptor_find_or_add(const char *name)
 {
-       static int last_pos = 0;
-       uint32_t hash = simple_hash(name);
-
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
-
-       struct file_descriptor *fd = file_descriptor_find(name, hash);
-       if(fd) {
-               // found
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin:   >> found on slot %d\n", fd->pos);
-
-               fd->count++;
-               return fd->pos;
-       }
-       // not found
-
-       // check we have enough memory to add it
-       if(!all_files || all_files_len == all_files_size) {
-               void *old = all_files;
-               int i;
-
-               // there is no empty slot
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
-
-               all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
-
-               // if the address changed, we have to rebuild the index
-               // since all pointers are now invalid
-               if(old && old != (void *)all_files) {
-                       if(unlikely(debug))
-                               fprintf(stderr, "apps.plugin:   >> re-indexing.\n");
-
-                       all_files_index.root = NULL;
-                       for(i = 0; i < all_files_size; i++) {
-                               if(!all_files[i].count) continue;
-                               file_descriptor_add(&all_files[i]);
-                       }
-
-                       if(unlikely(debug))
-                               fprintf(stderr, "apps.plugin:   >> re-indexing done.\n");
-               }
-
-               for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
-                       all_files[i].count = 0;
-                       all_files[i].name = NULL;
+    static int last_pos = 0;
+    uint32_t hash = simple_hash(name);
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
+
+    struct file_descriptor *fd = file_descriptor_find(name, hash);
+    if(fd) {
+        // found
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin:   >> found on slot %d\n", fd->pos);
+
+        fd->count++;
+        return fd->pos;
+    }
+    // not found
+
+    // check we have enough memory to add it
+    if(!all_files || all_files_len == all_files_size) {
+        void *old = all_files;
+        int i;
+
+        // there is no empty slot
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
+
+        all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
+
+        // if the address changed, we have to rebuild the index
+        // since all pointers are now invalid
+        if(old && old != (void *)all_files) {
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin:   >> re-indexing.\n");
+
+            all_files_index.root = NULL;
+            for(i = 0; i < all_files_size; i++) {
+                if(!all_files[i].count) continue;
+                file_descriptor_add(&all_files[i]);
+            }
+
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin:   >> re-indexing done.\n");
+        }
+
+        for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
+            all_files[i].count = 0;
+            all_files[i].name = NULL;
 #ifdef NETDATA_INTERNAL_CHECKS
-                       all_files[i].magic = 0x00000000;
+            all_files[i].magic = 0x00000000;
 #endif /* NETDATA_INTERNAL_CHECKS */
-                       all_files[i].pos = i;
-               }
+            all_files[i].pos = i;
+        }
 
-               if(!all_files_size) all_files_len = 1;
-               all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
-       }
+        if(!all_files_size) all_files_len = 1;
+        all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
+    }
 
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin:   >> searching for empty slot.\n");
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin:   >> searching for empty slot.\n");
 
-       // search for an empty slot
-       int i, c;
-       for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) {
-               if(c >= all_files_size) c = 0;
-               if(c == 0) continue;
+    // search for an empty slot
+    int i, c;
+    for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) {
+        if(c >= all_files_size) c = 0;
+        if(c == 0) continue;
 
-               if(!all_files[c].count) {
-                       if(unlikely(debug))
-                               fprintf(stderr, "apps.plugin:   >> Examining slot %d.\n", c);
+        if(!all_files[c].count) {
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin:   >> Examining slot %d.\n", c);
 
 #ifdef NETDATA_INTERNAL_CHECKS
-                       if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
-                               error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
+            if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
+                error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
 #endif /* NETDATA_INTERNAL_CHECKS */
 
-                       if(unlikely(debug))
-                               fprintf(stderr, "apps.plugin:   >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
-
-                       if(all_files[c].name) freez((void *)all_files[c].name);
-                       all_files[c].name = NULL;
-                       last_pos = c;
-                       break;
-               }
-       }
-       if(i == all_files_size) {
-               fatal("We should find an empty slot, but there isn't any");
-               exit(1);
-       }
-
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin:   >> updating slot %d.\n", c);
-
-       all_files_len++;
-
-       // else we have an empty slot in 'c'
-
-       int type;
-       if(name[0] == '/') type = FILETYPE_FILE;
-       else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
-       else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
-       else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
-       else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
-       else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
-       else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
-       else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
-       else if(strncmp(name, "anon_inode:", 11) == 0) {
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
-
-               type = FILETYPE_OTHER;
-       }
-       else {
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
-
-               type = FILETYPE_OTHER;
-       }
-
-       all_files[c].name = strdupz(name);
-       all_files[c].hash = hash;
-       all_files[c].type = type;
-       all_files[c].pos  = c;
-       all_files[c].count = 1;
+            if(unlikely(debug))
+                fprintf(stderr, "apps.plugin:   >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
+
+            if(all_files[c].name) freez((void *)all_files[c].name);
+            all_files[c].name = NULL;
+            last_pos = c;
+            break;
+        }
+    }
+    if(i == all_files_size) {
+        fatal("We should find an empty slot, but there isn't any");
+        exit(1);
+    }
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin:   >> updating slot %d.\n", c);
+
+    all_files_len++;
+
+    // else we have an empty slot in 'c'
+
+    int type;
+    if(name[0] == '/') type = FILETYPE_FILE;
+    else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
+    else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
+    else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
+    else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
+    else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
+    else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
+    else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
+    else if(strncmp(name, "anon_inode:", 11) == 0) {
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
+
+        type = FILETYPE_OTHER;
+    }
+    else {
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
+
+        type = FILETYPE_OTHER;
+    }
+
+    all_files[c].name = strdupz(name);
+    all_files[c].hash = hash;
+    all_files[c].type = type;
+    all_files[c].pos  = c;
+    all_files[c].count = 1;
 #ifdef NETDATA_INTERNAL_CHECKS
-       all_files[c].magic = 0x0BADCAFE;
+    all_files[c].magic = 0x0BADCAFE;
 #endif /* NETDATA_INTERNAL_CHECKS */
-       file_descriptor_add(&all_files[c]);
+    file_descriptor_add(&all_files[c]);
 
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
 
-       return c;
+    return c;
 }
 
 int read_pid_file_descriptors(struct pid_stat *p) {
-       char dirname[FILENAME_MAX+1];
-
-       snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
-       DIR *fds = opendir(dirname);
-       if(fds) {
-               int c;
-               struct dirent *de;
-               char fdname[FILENAME_MAX + 1];
-               char linkname[FILENAME_MAX + 1];
-
-               // make the array negative
-               for(c = 0 ; c < p->fds_size ; c++)
-                       p->fds[c] = -p->fds[c];
-
-               while((de = readdir(fds))) {
-                       if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-                               continue;
-
-                       // check if the fds array is small
-                       int fdid = atoi(de->d_name);
-                       if(fdid < 0) continue;
-                       if(fdid >= p->fds_size) {
-                               // it is small, extend it
-                               if(unlikely(debug))
-                                       fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
-
-                               p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
-                               if(!p->fds) {
-                                       fatal("Cannot re-allocate fds for %s", p->comm);
-                                       break;
-                               }
-
-                               // and initialize it
-                               for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
-                               p->fds_size = fdid + 100;
-                       }
-
-                       if(p->fds[fdid] == 0) {
-                               // we don't know this fd, get it
-
-                               sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
-                               ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
-                               if(l == -1) {
-                                       if(debug || (p->target && p->target->debug)) {
-                                               if(debug || (p->target && p->target->debug))
-                                                       error("Cannot read link %s", fdname);
-                                       }
-                                       continue;
-                               }
-                               linkname[l] = '\0';
-                               file_counter++;
-
-                               // if another process already has this, we will get
-                               // the same id
-                               p->fds[fdid] = file_descriptor_find_or_add(linkname);
-                       }
-
-                       // else make it positive again, we need it
-                       // of course, the actual file may have changed, but we don't care so much
-                       // FIXME: we could compare the inode as returned by readdir direct structure
-                       else p->fds[fdid] = -p->fds[fdid];
-               }
-               closedir(fds);
-
-               // remove all the negative file descriptors
-               for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
-                       file_descriptor_not_used(-p->fds[c]);
-                       p->fds[c] = 0;
-               }
-       }
-       else return 1;
-
-       return 0;
+    char dirname[FILENAME_MAX+1];
+
+    snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
+    DIR *fds = opendir(dirname);
+    if(fds) {
+        int c;
+        struct dirent *de;
+        char fdname[FILENAME_MAX + 1];
+        char linkname[FILENAME_MAX + 1];
+
+        // make the array negative
+        for(c = 0 ; c < p->fds_size ; c++)
+            p->fds[c] = -p->fds[c];
+
+        while((de = readdir(fds))) {
+            if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+                continue;
+
+            // check if the fds array is small
+            int fdid = atoi(de->d_name);
+            if(fdid < 0) continue;
+            if(fdid >= p->fds_size) {
+                // it is small, extend it
+                if(unlikely(debug))
+                    fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
+
+                p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
+                if(!p->fds) {
+                    fatal("Cannot re-allocate fds for %s", p->comm);
+                    break;
+                }
+
+                // and initialize it
+                for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
+                p->fds_size = fdid + 100;
+            }
+
+            if(p->fds[fdid] == 0) {
+                // we don't know this fd, get it
+
+                sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
+                ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
+                if(l == -1) {
+                    if(debug || (p->target && p->target->debug)) {
+                        if(debug || (p->target && p->target->debug))
+                            error("Cannot read link %s", fdname);
+                    }
+                    continue;
+                }
+                linkname[l] = '\0';
+                file_counter++;
+
+                // if another process already has this, we will get
+                // the same id
+                p->fds[fdid] = file_descriptor_find_or_add(linkname);
+            }
+
+            // else make it positive again, we need it
+            // of course, the actual file may have changed, but we don't care so much
+            // FIXME: we could compare the inode as returned by readdir direct structure
+            else p->fds[fdid] = -p->fds[fdid];
+        }
+        closedir(fds);
+
+        // remove all the negative file descriptors
+        for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
+            file_descriptor_not_used(-p->fds[c]);
+            p->fds[c] = 0;
+        }
+    }
+    else return 1;
+
+    return 0;
 }
 
 // ----------------------------------------------------------------------------
 
 int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
-       char *prefix = "\\_ ";
-       int indent = 0;
-
-       if(p->parent)
-               indent = print_process_and_parents(p->parent, p->stat_collected_usec);
-       else
-               prefix = " > ";
-
-       char buffer[indent + 1];
-       int i;
-
-       for(i = 0; i < indent ;i++) buffer[i] = ' ';
-       buffer[i] = '\0';
-
-       fprintf(stderr, "  %s %s%s (%d %s %lld"
-               , buffer
-               , prefix
-               , p->comm
-               , p->pid
-               , p->updated?"running":"exited"
-               , (long long)p->stat_collected_usec - (long long)time
-               );
-
-       if(p->utime)   fprintf(stderr, " utime=%llu",   p->utime);
-       if(p->stime)   fprintf(stderr, " stime=%llu",   p->stime);
-       if(p->gtime)   fprintf(stderr, " gtime=%llu",   p->gtime);
-       if(p->cutime)  fprintf(stderr, " cutime=%llu",  p->cutime);
-       if(p->cstime)  fprintf(stderr, " cstime=%llu",  p->cstime);
-       if(p->cgtime)  fprintf(stderr, " cgtime=%llu",  p->cgtime);
-       if(p->minflt)  fprintf(stderr, " minflt=%llu",  p->minflt);
-       if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
-       if(p->majflt)  fprintf(stderr, " majflt=%llu",  p->majflt);
-       if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
-       fprintf(stderr, ")\n");
-
-       return indent + 1;
+    char *prefix = "\\_ ";
+    int indent = 0;
+
+    if(p->parent)
+        indent = print_process_and_parents(p->parent, p->stat_collected_usec);
+    else
+        prefix = " > ";
+
+    char buffer[indent + 1];
+    int i;
+
+    for(i = 0; i < indent ;i++) buffer[i] = ' ';
+    buffer[i] = '\0';
+
+    fprintf(stderr, "  %s %s%s (%d %s %lld"
+        , buffer
+        , prefix
+        , p->comm
+        , p->pid
+        , p->updated?"running":"exited"
+        , (long long)p->stat_collected_usec - (long long)time
+        );
+
+    if(p->utime)   fprintf(stderr, " utime=%llu",   p->utime);
+    if(p->stime)   fprintf(stderr, " stime=%llu",   p->stime);
+    if(p->gtime)   fprintf(stderr, " gtime=%llu",   p->gtime);
+    if(p->cutime)  fprintf(stderr, " cutime=%llu",  p->cutime);
+    if(p->cstime)  fprintf(stderr, " cstime=%llu",  p->cstime);
+    if(p->cgtime)  fprintf(stderr, " cgtime=%llu",  p->cgtime);
+    if(p->minflt)  fprintf(stderr, " minflt=%llu",  p->minflt);
+    if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
+    if(p->majflt)  fprintf(stderr, " majflt=%llu",  p->majflt);
+    if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
+    fprintf(stderr, ")\n");
+
+    return indent + 1;
 }
 
 void print_process_tree(struct pid_stat *p, char *msg) {
-       log_date(stderr);
-       fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
-       print_process_and_parents(p, p->stat_collected_usec);
+    log_date(stderr);
+    fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
+    print_process_and_parents(p, p->stat_collected_usec);
 }
 
 void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
-       int found = 0;
-       struct pid_stat *p = NULL;
-
-       for(p = root_of_pids; p ; p = p->next) {
-               if(p == pe) continue;
-
-               switch(type) {
-                       case 1:
-                               if(p->cminflt > lost) {
-                                       fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
-                                       found++;
-                               }
-                               break;
-                               
-                       case 2:
-                               if(p->cmajflt > lost) {
-                                       fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
-                                       found++;
-                               }
-                               break;
-                               
-                       case 3:
-                               if(p->cutime > lost) {
-                                       fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
-                                       found++;
-                               }
-                               break;
-
-                       case 4:
-                               if(p->cstime > lost) {
-                                       fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
-                                       found++;
-                               }
-                               break;
-
-                       case 5:
-                               if(p->cgtime > lost) {
-                                       fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
-                                       found++;
-                               }
-                               break;
-               }
-       }
-
-       if(!found) {
-               switch(type) {
-                       case 1:
-                               fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
-                               break;
-                               
-                       case 2:
-                               fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
-                               break;
-                               
-                       case 3:
-                               fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
-                               break;
-
-                       case 4:
-                               fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
-                               break;
-
-                       case 5:
-                               fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
-                               break;
-               }
-       }
+    int found = 0;
+    struct pid_stat *p = NULL;
+
+    for(p = root_of_pids; p ; p = p->next) {
+        if(p == pe) continue;
+
+        switch(type) {
+            case 1:
+                if(p->cminflt > lost) {
+                    fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+                    found++;
+                }
+                break;
+                
+            case 2:
+                if(p->cmajflt > lost) {
+                    fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+                    found++;
+                }
+                break;
+                
+            case 3:
+                if(p->cutime > lost) {
+                    fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+                    found++;
+                }
+                break;
+
+            case 4:
+                if(p->cstime > lost) {
+                    fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+                    found++;
+                }
+                break;
+
+            case 5:
+                if(p->cgtime > lost) {
+                    fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
+                    found++;
+                }
+                break;
+        }
+    }
+
+    if(!found) {
+        switch(type) {
+            case 1:
+                fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+                break;
+                
+            case 2:
+                fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+                break;
+                
+            case 3:
+                fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+                break;
+
+            case 4:
+                fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+                break;
+
+            case 5:
+                fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
+                break;
+        }
+    }
 }
 
 unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
-       unsigned long long absorbed = 0;
-
-       if(*field > *pfield) {
-               absorbed += *pfield;
-               *field -= *pfield;
-               *pfield = 0;
-       }
-       else {
-               absorbed += *field;
-               *pfield -= *field;
-               *field = 0;
-       }
-
-       return absorbed;
+    unsigned long long absorbed = 0;
+
+    if(*field > *pfield) {
+        absorbed += *pfield;
+        *field -= *pfield;
+        *pfield = 0;
+    }
+    else {
+        absorbed += *field;
+        *pfield -= *field;
+        *field = 0;
+    }
+
+    return absorbed;
 }
 
 void process_exited_processes() {
-       struct pid_stat *p;
-
-       for(p = root_of_pids; p ; p = p->next) {
-               if(p->updated || !p->stat_collected_usec)
-                       continue;
-
-               struct pid_stat *pp = p->parent;
-
-               unsigned long long utime  = (p->utime_raw + p->cutime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-               unsigned long long stime  = (p->stime_raw + p->cstime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-               unsigned long long gtime  = (p->gtime_raw + p->cgtime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-               unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-               unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
-
-               if(utime + stime + gtime + minflt + majflt == 0)
-                       continue;
-
-               if(unlikely(debug)) {
-                       log_date(stderr);
-                       fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
-                               , p->comm
-                               , p->pid
-                               , p->updated?"running":"exited"
-                               , utime
-                               , stime
-                               , gtime
-                               , minflt
-                               , majflt
-                               );
-                       print_process_tree(p, "Searching parents");
-               }
-
-               for(pp = p->parent; pp ; pp = pp->parent) {
-                       if(!pp->updated) continue;
-
-                       unsigned long long absorbed;
-                       absorbed = remove_exited_child_from_parent(&utime,  &pp->cutime);
-                       if(unlikely(debug && absorbed))
-                               fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
-
-                       absorbed = remove_exited_child_from_parent(&stime,  &pp->cstime);
-                       if(unlikely(debug && absorbed))
-                               fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
-
-                       absorbed = remove_exited_child_from_parent(&gtime,  &pp->cgtime);
-                       if(unlikely(debug && absorbed))
-                               fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
-
-                       absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
-                       if(unlikely(debug && absorbed))
-                               fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
-
-                       absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
-                       if(unlikely(debug && absorbed))
-                               fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
-               }
-
-               if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
-                       if(unlikely(debug)) {
-                               if(utime)  find_lost_child_debug(p, utime,  3);
-                               if(stime)  find_lost_child_debug(p, stime,  4);
-                               if(gtime)  find_lost_child_debug(p, gtime,  5);
-                               if(minflt) find_lost_child_debug(p, minflt, 1);
-                               if(majflt) find_lost_child_debug(p, majflt, 2);
-                       }
-
-                       p->keep = 1;
-
-                       if(unlikely(debug))
-                               fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
-                                       , p->comm
-                                       , p->pid
-                                       , p->updated?"running":"exited"
-                                       , utime
-                                       , stime
-                                       , gtime
-                                       , minflt
-                                       , majflt
-                                       );
-
-                       for(pp = p->parent; pp ; pp = pp->parent) {
-                               if(pp->updated) break;
-                               pp->keep = 1;
-
-                               if(unlikely(debug))
-                                       fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n"
-                                               , pp->comm
-                                               , pp->pid
-                                               , pp->updated?"running":"exited"
-                                               );
-                       }
-
-                       p->utime_raw   = utime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-                       p->stime_raw   = stime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-                       p->gtime_raw   = gtime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-                       p->minflt_raw  = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-                       p->majflt_raw  = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
-                       p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
-
-                       if(unlikely(debug))
-                               fprintf(stderr, "\n");
-               }
-               else if(unlikely(debug)) {
-                       fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n"
-                               , p->comm
-                               , p->pid
-                               , p->updated?"running":"exited"
-                               );
-               }
-       }
+    struct pid_stat *p;
+
+    for(p = root_of_pids; p ; p = p->next) {
+        if(p->updated || !p->stat_collected_usec)
+            continue;
+
+        struct pid_stat *pp = p->parent;
+
+        unsigned long long utime  = (p->utime_raw + p->cutime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        unsigned long long stime  = (p->stime_raw + p->cstime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        unsigned long long gtime  = (p->gtime_raw + p->cgtime_raw)   * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+        unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
+
+        if(utime + stime + gtime + minflt + majflt == 0)
+            continue;
+
+        if(unlikely(debug)) {
+            log_date(stderr);
+            fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+                , p->comm
+                , p->pid
+                , p->updated?"running":"exited"
+                , utime
+                , stime
+                , gtime
+                , minflt
+                , majflt
+                );
+            print_process_tree(p, "Searching parents");
+        }
+
+        for(pp = p->parent; pp ; pp = pp->parent) {
+            if(!pp->updated) continue;
+
+            unsigned long long absorbed;
+            absorbed = remove_exited_child_from_parent(&utime,  &pp->cutime);
+            if(unlikely(debug && absorbed))
+                fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
+
+            absorbed = remove_exited_child_from_parent(&stime,  &pp->cstime);
+            if(unlikely(debug && absorbed))
+                fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
+
+            absorbed = remove_exited_child_from_parent(&gtime,  &pp->cgtime);
+            if(unlikely(debug && absorbed))
+                fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
+
+            absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
+            if(unlikely(debug && absorbed))
+                fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
+
+            absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
+            if(unlikely(debug && absorbed))
+                fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
+        }
+
+        if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
+            if(unlikely(debug)) {
+                if(utime)  find_lost_child_debug(p, utime,  3);
+                if(stime)  find_lost_child_debug(p, stime,  4);
+                if(gtime)  find_lost_child_debug(p, gtime,  5);
+                if(minflt) find_lost_child_debug(p, minflt, 1);
+                if(majflt) find_lost_child_debug(p, majflt, 2);
+            }
+
+            p->keep = 1;
+
+            if(unlikely(debug))
+                fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
+                    , p->comm
+                    , p->pid
+                    , p->updated?"running":"exited"
+                    , utime
+                    , stime
+                    , gtime
+                    , minflt
+                    , majflt
+                    );
+
+            for(pp = p->parent; pp ; pp = pp->parent) {
+                if(pp->updated) break;
+                pp->keep = 1;
+
+                if(unlikely(debug))
+                    fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n"
+                        , pp->comm
+                        , pp->pid
+                        , pp->updated?"running":"exited"
+                        );
+            }
+
+            p->utime_raw   = utime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->stime_raw   = stime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->gtime_raw   = gtime  * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->minflt_raw  = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->majflt_raw  = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
+            p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
+
+            if(unlikely(debug))
+                fprintf(stderr, "\n");
+        }
+        else if(unlikely(debug)) {
+            fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n"
+                , p->comm
+                , p->pid
+                , p->updated?"running":"exited"
+                );
+        }
+    }
 }
 
 void link_all_processes_to_their_parents(void) {
-       struct pid_stat *p, *pp;
-
-       // link all children to their parents
-       // and update children count on parents
-       for(p = root_of_pids; p ; p = p->next) {
-               // for each process found
-
-               p->sortlist = 0;
-               p->parent = NULL;
-
-               if(unlikely(!p->ppid)) {
-                       p->parent = NULL;
-                       continue;
-               }
-
-               pp = all_pids[p->ppid];
-               if(likely(pp)) {
-                       p->parent = pp;
-                       pp->children_count++;
-
-                       if(unlikely(debug || (p->target && p->target->debug)))
-                               fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
-               }
-               else {
-                       p->parent = NULL;
-                       error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
-               }
-       }
+    struct pid_stat *p, *pp;
+
+    // link all children to their parents
+    // and update children count on parents
+    for(p = root_of_pids; p ; p = p->next) {
+        // for each process found
+
+        p->sortlist = 0;
+        p->parent = NULL;
+
+        if(unlikely(!p->ppid)) {
+            p->parent = NULL;
+            continue;
+        }
+
+        pp = all_pids[p->ppid];
+        if(likely(pp)) {
+            p->parent = pp;
+            pp->children_count++;
+
+            if(unlikely(debug || (p->target && p->target->debug)))
+                fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
+        }
+        else {
+            p->parent = NULL;
+            error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
+        }
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -1562,203 +1562,203 @@ void link_all_processes_to_their_parents(void) {
 
 static int compar_pid(const void *pid1, const void *pid2) {
 
-       struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
-       struct pid_stat *p2 = all_pids[*((pid_t *)pid2)];
+    struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
+    struct pid_stat *p2 = all_pids[*((pid_t *)pid2)];
 
-       if(p1->sortlist > p2->sortlist)
-               return -1;
-       else
-               return 1;
+    if(p1->sortlist > p2->sortlist)
+        return -1;
+    else
+        return 1;
 }
 
 void collect_data_for_pid(pid_t pid) {
-       if(unlikely(pid <= 0 || pid > pid_max)) {
-               error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
-               return;
-       }
-
-       struct pid_stat *p = get_pid_entry(pid);
-       if(unlikely(!p || p->read)) return;
-       p->read             = 1;
-
-       // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
-
-       // --------------------------------------------------------------------
-       // /proc/<pid>/stat
-
-       if(unlikely(read_proc_pid_stat(p))) {
-               if(errno != ENOENT || debug)
-                       error("Cannot process %s/proc/%d/stat (command '%s')", host_prefix, pid, p->comm);
-               else
-                       errno = 0;
-               // there is no reason to proceed if we cannot get its status
-               return;
-       }
-
-       read_proc_pid_ownership(p);
-
-       // check its parent pid
-       if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
-               error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
-               p->ppid = 0;
-       }
-
-       // --------------------------------------------------------------------
-       // /proc/<pid>/io
-
-       if(unlikely(read_proc_pid_io(p))) {
-               if(errno != ENOENT || debug)
-                       error("Cannot process %s/proc/%d/io (command '%s')", host_prefix, pid, p->comm);
-               else
-                       errno = 0;
-       }
-
-       // --------------------------------------------------------------------
-       // /proc/<pid>/statm
-
-       if(unlikely(read_proc_pid_statm(p))) {
-               if(errno != ENOENT || debug)
-                       error("Cannot process %s/proc/%d/statm (command '%s')", host_prefix, pid, p->comm);
-               else
-                       errno = 0;
-               // there is no reason to proceed if we cannot get its memory status
-               return;
-       }
-
-       // --------------------------------------------------------------------
-       // link it
-
-       // check if it is target
-       // we do this only once, the first time this pid is loaded
-       if(unlikely(p->new_entry)) {
-               // /proc/<pid>/cmdline
-               if(likely(proc_pid_cmdline_is_needed)) {
-                       if(unlikely(read_proc_pid_cmdline(p))) {
-                               if(errno != ENOENT || debug)
-                                       error("Cannot process %s/proc/%d/cmdline (command '%s')", host_prefix, pid, p->comm);
-                               else
-                                       errno = 0;
-                       }
-               }
-
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
-
-               uint32_t hash = simple_hash(p->comm);
-               size_t pclen  = strlen(p->comm);
-
-               struct target *w;
-               for(w = apps_groups_root_target; w ; w = w->next) {
-                       // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
-
-                       // find it - 4 cases:
-                       // 1. the target is not a pattern
-                       // 2. the target has the prefix
-                       // 3. the target has the suffix
-                       // 4. the target is something inside cmdline
-                       if(     (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
-                              || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
-                              || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
-                              || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
-                                       ) {
-                               if(w->target) p->target = w->target;
-                               else p->target = w;
-
-                               if(debug || (p->target && p->target->debug))
-                                       fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
-
-                               break;
-                       }
-               }
-       }
-
-       // --------------------------------------------------------------------
-       // /proc/<pid>/fd
-
-       if(unlikely(read_pid_file_descriptors(p))) {
-               if(errno != ENOENT || debug)
-                       error("Cannot process entries in %s/proc/%d/fd (command '%s')", host_prefix, pid, p->comm);
-               else
-                       errno = 0;
-       }
-
-       // --------------------------------------------------------------------
-       // done!
-
-       if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
-               fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
-
-       // mark it as updated
-       p->updated = 1;
-       p->keep = 0;
-       p->keeploops = 0;
+    if(unlikely(pid <= 0 || pid > pid_max)) {
+        error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
+        return;
+    }
+
+    struct pid_stat *p = get_pid_entry(pid);
+    if(unlikely(!p || p->read)) return;
+    p->read             = 1;
+
+    // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
+
+    // --------------------------------------------------------------------
+    // /proc/<pid>/stat
+
+    if(unlikely(read_proc_pid_stat(p))) {
+        if(errno != ENOENT || debug)
+            error("Cannot process %s/proc/%d/stat (command '%s')", host_prefix, pid, p->comm);
+        else
+            errno = 0;
+        // there is no reason to proceed if we cannot get its status
+        return;
+    }
+
+    read_proc_pid_ownership(p);
+
+    // check its parent pid
+    if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
+        error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
+        p->ppid = 0;
+    }
+
+    // --------------------------------------------------------------------
+    // /proc/<pid>/io
+
+    if(unlikely(read_proc_pid_io(p))) {
+        if(errno != ENOENT || debug)
+            error("Cannot process %s/proc/%d/io (command '%s')", host_prefix, pid, p->comm);
+        else
+            errno = 0;
+    }
+
+    // --------------------------------------------------------------------
+    // /proc/<pid>/statm
+
+    if(unlikely(read_proc_pid_statm(p))) {
+        if(errno != ENOENT || debug)
+            error("Cannot process %s/proc/%d/statm (command '%s')", host_prefix, pid, p->comm);
+        else
+            errno = 0;
+        // there is no reason to proceed if we cannot get its memory status
+        return;
+    }
+
+    // --------------------------------------------------------------------
+    // link it
+
+    // check if it is target
+    // we do this only once, the first time this pid is loaded
+    if(unlikely(p->new_entry)) {
+        // /proc/<pid>/cmdline
+        if(likely(proc_pid_cmdline_is_needed)) {
+            if(unlikely(read_proc_pid_cmdline(p))) {
+                if(errno != ENOENT || debug)
+                    error("Cannot process %s/proc/%d/cmdline (command '%s')", host_prefix, pid, p->comm);
+                else
+                    errno = 0;
+            }
+        }
+
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
+
+        uint32_t hash = simple_hash(p->comm);
+        size_t pclen  = strlen(p->comm);
+
+        struct target *w;
+        for(w = apps_groups_root_target; w ; w = w->next) {
+            // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
+
+            // find it - 4 cases:
+            // 1. the target is not a pattern
+            // 2. the target has the prefix
+            // 3. the target has the suffix
+            // 4. the target is something inside cmdline
+            if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
+                   || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
+                   || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
+                   || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
+                    ) {
+                if(w->target) p->target = w->target;
+                else p->target = w;
+
+                if(debug || (p->target && p->target->debug))
+                    fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
+
+                break;
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+    // /proc/<pid>/fd
+
+    if(unlikely(read_pid_file_descriptors(p))) {
+        if(errno != ENOENT || debug)
+            error("Cannot process entries in %s/proc/%d/fd (command '%s')", host_prefix, pid, p->comm);
+        else
+            errno = 0;
+    }
+
+    // --------------------------------------------------------------------
+    // done!
+
+    if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
+        fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
+
+    // mark it as updated
+    p->updated = 1;
+    p->keep = 0;
+    p->keeploops = 0;
 }
 
 int collect_data_for_all_processes_from_proc(void) {
-       struct pid_stat *p = NULL;
-
-       if(all_pids_count) {
-               // read parents before childs
-               // this is needed to prevent a situation where
-               // a child is found running, but until we read
-               // its parent, it has exited and its parent
-               // has accumulated its resources
-
-               long slc = 0;
-               for(p = root_of_pids; p ; p = p->next) {
-                       p->read             = 0;
-                       p->updated          = 0;
-                       p->new_entry        = 0;
-                       p->merged           = 0;
-                       p->children_count   = 0;
-                       p->parent           = NULL;
-
-                       all_pids_sortlist[slc++] = p->pid;
-               }
-
-               if(unlikely(slc != all_pids_count)) {
-                       error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
-                       all_pids_count = slc;
-               }
-
-               if(include_exited_childs) {
-                       qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
-                       for(slc = 0; slc < all_pids_count; slc++)
-                               collect_data_for_pid(all_pids_sortlist[slc]);
-               }
-       }
-
-       char dirname[FILENAME_MAX + 1];
-
-       snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
-       DIR *dir = opendir(dirname);
-       if(!dir) return 0;
-
-       struct dirent *file = NULL;
-
-       while((file = readdir(dir))) {
-               char *endptr = file->d_name;
-               pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
-
-               // make sure we read a valid number
-               if(unlikely(endptr == file->d_name || *endptr != '\0'))
-                       continue;
-
-               collect_data_for_pid(pid);
-       }
-       closedir(dir);
-
-       // normally this is done
-       // however we may have processes exited while we collected values
-       // so let's find the exited ones
-       // we do this by collecting the ownership of process
-       // if we manage to get the ownership, the process still runs
-
-       read_proc_stat();
-       link_all_processes_to_their_parents();
-       process_exited_processes();
-
-       return 1;
+    struct pid_stat *p = NULL;
+
+    if(all_pids_count) {
+        // read parents before childs
+        // this is needed to prevent a situation where
+        // a child is found running, but until we read
+        // its parent, it has exited and its parent
+        // has accumulated its resources
+
+        long slc = 0;
+        for(p = root_of_pids; p ; p = p->next) {
+            p->read             = 0;
+            p->updated          = 0;
+            p->new_entry        = 0;
+            p->merged           = 0;
+            p->children_count   = 0;
+            p->parent           = NULL;
+
+            all_pids_sortlist[slc++] = p->pid;
+        }
+
+        if(unlikely(slc != all_pids_count)) {
+            error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
+            all_pids_count = slc;
+        }
+
+        if(include_exited_childs) {
+            qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
+            for(slc = 0; slc < all_pids_count; slc++)
+                collect_data_for_pid(all_pids_sortlist[slc]);
+        }
+    }
+
+    char dirname[FILENAME_MAX + 1];
+
+    snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
+    DIR *dir = opendir(dirname);
+    if(!dir) return 0;
+
+    struct dirent *file = NULL;
+
+    while((file = readdir(dir))) {
+        char *endptr = file->d_name;
+        pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
+
+        // make sure we read a valid number
+        if(unlikely(endptr == file->d_name || *endptr != '\0'))
+            continue;
+
+        collect_data_for_pid(pid);
+    }
+    closedir(dir);
+
+    // normally this is done
+    // however we may have processes exited while we collected values
+    // so let's find the exited ones
+    // we do this by collecting the ownership of process
+    // if we manage to get the ownership, the process still runs
+
+    read_proc_stat();
+    link_all_processes_to_their_parents();
+    process_exited_processes();
+
+    return 1;
 }
 
 // ----------------------------------------------------------------------------
@@ -1778,371 +1778,371 @@ int collect_data_for_all_processes_from_proc(void) {
 // check: update_apps_groups_statistics()
 
 void cleanup_exited_pids(void) {
-       int c;
-       struct pid_stat *p = NULL;
-
-       for(p = root_of_pids; p ;) {
-               if(!p->updated && (!p->keep || p->keeploops > 0)) {
-//                     fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name,  p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
-
-                       if(unlikely(debug && (p->keep || p->keeploops)))
-                               fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
-
-                       for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
-                               file_descriptor_not_used(p->fds[c]);
-                               p->fds[c] = 0;
-                       }
-
-                       pid_t r = p->pid;
-                       p = p->next;
-                       del_pid_entry(r);
-               }
-               else {
-                       if(unlikely(p->keep)) p->keeploops++;
-                       p->keep = 0;
-                       p = p->next;
-               }
-       }
+    int c;
+    struct pid_stat *p = NULL;
+
+    for(p = root_of_pids; p ;) {
+        if(!p->updated && (!p->keep || p->keeploops > 0)) {
+//          fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name,  p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+
+            if(unlikely(debug && (p->keep || p->keeploops)))
+                fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
+
+            for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
+                file_descriptor_not_used(p->fds[c]);
+                p->fds[c] = 0;
+            }
+
+            pid_t r = p->pid;
+            p = p->next;
+            del_pid_entry(r);
+        }
+        else {
+            if(unlikely(p->keep)) p->keeploops++;
+            p->keep = 0;
+            p = p->next;
+        }
+    }
 }
 
 void apply_apps_groups_targets_inheritance(void) {
-       struct pid_stat *p = NULL;
-
-       // children that do not have a target
-       // inherit their target from their parent
-       int found = 1, loops = 0;
-       while(found) {
-               if(unlikely(debug)) loops++;
-               found = 0;
-               for(p = root_of_pids; p ; p = p->next) {
-                       // if this process does not have a target
-                       // and it has a parent
-                       // and its parent has a target
-                       // then, set the parent's target to this process
-                       if(unlikely(!p->target && p->parent && p->parent->target)) {
-                               p->target = p->parent->target;
-                               found++;
-
-                               if(debug || (p->target && p->target->debug))
-                                       fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
-                       }
-               }
-       }
-
-       // find all the procs with 0 childs and merge them to their parents
-       // repeat, until nothing more can be done.
-       int sortlist = 1;
-       found = 1;
-       while(found) {
-               if(unlikely(debug)) loops++;
-               found = 0;
-
-               for(p = root_of_pids; p ; p = p->next) {
-                       if(unlikely(!p->sortlist && !p->children_count))
-                               p->sortlist = sortlist++;
-
-                       // if this process does not have any children
-                       // and is not already merged
-                       // and has a parent
-                       // and its parent has children
-                       // and the target of this process and its parent is the same, or the parent does not have a target
-                       // and its parent is not init
-                       // then, mark them as merged.
-                       if(unlikely(
-                                       !p->children_count
-                                       && !p->merged
-                                       && p->parent
-                                       && p->parent->children_count
-                                       && (p->target == p->parent->target || !p->parent->target)
-                                       && p->ppid != 1
-                               )) {
-                               p->parent->children_count--;
-                               p->merged = 1;
-
-                               // the parent inherits the child's target, if it does not have a target itself
-                               if(unlikely(p->target && !p->parent->target)) {
-                                       p->parent->target = p->target;
-
-                                       if(debug || (p->target && p->target->debug))
-                                               fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
-                               }
-
-                               found++;
-                       }
-               }
-
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
-       }
-
-       // init goes always to default target
-       if(all_pids[1])
-               all_pids[1]->target = apps_groups_default_target;
-
-       // give a default target on all top level processes
-       if(unlikely(debug)) loops++;
-       for(p = root_of_pids; p ; p = p->next) {
-               // if the process is not merged itself
-               // then is is a top level process
-               if(unlikely(!p->merged && !p->target))
-                       p->target = apps_groups_default_target;
-
-               // make sure all processes have a sortlist
-               if(unlikely(!p->sortlist))
-                       p->sortlist = sortlist++;
-       }
-
-       if(all_pids[1])
-               all_pids[1]->sortlist = sortlist++;
-
-       // give a target to all merged child processes
-       found = 1;
-       while(found) {
-               if(unlikely(debug)) loops++;
-               found = 0;
-               for(p = root_of_pids; p ; p = p->next) {
-                       if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
-                               p->target = p->parent->target;
-                               found++;
-
-                               if(debug || (p->target && p->target->debug))
-                                       fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
-                       }
-               }
-       }
-
-       if(unlikely(debug))
-               fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
+    struct pid_stat *p = NULL;
+
+    // children that do not have a target
+    // inherit their target from their parent
+    int found = 1, loops = 0;
+    while(found) {
+        if(unlikely(debug)) loops++;
+        found = 0;
+        for(p = root_of_pids; p ; p = p->next) {
+            // if this process does not have a target
+            // and it has a parent
+            // and its parent has a target
+            // then, set the parent's target to this process
+            if(unlikely(!p->target && p->parent && p->parent->target)) {
+                p->target = p->parent->target;
+                found++;
+
+                if(debug || (p->target && p->target->debug))
+                    fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
+            }
+        }
+    }
+
+    // find all the procs with 0 childs and merge them to their parents
+    // repeat, until nothing more can be done.
+    int sortlist = 1;
+    found = 1;
+    while(found) {
+        if(unlikely(debug)) loops++;
+        found = 0;
+
+        for(p = root_of_pids; p ; p = p->next) {
+            if(unlikely(!p->sortlist && !p->children_count))
+                p->sortlist = sortlist++;
+
+            // if this process does not have any children
+            // and is not already merged
+            // and has a parent
+            // and its parent has children
+            // and the target of this process and its parent is the same, or the parent does not have a target
+            // and its parent is not init
+            // then, mark them as merged.
+            if(unlikely(
+                    !p->children_count
+                    && !p->merged
+                    && p->parent
+                    && p->parent->children_count
+                    && (p->target == p->parent->target || !p->parent->target)
+                    && p->ppid != 1
+                )) {
+                p->parent->children_count--;
+                p->merged = 1;
+
+                // the parent inherits the child's target, if it does not have a target itself
+                if(unlikely(p->target && !p->parent->target)) {
+                    p->parent->target = p->target;
+
+                    if(debug || (p->target && p->target->debug))
+                        fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
+                }
+
+                found++;
+            }
+        }
+
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
+    }
+
+    // init goes always to default target
+    if(all_pids[1])
+        all_pids[1]->target = apps_groups_default_target;
+
+    // give a default target on all top level processes
+    if(unlikely(debug)) loops++;
+    for(p = root_of_pids; p ; p = p->next) {
+        // if the process is not merged itself
+        // then is is a top level process
+        if(unlikely(!p->merged && !p->target))
+            p->target = apps_groups_default_target;
+
+        // make sure all processes have a sortlist
+        if(unlikely(!p->sortlist))
+            p->sortlist = sortlist++;
+    }
+
+    if(all_pids[1])
+        all_pids[1]->sortlist = sortlist++;
+
+    // give a target to all merged child processes
+    found = 1;
+    while(found) {
+        if(unlikely(debug)) loops++;
+        found = 0;
+        for(p = root_of_pids; p ; p = p->next) {
+            if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
+                p->target = p->parent->target;
+                found++;
+
+                if(debug || (p->target && p->target->debug))
+                    fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
+            }
+        }
+    }
+
+    if(unlikely(debug))
+        fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
 }
 
 long zero_all_targets(struct target *root) {
-       struct target *w;
-       long count = 0;
-
-       for (w = root; w ; w = w->next) {
-               count++;
-
-               if(w->fds) freez(w->fds);
-               w->fds = NULL;
-
-               w->minflt = 0;
-               w->majflt = 0;
-               w->utime = 0;
-               w->stime = 0;
-               w->gtime = 0;
-               w->cminflt = 0;
-               w->cmajflt = 0;
-               w->cutime = 0;
-               w->cstime = 0;
-               w->cgtime = 0;
-               w->num_threads = 0;
-               w->rss = 0;
-               w->processes = 0;
-
-               w->statm_size = 0;
-               w->statm_resident = 0;
-               w->statm_share = 0;
-               w->statm_text = 0;
-               w->statm_lib = 0;
-               w->statm_data = 0;
-               w->statm_dirty = 0;
-
-               w->io_logical_bytes_read = 0;
-               w->io_logical_bytes_written = 0;
-               w->io_read_calls = 0;
-               w->io_write_calls = 0;
-               w->io_storage_bytes_read = 0;
-               w->io_storage_bytes_written = 0;
-               w->io_cancelled_write_bytes = 0;
-       }
-
-       return count;
+    struct target *w;
+    long count = 0;
+
+    for (w = root; w ; w = w->next) {
+        count++;
+
+        if(w->fds) freez(w->fds);
+        w->fds = NULL;
+
+        w->minflt = 0;
+        w->majflt = 0;
+        w->utime = 0;
+        w->stime = 0;
+        w->gtime = 0;
+        w->cminflt = 0;
+        w->cmajflt = 0;
+        w->cutime = 0;
+        w->cstime = 0;
+        w->cgtime = 0;
+        w->num_threads = 0;
+        w->rss = 0;
+        w->processes = 0;
+
+        w->statm_size = 0;
+        w->statm_resident = 0;
+        w->statm_share = 0;
+        w->statm_text = 0;
+        w->statm_lib = 0;
+        w->statm_data = 0;
+        w->statm_dirty = 0;
+
+        w->io_logical_bytes_read = 0;
+        w->io_logical_bytes_written = 0;
+        w->io_read_calls = 0;
+        w->io_write_calls = 0;
+        w->io_storage_bytes_read = 0;
+        w->io_storage_bytes_written = 0;
+        w->io_cancelled_write_bytes = 0;
+    }
+
+    return count;
 }
 
 void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
-       (void)o;
-
-       if(unlikely(!w->fds))
-               w->fds = callocz(sizeof(int), (size_t) all_files_size);
-
-       if(likely(p->updated)) {
-               w->cutime  += p->cutime;
-               w->cstime  += p->cstime;
-               w->cgtime  += p->cgtime;
-               w->cminflt += p->cminflt;
-               w->cmajflt += p->cmajflt;
-
-               w->utime  += p->utime;
-               w->stime  += p->stime;
-               w->gtime  += p->gtime;
-               w->minflt += p->minflt;
-               w->majflt += p->majflt;
-
-               w->rss += p->rss;
-
-               w->statm_size += p->statm_size;
-               w->statm_resident += p->statm_resident;
-               w->statm_share += p->statm_share;
-               w->statm_text += p->statm_text;
-               w->statm_lib += p->statm_lib;
-               w->statm_data += p->statm_data;
-               w->statm_dirty += p->statm_dirty;
-
-               w->io_logical_bytes_read    += p->io_logical_bytes_read;
-               w->io_logical_bytes_written += p->io_logical_bytes_written;
-               w->io_read_calls            += p->io_read_calls;
-               w->io_write_calls           += p->io_write_calls;
-               w->io_storage_bytes_read    += p->io_storage_bytes_read;
-               w->io_storage_bytes_written += p->io_storage_bytes_written;
-               w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
-
-               w->processes++;
-               w->num_threads += p->num_threads;
-
-               if(likely(w->fds)) {
-                       int c;
-                       for(c = 0; c < p->fds_size ;c++) {
-                               if(p->fds[c] == 0) continue;
-
-                               if(likely(p->fds[c] < all_files_size)) {
-                                       if(w->fds) w->fds[p->fds[c]]++;
-                               }
-                               else
-                                       error("Invalid fd number %d", p->fds[c]);
-                       }
-               }
-
-               if(unlikely(debug || w->debug))
-                       fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
-       }
+    (void)o;
+
+    if(unlikely(!w->fds))
+        w->fds = callocz(sizeof(int), (size_t) all_files_size);
+
+    if(likely(p->updated)) {
+        w->cutime  += p->cutime;
+        w->cstime  += p->cstime;
+        w->cgtime  += p->cgtime;
+        w->cminflt += p->cminflt;
+        w->cmajflt += p->cmajflt;
+
+        w->utime  += p->utime;
+        w->stime  += p->stime;
+        w->gtime  += p->gtime;
+        w->minflt += p->minflt;
+        w->majflt += p->majflt;
+
+        w->rss += p->rss;
+
+        w->statm_size += p->statm_size;
+        w->statm_resident += p->statm_resident;
+        w->statm_share += p->statm_share;
+        w->statm_text += p->statm_text;
+        w->statm_lib += p->statm_lib;
+        w->statm_data += p->statm_data;
+        w->statm_dirty += p->statm_dirty;
+
+        w->io_logical_bytes_read    += p->io_logical_bytes_read;
+        w->io_logical_bytes_written += p->io_logical_bytes_written;
+        w->io_read_calls            += p->io_read_calls;
+        w->io_write_calls           += p->io_write_calls;
+        w->io_storage_bytes_read    += p->io_storage_bytes_read;
+        w->io_storage_bytes_written += p->io_storage_bytes_written;
+        w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+
+        w->processes++;
+        w->num_threads += p->num_threads;
+
+        if(likely(w->fds)) {
+            int c;
+            for(c = 0; c < p->fds_size ;c++) {
+                if(p->fds[c] == 0) continue;
+
+                if(likely(p->fds[c] < all_files_size)) {
+                    if(w->fds) w->fds[p->fds[c]]++;
+                }
+                else
+                    error("Invalid fd number %d", p->fds[c]);
+            }
+        }
+
+        if(unlikely(debug || w->debug))
+            fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+    }
 }
 
 void count_targets_fds(struct target *root) {
-       int c;
-       struct target *w;
-
-       for (w = root; w ; w = w->next) {
-               if(!w->fds) continue;
-
-               w->openfiles = 0;
-               w->openpipes = 0;
-               w->opensockets = 0;
-               w->openinotifies = 0;
-               w->openeventfds = 0;
-               w->opentimerfds = 0;
-               w->opensignalfds = 0;
-               w->openeventpolls = 0;
-               w->openother = 0;
-
-               for(c = 1; c < all_files_size ;c++) {
-                       if(w->fds[c] > 0)
-                               switch(all_files[c].type) {
-                               case FILETYPE_FILE:
-                                       w->openfiles++;
-                                       break;
-
-                               case FILETYPE_PIPE:
-                                       w->openpipes++;
-                                       break;
-
-                               case FILETYPE_SOCKET:
-                                       w->opensockets++;
-                                       break;
-
-                               case FILETYPE_INOTIFY:
-                                       w->openinotifies++;
-                                       break;
-
-                               case FILETYPE_EVENTFD:
-                                       w->openeventfds++;
-                                       break;
-
-                               case FILETYPE_TIMERFD:
-                                       w->opentimerfds++;
-                                       break;
-
-                               case FILETYPE_SIGNALFD:
-                                       w->opensignalfds++;
-                                       break;
-
-                               case FILETYPE_EVENTPOLL:
-                                       w->openeventpolls++;
-                                       break;
-
-                               default:
-                                       w->openother++;
-                       }
-               }
-
-               freez(w->fds);
-               w->fds = NULL;
-       }
+    int c;
+    struct target *w;
+
+    for (w = root; w ; w = w->next) {
+        if(!w->fds) continue;
+
+        w->openfiles = 0;
+        w->openpipes = 0;
+        w->opensockets = 0;
+        w->openinotifies = 0;
+        w->openeventfds = 0;
+        w->opentimerfds = 0;
+        w->opensignalfds = 0;
+        w->openeventpolls = 0;
+        w->openother = 0;
+
+        for(c = 1; c < all_files_size ;c++) {
+            if(w->fds[c] > 0)
+                switch(all_files[c].type) {
+                case FILETYPE_FILE:
+                    w->openfiles++;
+                    break;
+
+                case FILETYPE_PIPE:
+                    w->openpipes++;
+                    break;
+
+                case FILETYPE_SOCKET:
+                    w->opensockets++;
+                    break;
+
+                case FILETYPE_INOTIFY:
+                    w->openinotifies++;
+                    break;
+
+                case FILETYPE_EVENTFD:
+                    w->openeventfds++;
+                    break;
+
+                case FILETYPE_TIMERFD:
+                    w->opentimerfds++;
+                    break;
+
+                case FILETYPE_SIGNALFD:
+                    w->opensignalfds++;
+                    break;
+
+                case FILETYPE_EVENTPOLL:
+                    w->openeventpolls++;
+                    break;
+
+                default:
+                    w->openother++;
+            }
+        }
+
+        freez(w->fds);
+        w->fds = NULL;
+    }
 }
 
 void calculate_netdata_statistics(void) {
-       apply_apps_groups_targets_inheritance();
+    apply_apps_groups_targets_inheritance();
 
-       zero_all_targets(users_root_target);
-       zero_all_targets(groups_root_target);
-       apps_groups_targets = zero_all_targets(apps_groups_root_target);
+    zero_all_targets(users_root_target);
+    zero_all_targets(groups_root_target);
+    apps_groups_targets = zero_all_targets(apps_groups_root_target);
 
-       // this has to be done, before the cleanup
-       struct pid_stat *p = NULL;
-       struct target *w = NULL, *o = NULL;
+    // this has to be done, before the cleanup
+    struct pid_stat *p = NULL;
+    struct target *w = NULL, *o = NULL;
 
-       // concentrate everything on the apps_groups_targets
-       for(p = root_of_pids; p ; p = p->next) {
+    // concentrate everything on the apps_groups_targets
+    for(p = root_of_pids; p ; p = p->next) {
 
-               // --------------------------------------------------------------------
-               // apps_groups targets
-               if(likely(p->target))
-                       aggregate_pid_on_target(p->target, p, NULL);
-               else
-                       error("pid %d %s was left without a target!", p->pid, p->comm);
+        // --------------------------------------------------------------------
+        // apps_groups targets
+        if(likely(p->target))
+            aggregate_pid_on_target(p->target, p, NULL);
+        else
+            error("pid %d %s was left without a target!", p->pid, p->comm);
 
 
-               // --------------------------------------------------------------------
-               // user targets
-               o = p->user_target;
-               if(likely(p->user_target && p->user_target->uid == p->uid))
-                       w = p->user_target;
-               else {
-                       if(unlikely(debug && p->user_target))
-                                       fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
+        // --------------------------------------------------------------------
+        // user targets
+        o = p->user_target;
+        if(likely(p->user_target && p->user_target->uid == p->uid))
+            w = p->user_target;
+        else {
+            if(unlikely(debug && p->user_target))
+                    fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
 
-                       w = p->user_target = get_users_target(p->uid);
-               }
+            w = p->user_target = get_users_target(p->uid);
+        }
 
-               if(likely(w))
-                       aggregate_pid_on_target(w, p, o);
-               else
-                       error("pid %d %s was left without a user target!", p->pid, p->comm);
+        if(likely(w))
+            aggregate_pid_on_target(w, p, o);
+        else
+            error("pid %d %s was left without a user target!", p->pid, p->comm);
 
 
-               // --------------------------------------------------------------------
-               // group targets
-               o = p->group_target;
-               if(likely(p->group_target && p->group_target->gid == p->gid))
-                       w = p->group_target;
-               else {
-                       if(unlikely(debug && p->group_target))
-                                       fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
+        // --------------------------------------------------------------------
+        // group targets
+        o = p->group_target;
+        if(likely(p->group_target && p->group_target->gid == p->gid))
+            w = p->group_target;
+        else {
+            if(unlikely(debug && p->group_target))
+                    fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
 
-                       w = p->group_target = get_groups_target(p->gid);
-               }
+            w = p->group_target = get_groups_target(p->gid);
+        }
 
-               if(likely(w))
-                       aggregate_pid_on_target(w, p, o);
-               else
-                       error("pid %d %s was left without a group target!", p->pid, p->comm);
+        if(likely(w))
+            aggregate_pid_on_target(w, p, o);
+        else
+            error("pid %d %s was left without a group target!", p->pid, p->comm);
 
-       }
+    }
 
-       count_targets_fds(apps_groups_root_target);
-       count_targets_fds(users_root_target);
-       count_targets_fds(groups_root_target);
+    count_targets_fds(apps_groups_root_target);
+    count_targets_fds(users_root_target);
+    count_targets_fds(groups_root_target);
 
-       cleanup_exited_pids();
+    cleanup_exited_pids();
 }
 
 // ----------------------------------------------------------------------------
@@ -2152,383 +2152,383 @@ BUFFER *output = NULL;
 int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
 
 static inline void send_BEGIN(const char *type, const char *id, unsigned long long usec) {
-       // fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
-       buffer_strcat(output, "BEGIN ");
-       buffer_strcat(output, type);
-       buffer_strcat(output, ".");
-       buffer_strcat(output, id);
-       buffer_strcat(output, " ");
-       buffer_print_llu(output, usec);
-       buffer_strcat(output, "\n");
+    // fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
+    buffer_strcat(output, "BEGIN ");
+    buffer_strcat(output, type);
+    buffer_strcat(output, ".");
+    buffer_strcat(output, id);
+    buffer_strcat(output, " ");
+    buffer_print_llu(output, usec);
+    buffer_strcat(output, "\n");
 }
 
 static inline void send_SET(const char *name, unsigned long long value) {
-       // fprintf(stdout, "SET %s = %llu\n", name, value);
-       buffer_strcat(output, "SET ");
-       buffer_strcat(output, name);
-       buffer_strcat(output, " = ");
-       buffer_print_llu(output, value);
-       buffer_strcat(output, "\n");
+    // fprintf(stdout, "SET %s = %llu\n", name, value);
+    buffer_strcat(output, "SET ");
+    buffer_strcat(output, name);
+    buffer_strcat(output, " = ");
+    buffer_print_llu(output, value);
+    buffer_strcat(output, "\n");
 }
 
 static inline void send_END(void) {
-       // fprintf(stdout, "END\n");
-       buffer_strcat(output, "END\n");
+    // fprintf(stdout, "END\n");
+    buffer_strcat(output, "END\n");
 }
 
 double utime_fix_ratio = 1.0, stime_fix_ratio = 1.0, gtime_fix_ratio = 1.0, cutime_fix_ratio = 1.0, cstime_fix_ratio = 1.0, cgtime_fix_ratio = 1.0;
 double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0;
 
 unsigned long long send_resource_usage_to_netdata() {
-       static struct timeval last = { 0, 0 };
-       static struct rusage me_last;
-
-       struct timeval now;
-       struct rusage me;
-
-       unsigned long long usec;
-       unsigned long long cpuuser;
-       unsigned long long cpusyst;
-
-       if(!last.tv_sec) {
-               gettimeofday(&last, NULL);
-               getrusage(RUSAGE_SELF, &me_last);
-
-               // the first time, give a zero to allow
-               // netdata calibrate to the current time
-               // usec = update_every * 1000000ULL;
-               usec = 0ULL;
-               cpuuser = 0;
-               cpusyst = 0;
-       }
-       else {
-               gettimeofday(&now, NULL);
-               getrusage(RUSAGE_SELF, &me);
-
-               usec = usec_dt(&now, &last);
-               cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
-               cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
-
-               bcopy(&now, &last, sizeof(struct timeval));
-               bcopy(&me, &me_last, sizeof(struct rusage));
-       }
-
-       buffer_sprintf(output,
-               "BEGIN netdata.apps_cpu %llu\n"
-               "SET user = %llu\n"
-               "SET system = %llu\n"
-               "END\n"
-               "BEGIN netdata.apps_files %llu\n"
-               "SET files = %llu\n"
-               "SET pids = %ld\n"
-               "SET fds = %d\n"
-               "SET targets = %ld\n"
-               "END\n"
-               "BEGIN netdata.apps_fix %llu\n"
-               "SET utime = %llu\n"
-               "SET stime = %llu\n"
-               "SET gtime = %llu\n"
-               "SET minflt = %llu\n"
-               "SET majflt = %llu\n"
-               "END\n"
-               , usec
-               , cpuuser
-               , cpusyst
-               , usec
-               , file_counter
-               , all_pids_count
-               , all_files_len
-               , apps_groups_targets
-               , usec
-               , (unsigned long long)(utime_fix_ratio   * 100 * RATES_DETAIL)
-               , (unsigned long long)(stime_fix_ratio   * 100 * RATES_DETAIL)
-               , (unsigned long long)(gtime_fix_ratio   * 100 * RATES_DETAIL)
-               , (unsigned long long)(minflt_fix_ratio  * 100 * RATES_DETAIL)
-               , (unsigned long long)(majflt_fix_ratio  * 100 * RATES_DETAIL)
-               );
-
-       if(include_exited_childs)
-               buffer_sprintf(output,
-                       "BEGIN netdata.apps_children_fix %llu\n"
-                       "SET cutime = %llu\n"
-                       "SET cstime = %llu\n"
-                       "SET cgtime = %llu\n"
-                       "SET cminflt = %llu\n"
-                       "SET cmajflt = %llu\n"
-                       "END\n"
-                       , usec
-                       , (unsigned long long)(cutime_fix_ratio  * 100 * RATES_DETAIL)
-                       , (unsigned long long)(cstime_fix_ratio  * 100 * RATES_DETAIL)
-                       , (unsigned long long)(cgtime_fix_ratio  * 100 * RATES_DETAIL)
-                       , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
-                       , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
-                       );
-
-       return usec;
+    static struct timeval last = { 0, 0 };
+    static struct rusage me_last;
+
+    struct timeval now;
+    struct rusage me;
+
+    unsigned long long usec;
+    unsigned long long cpuuser;
+    unsigned long long cpusyst;
+
+    if(!last.tv_sec) {
+        gettimeofday(&last, NULL);
+        getrusage(RUSAGE_SELF, &me_last);
+
+        // the first time, give a zero to allow
+        // netdata calibrate to the current time
+        // usec = update_every * 1000000ULL;
+        usec = 0ULL;
+        cpuuser = 0;
+        cpusyst = 0;
+    }
+    else {
+        gettimeofday(&now, NULL);
+        getrusage(RUSAGE_SELF, &me);
+
+        usec = usec_dt(&now, &last);
+        cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
+        cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
+
+        bcopy(&now, &last, sizeof(struct timeval));
+        bcopy(&me, &me_last, sizeof(struct rusage));
+    }
+
+    buffer_sprintf(output,
+        "BEGIN netdata.apps_cpu %llu\n"
+        "SET user = %llu\n"
+        "SET system = %llu\n"
+        "END\n"
+        "BEGIN netdata.apps_files %llu\n"
+        "SET files = %llu\n"
+        "SET pids = %ld\n"
+        "SET fds = %d\n"
+        "SET targets = %ld\n"
+        "END\n"
+        "BEGIN netdata.apps_fix %llu\n"
+        "SET utime = %llu\n"
+        "SET stime = %llu\n"
+        "SET gtime = %llu\n"
+        "SET minflt = %llu\n"
+        "SET majflt = %llu\n"
+        "END\n"
+        , usec
+        , cpuuser
+        , cpusyst
+        , usec
+        , file_counter
+        , all_pids_count
+        , all_files_len
+        , apps_groups_targets
+        , usec
+        , (unsigned long long)(utime_fix_ratio   * 100 * RATES_DETAIL)
+        , (unsigned long long)(stime_fix_ratio   * 100 * RATES_DETAIL)
+        , (unsigned long long)(gtime_fix_ratio   * 100 * RATES_DETAIL)
+        , (unsigned long long)(minflt_fix_ratio  * 100 * RATES_DETAIL)
+        , (unsigned long long)(majflt_fix_ratio  * 100 * RATES_DETAIL)
+        );
+
+    if(include_exited_childs)
+        buffer_sprintf(output,
+            "BEGIN netdata.apps_children_fix %llu\n"
+            "SET cutime = %llu\n"
+            "SET cstime = %llu\n"
+            "SET cgtime = %llu\n"
+            "SET cminflt = %llu\n"
+            "SET cmajflt = %llu\n"
+            "END\n"
+            , usec
+            , (unsigned long long)(cutime_fix_ratio  * 100 * RATES_DETAIL)
+            , (unsigned long long)(cstime_fix_ratio  * 100 * RATES_DETAIL)
+            , (unsigned long long)(cgtime_fix_ratio  * 100 * RATES_DETAIL)
+            , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
+            , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
+            );
+
+    return usec;
 }
 
 void normalize_data(struct target *root) {
-       struct target *w;
-
-       // childs processing introduces spikes
-       // here we try to eliminate them by disabling childs processing either for specific dimensions
-       // or entirely. Of course, either way, we disable it just a single iteration.
-
-       unsigned long long max = processors * hz * RATES_DETAIL;
-       unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
-
-       if(global_utime > max) global_utime = max;
-       if(global_stime > max) global_stime = max;
-       if(global_gtime > max) global_gtime = max;
-
-       for(w = root; w ; w = w->next) {
-               if(w->target || (!w->processes && !w->exposed)) continue;
-
-               utime   += w->utime;
-               stime   += w->stime;
-               gtime   += w->gtime;
-               cutime  += w->cutime;
-               cstime  += w->cstime;
-               cgtime  += w->cgtime;
-
-               minflt  += w->minflt;
-               majflt  += w->majflt;
-               cminflt += w->cminflt;
-               cmajflt += w->cmajflt;
-       }
-
-       if((global_utime || global_stime || global_gtime) && (utime || stime || gtime)) {
-               if(global_utime + global_stime + global_gtime > utime + cutime + stime + cstime + gtime + cgtime) {
-                       // everything we collected fits
-                       utime_fix_ratio  =
-                       stime_fix_ratio  =
-                       gtime_fix_ratio  =
-                       cutime_fix_ratio =
-                       cstime_fix_ratio =
-                       cgtime_fix_ratio = 1.0; //(double)(global_utime + global_stime) / (double)(utime + cutime + stime + cstime);
-               }
-               else if(global_utime + global_stime > utime + stime) {
-                       // childrens resources are too high
-                       // lower only the children resources
-                       utime_fix_ratio  =
-                       stime_fix_ratio  =
-                       gtime_fix_ratio  = 1.0;
-                       cutime_fix_ratio =
-                       cstime_fix_ratio =
-                       cgtime_fix_ratio = (double)((global_utime + global_stime) - (utime + stime)) / (double)(cutime + cstime);
-               }
-               else {
-                       // even running processes are unrealistic
-                       // zero the children resources
-                       // lower the running processes resources
-                       utime_fix_ratio  =
-                       stime_fix_ratio  =
-                       gtime_fix_ratio  = (double)(global_utime + global_stime) / (double)(utime + stime);
-                       cutime_fix_ratio =
-                       cstime_fix_ratio =
-                       cgtime_fix_ratio = 0.0;
-               }
-       }
-       else {
-               utime_fix_ratio  =
-               stime_fix_ratio  =
-               gtime_fix_ratio  =
-               cutime_fix_ratio =
-               cstime_fix_ratio =
-               cgtime_fix_ratio = 0.0;
-       }
-
-       if(utime_fix_ratio  > 1.0) utime_fix_ratio  = 1.0;
-       if(cutime_fix_ratio > 1.0) cutime_fix_ratio = 1.0;
-       if(stime_fix_ratio  > 1.0) stime_fix_ratio  = 1.0;
-       if(cstime_fix_ratio > 1.0) cstime_fix_ratio = 1.0;
-       if(gtime_fix_ratio  > 1.0) gtime_fix_ratio  = 1.0;
-       if(cgtime_fix_ratio > 1.0) cgtime_fix_ratio = 1.0;
-
-       // if(utime_fix_ratio  < 0.0) utime_fix_ratio  = 0.0;
-       // if(cutime_fix_ratio < 0.0) cutime_fix_ratio = 0.0;
-       // if(stime_fix_ratio  < 0.0) stime_fix_ratio  = 0.0;
-       // if(cstime_fix_ratio < 0.0) cstime_fix_ratio = 0.0;
-       // if(gtime_fix_ratio  < 0.0) gtime_fix_ratio  = 0.0;
-       // if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0;
-
-       // FIXME
-       // we use cpu time to normalize page faults
-       // the problem is that to find the proper max values
-       // for page faults we have to parse /proc/vmstat
-       // which is quite big to do it again (netdata does it already)
-       //
-       // a better solution could be to somehow have netdata
-       // do this normalization for us
-
-       if(utime || stime || gtime)
-               majflt_fix_ratio =
-               minflt_fix_ratio = (double)(utime * utime_fix_ratio + stime * stime_fix_ratio + gtime * gtime_fix_ratio) / (double)(utime + stime + gtime);
-       else
-               minflt_fix_ratio =
-               majflt_fix_ratio = 1.0;
-
-       if(cutime || cstime || cgtime)
-               cmajflt_fix_ratio =
-               cminflt_fix_ratio = (double)(cutime * cutime_fix_ratio + cstime * cstime_fix_ratio + cgtime * cgtime_fix_ratio) / (double)(cutime + cstime + cgtime);
-       else
-               cminflt_fix_ratio =
-               cmajflt_fix_ratio = 1.0;
-
-       // the report
-
-       if(unlikely(debug)) {
-               fprintf(stderr,
-                       "SYSTEM: u=%llu s=%llu g=%llu "
-                       "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
-                       "DELTA: u=%lld s=%lld g=%lld "
-                       "FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
-                       "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
-                       "\n"
-                       , global_utime
-                       , global_stime
-                       , global_gtime
-                       , utime
-                       , stime
-                       , gtime
-                       , cutime
-                       , cstime
-                       , cgtime
-                       , (long long)utime + (long long)cutime - (long long)global_utime
-                       , (long long)stime + (long long)cstime - (long long)global_stime
-                       , (long long)gtime + (long long)cgtime - (long long)global_gtime
-                       , utime_fix_ratio
-                       , stime_fix_ratio
-                       , gtime_fix_ratio
-                       , cutime_fix_ratio
-                       , cstime_fix_ratio
-                       , cgtime_fix_ratio
-                       , (unsigned long long)(utime * utime_fix_ratio)
-                       , (unsigned long long)(stime * stime_fix_ratio)
-                       , (unsigned long long)(gtime * gtime_fix_ratio)
-                       , (unsigned long long)(cutime * cutime_fix_ratio)
-                       , (unsigned long long)(cstime * cstime_fix_ratio)
-                       , (unsigned long long)(cgtime * cgtime_fix_ratio)
-                       );
-       }
+    struct target *w;
+
+    // childs processing introduces spikes
+    // here we try to eliminate them by disabling childs processing either for specific dimensions
+    // or entirely. Of course, either way, we disable it just a single iteration.
+
+    unsigned long long max = processors * hz * RATES_DETAIL;
+    unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
+
+    if(global_utime > max) global_utime = max;
+    if(global_stime > max) global_stime = max;
+    if(global_gtime > max) global_gtime = max;
+
+    for(w = root; w ; w = w->next) {
+        if(w->target || (!w->processes && !w->exposed)) continue;
+
+        utime   += w->utime;
+        stime   += w->stime;
+        gtime   += w->gtime;
+        cutime  += w->cutime;
+        cstime  += w->cstime;
+        cgtime  += w->cgtime;
+
+        minflt  += w->minflt;
+        majflt  += w->majflt;
+        cminflt += w->cminflt;
+        cmajflt += w->cmajflt;
+    }
+
+    if((global_utime || global_stime || global_gtime) && (utime || stime || gtime)) {
+        if(global_utime + global_stime + global_gtime > utime + cutime + stime + cstime + gtime + cgtime) {
+            // everything we collected fits
+            utime_fix_ratio  =
+            stime_fix_ratio  =
+            gtime_fix_ratio  =
+            cutime_fix_ratio =
+            cstime_fix_ratio =
+            cgtime_fix_ratio = 1.0; //(double)(global_utime + global_stime) / (double)(utime + cutime + stime + cstime);
+        }
+        else if(global_utime + global_stime > utime + stime) {
+            // childrens resources are too high
+            // lower only the children resources
+            utime_fix_ratio  =
+            stime_fix_ratio  =
+            gtime_fix_ratio  = 1.0;
+            cutime_fix_ratio =
+            cstime_fix_ratio =
+            cgtime_fix_ratio = (double)((global_utime + global_stime) - (utime + stime)) / (double)(cutime + cstime);
+        }
+        else {
+            // even running processes are unrealistic
+            // zero the children resources
+            // lower the running processes resources
+            utime_fix_ratio  =
+            stime_fix_ratio  =
+            gtime_fix_ratio  = (double)(global_utime + global_stime) / (double)(utime + stime);
+            cutime_fix_ratio =
+            cstime_fix_ratio =
+            cgtime_fix_ratio = 0.0;
+        }
+    }
+    else {
+        utime_fix_ratio  =
+        stime_fix_ratio  =
+        gtime_fix_ratio  =
+        cutime_fix_ratio =
+        cstime_fix_ratio =
+        cgtime_fix_ratio = 0.0;
+    }
+
+    if(utime_fix_ratio  > 1.0) utime_fix_ratio  = 1.0;
+    if(cutime_fix_ratio > 1.0) cutime_fix_ratio = 1.0;
+    if(stime_fix_ratio  > 1.0) stime_fix_ratio  = 1.0;
+    if(cstime_fix_ratio > 1.0) cstime_fix_ratio = 1.0;
+    if(gtime_fix_ratio  > 1.0) gtime_fix_ratio  = 1.0;
+    if(cgtime_fix_ratio > 1.0) cgtime_fix_ratio = 1.0;
+
+    // if(utime_fix_ratio  < 0.0) utime_fix_ratio  = 0.0;
+    // if(cutime_fix_ratio < 0.0) cutime_fix_ratio = 0.0;
+    // if(stime_fix_ratio  < 0.0) stime_fix_ratio  = 0.0;
+    // if(cstime_fix_ratio < 0.0) cstime_fix_ratio = 0.0;
+    // if(gtime_fix_ratio  < 0.0) gtime_fix_ratio  = 0.0;
+    // if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0;
+
+    // FIXME
+    // we use cpu time to normalize page faults
+    // the problem is that to find the proper max values
+    // for page faults we have to parse /proc/vmstat
+    // which is quite big to do it again (netdata does it already)
+    //
+    // a better solution could be to somehow have netdata
+    // do this normalization for us
+
+    if(utime || stime || gtime)
+        majflt_fix_ratio =
+        minflt_fix_ratio = (double)(utime * utime_fix_ratio + stime * stime_fix_ratio + gtime * gtime_fix_ratio) / (double)(utime + stime + gtime);
+    else
+        minflt_fix_ratio =
+        majflt_fix_ratio = 1.0;
+
+    if(cutime || cstime || cgtime)
+        cmajflt_fix_ratio =
+        cminflt_fix_ratio = (double)(cutime * cutime_fix_ratio + cstime * cstime_fix_ratio + cgtime * cgtime_fix_ratio) / (double)(cutime + cstime + cgtime);
+    else
+        cminflt_fix_ratio =
+        cmajflt_fix_ratio = 1.0;
+
+    // the report
+
+    if(unlikely(debug)) {
+        fprintf(stderr,
+            "SYSTEM: u=%llu s=%llu g=%llu "
+            "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
+            "DELTA: u=%lld s=%lld g=%lld "
+            "FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
+            "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
+            "\n"
+            , global_utime
+            , global_stime
+            , global_gtime
+            , utime
+            , stime
+            , gtime
+            , cutime
+            , cstime
+            , cgtime
+            , (long long)utime + (long long)cutime - (long long)global_utime
+            , (long long)stime + (long long)cstime - (long long)global_stime
+            , (long long)gtime + (long long)cgtime - (long long)global_gtime
+            , utime_fix_ratio
+            , stime_fix_ratio
+            , gtime_fix_ratio
+            , cutime_fix_ratio
+            , cstime_fix_ratio
+            , cgtime_fix_ratio
+            , (unsigned long long)(utime * utime_fix_ratio)
+            , (unsigned long long)(stime * stime_fix_ratio)
+            , (unsigned long long)(gtime * gtime_fix_ratio)
+            , (unsigned long long)(cutime * cutime_fix_ratio)
+            , (unsigned long long)(cstime * cstime_fix_ratio)
+            , (unsigned long long)(cgtime * cgtime_fix_ratio)
+            );
+    }
 }
 
 void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec) {
-       struct target *w;
-
-       send_BEGIN(type, "cpu", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
-       }
-       send_END();
-
-       send_BEGIN(type, "cpu_user", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
-       }
-       send_END();
-
-       send_BEGIN(type, "cpu_system", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
-       }
-       send_END();
-
-       if(show_guest_time) {
-               send_BEGIN(type, "cpu_guest", usec);
-               for (w = root; w ; w = w->next) {
-                       if(unlikely(w->exposed))
-                               send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
-               }
-               send_END();
-       }
-
-       send_BEGIN(type, "threads", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->num_threads);
-       }
-       send_END();
-
-       send_BEGIN(type, "processes", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->processes);
-       }
-       send_END();
-
-       send_BEGIN(type, "mem", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (w->statm_resident > w->statm_share)?(w->statm_resident - w->statm_share):0ULL);
-       }
-       send_END();
-
-       send_BEGIN(type, "minor_faults", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
-       }
-       send_END();
-
-       send_BEGIN(type, "major_faults", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
-       }
-       send_END();
-
-       send_BEGIN(type, "lreads", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->io_logical_bytes_read);
-       }
-       send_END();
-
-       send_BEGIN(type, "lwrites", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->io_logical_bytes_written);
-       }
-       send_END();
-
-       send_BEGIN(type, "preads", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->io_storage_bytes_read);
-       }
-       send_END();
-
-       send_BEGIN(type, "pwrites", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->io_storage_bytes_written);
-       }
-       send_END();
-
-       send_BEGIN(type, "files", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->openfiles);
-       }
-       send_END();
-
-       send_BEGIN(type, "sockets", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->opensockets);
-       }
-       send_END();
-
-       send_BEGIN(type, "pipes", usec);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       send_SET(w->name, w->openpipes);
-       }
-       send_END();
+    struct target *w;
+
+    send_BEGIN(type, "cpu", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+    }
+    send_END();
+
+    send_BEGIN(type, "cpu_user", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
+    }
+    send_END();
+
+    send_BEGIN(type, "cpu_system", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
+    }
+    send_END();
+
+    if(show_guest_time) {
+        send_BEGIN(type, "cpu_guest", usec);
+        for (w = root; w ; w = w->next) {
+            if(unlikely(w->exposed))
+                send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
+        }
+        send_END();
+    }
+
+    send_BEGIN(type, "threads", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->num_threads);
+    }
+    send_END();
+
+    send_BEGIN(type, "processes", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->processes);
+    }
+    send_END();
+
+    send_BEGIN(type, "mem", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (w->statm_resident > w->statm_share)?(w->statm_resident - w->statm_share):0ULL);
+    }
+    send_END();
+
+    send_BEGIN(type, "minor_faults", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
+    }
+    send_END();
+
+    send_BEGIN(type, "major_faults", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
+    }
+    send_END();
+
+    send_BEGIN(type, "lreads", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->io_logical_bytes_read);
+    }
+    send_END();
+
+    send_BEGIN(type, "lwrites", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->io_logical_bytes_written);
+    }
+    send_END();
+
+    send_BEGIN(type, "preads", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->io_storage_bytes_read);
+    }
+    send_END();
+
+    send_BEGIN(type, "pwrites", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->io_storage_bytes_written);
+    }
+    send_END();
+
+    send_BEGIN(type, "files", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->openfiles);
+    }
+    send_END();
+
+    send_BEGIN(type, "sockets", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->opensockets);
+    }
+    send_END();
+
+    send_BEGIN(type, "pipes", usec);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            send_SET(w->name, w->openpipes);
+    }
+    send_END();
 }
 
 
@@ -2537,121 +2537,121 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
 
 void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
 {
-       struct target *w;
-       int newly_added = 0;
-
-       for(w = root ; w ; w = w->next) {
-               if (w->target) continue;
-
-               if (!w->exposed && w->processes) {
-                       newly_added++;
-                       w->exposed = 1;
-                       if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name);
-               }
-       }
-
-       // nothing more to show
-       if(!newly_added && show_guest_time == show_guest_time_old) return;
-
-       // we have something new to show
-       // update the charts
-       buffer_sprintf(output, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
-       }
-
-       buffer_sprintf(output, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
-       }
-
-       buffer_sprintf(output, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-       }
-
-       buffer_sprintf(output, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-       }
-
-       buffer_sprintf(output, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
-       }
-
-       buffer_sprintf(output, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
-       }
-
-       if(show_guest_time) {
-               buffer_sprintf(output, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
-               for (w = root; w; w = w->next) {
-                       if(unlikely(w->exposed))
-                               buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
-               }
-       }
-
-       buffer_sprintf(output, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
-       }
-
-       buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-       }
-
-       buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-       }
-
-       buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
-       for (w = root; w ; w = w->next) {
-               if(unlikely(w->exposed))
-                       buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
-       }
+    struct target *w;
+    int newly_added = 0;
+
+    for(w = root ; w ; w = w->next) {
+        if (w->target) continue;
+
+        if (!w->exposed && w->processes) {
+            newly_added++;
+            w->exposed = 1;
+            if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name);
+        }
+    }
+
+    // nothing more to show
+    if(!newly_added && show_guest_time == show_guest_time_old) return;
+
+    // we have something new to show
+    // update the charts
+    buffer_sprintf(output, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
+    }
+
+    buffer_sprintf(output, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
+    }
+
+    buffer_sprintf(output, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+    }
+
+    buffer_sprintf(output, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+    }
+
+    buffer_sprintf(output, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+    }
+
+    buffer_sprintf(output, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+    }
+
+    if(show_guest_time) {
+        buffer_sprintf(output, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
+        for (w = root; w; w = w->next) {
+            if(unlikely(w->exposed))
+                buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
+        }
+    }
+
+    buffer_sprintf(output, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
+    }
+
+    buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+    }
+
+    buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+    }
+
+    buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
+    for (w = root; w ; w = w->next) {
+        if(unlikely(w->exposed))
+            buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
+    }
 }
 
 
@@ -2660,33 +2660,33 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
 
 void parse_args(int argc, char **argv)
 {
-       int i, freq = 0;
-       char *name = NULL;
-
-       for(i = 1; i < argc; i++) {
-               if(!freq) {
-                       int n = atoi(argv[i]);
-                       if(n > 0) {
-                               freq = n;
-                               continue;
-                       }
-               }
-
-               if(strcmp("debug", argv[i]) == 0) {
-                       debug = 1;
-                       // debug_flags = 0xffffffff;
-                       continue;
-               }
-
-               if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) {
-                       include_exited_childs = 0;
-                       continue;
-               }
-
-               if(strcmp("with-childs", argv[i]) == 0) {
-                       include_exited_childs = 1;
-                       continue;
-               }
+    int i, freq = 0;
+    char *name = NULL;
+
+    for(i = 1; i < argc; i++) {
+        if(!freq) {
+            int n = atoi(argv[i]);
+            if(n > 0) {
+                freq = n;
+                continue;
+            }
+        }
+
+        if(strcmp("debug", argv[i]) == 0) {
+            debug = 1;
+            // debug_flags = 0xffffffff;
+            continue;
+        }
+
+        if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) {
+            include_exited_childs = 0;
+            continue;
+        }
+
+        if(strcmp("with-childs", argv[i]) == 0) {
+            include_exited_childs = 1;
+            continue;
+        }
 
         if(strcmp("with-guest", argv[i]) == 0) {
             enable_guest_charts = 1;
@@ -2698,7 +2698,7 @@ void parse_args(int argc, char **argv)
             continue;
         }
 
-               if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
+        if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
             fprintf(stderr,
                     "apps.plugin\n"
                     "(C) 2016 Costa Tsaousis"
@@ -2728,161 +2728,161 @@ void parse_args(int argc, char **argv)
         }
 
         if(!name) {
-                       name = argv[i];
-                       continue;
-               }
+            name = argv[i];
+            continue;
+        }
 
-               error("Cannot understand option %s", argv[i]);
-               exit(1);
-       }
+        error("Cannot understand option %s", argv[i]);
+        exit(1);
+    }
 
-       if(freq > 0) update_every = freq;
-       if(!name) name = "groups";
+    if(freq > 0) update_every = freq;
+    if(!name) name = "groups";
 
-       if(read_apps_groups_conf(name)) {
-               error("Cannot read process groups %s", name);
-               exit(1);
-       }
+    if(read_apps_groups_conf(name)) {
+        error("Cannot read process groups %s", name);
+        exit(1);
+    }
 }
 
 int main(int argc, char **argv)
 {
-       // debug_flags = D_PROCFILE;
+    // debug_flags = D_PROCFILE;
 
-       // set the name for logging
-       program_name = "apps.plugin";
+    // set the name for logging
+    program_name = "apps.plugin";
 
-       // disable syslog for apps.plugin
-       error_log_syslog = 0;
+    // disable syslog for apps.plugin
+    error_log_syslog = 0;
 
-       // set errors flood protection to 100 logs per hour
-       error_log_errors_per_period = 100;
-       error_log_throttle_period = 3600;
+    // set errors flood protection to 100 logs per hour
+    error_log_errors_per_period = 100;
+    error_log_throttle_period = 3600;
 
-       host_prefix = getenv("NETDATA_HOST_PREFIX");
-       if(host_prefix == NULL) {
-               info("NETDATA_HOST_PREFIX is not passed from netdata");
-               host_prefix = "";
-       }
-       else info("Found NETDATA_HOST_PREFIX='%s'", host_prefix);
+    host_prefix = getenv("NETDATA_HOST_PREFIX");
+    if(host_prefix == NULL) {
+        info("NETDATA_HOST_PREFIX is not passed from netdata");
+        host_prefix = "";
+    }
+    else info("Found NETDATA_HOST_PREFIX='%s'", host_prefix);
 
-       config_dir = getenv("NETDATA_CONFIG_DIR");
-       if(config_dir == NULL) {
-               info("NETDATA_CONFIG_DIR is not passed from netdata");
-               config_dir = CONFIG_DIR;
-       }
-       else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
+    config_dir = getenv("NETDATA_CONFIG_DIR");
+    if(config_dir == NULL) {
+        info("NETDATA_CONFIG_DIR is not passed from netdata");
+        config_dir = CONFIG_DIR;
+    }
+    else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
 
 #ifdef NETDATA_INTERNAL_CHECKS
-       if(debug_flags != 0) {
-               struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
-               if(setrlimit(RLIMIT_CORE, &rl) != 0)
-                       info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
-               prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-       }
+    if(debug_flags != 0) {
+        struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
+        if(setrlimit(RLIMIT_CORE, &rl) != 0)
+            info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+        prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+    }
 #endif /* NETDATA_INTERNAL_CHECKS */
 
-       procfile_adaptive_initial_allocation = 1;
-
-       time_t started_t = time(NULL);
-       time_t current_t;
-       get_HZ();
-       pid_max = get_system_pid_max();
-       processors = get_system_cpus();
-
-       parse_args(argc, argv);
-
-       all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
-       all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
-
-       output = buffer_create(1024);
-       buffer_sprintf(output,
-               "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
-               "DIMENSION user '' incremental 1 1000\n"
-               "DIMENSION system '' incremental 1 1000\n"
-               "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
-               "DIMENSION files '' incremental 1 1\n"
-               "DIMENSION pids '' absolute 1 1\n"
-               "DIMENSION fds '' absolute 1 1\n"
-               "DIMENSION targets '' absolute 1 1\n"
-               "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
-               "DIMENSION utime '' absolute 1 %2$llu\n"
-               "DIMENSION stime '' absolute 1 %2$llu\n"
-               "DIMENSION gtime '' absolute 1 %2$llu\n"
-               "DIMENSION minflt '' absolute 1 %2$llu\n"
-               "DIMENSION majflt '' absolute 1 %2$llu\n"
-               , update_every
-               , RATES_DETAIL
-               );
-
-       if(include_exited_childs)
-               buffer_sprintf(output,
-                       "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
-                       "DIMENSION cutime '' absolute 1 %2$llu\n"
-                       "DIMENSION cstime '' absolute 1 %2$llu\n"
-                       "DIMENSION cgtime '' absolute 1 %2$llu\n"
-                       "DIMENSION cminflt '' absolute 1 %2$llu\n"
-                       "DIMENSION cmajflt '' absolute 1 %2$llu\n"
-                       , update_every
-                       , RATES_DETAIL
-                       );
+    procfile_adaptive_initial_allocation = 1;
+
+    time_t started_t = time(NULL);
+    time_t current_t;
+    get_HZ();
+    pid_max = get_system_pid_max();
+    processors = get_system_cpus();
+
+    parse_args(argc, argv);
+
+    all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
+    all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
+
+    output = buffer_create(1024);
+    buffer_sprintf(output,
+        "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
+        "DIMENSION user '' incremental 1 1000\n"
+        "DIMENSION system '' incremental 1 1000\n"
+        "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
+        "DIMENSION files '' incremental 1 1\n"
+        "DIMENSION pids '' absolute 1 1\n"
+        "DIMENSION fds '' absolute 1 1\n"
+        "DIMENSION targets '' absolute 1 1\n"
+        "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
+        "DIMENSION utime '' absolute 1 %2$llu\n"
+        "DIMENSION stime '' absolute 1 %2$llu\n"
+        "DIMENSION gtime '' absolute 1 %2$llu\n"
+        "DIMENSION minflt '' absolute 1 %2$llu\n"
+        "DIMENSION majflt '' absolute 1 %2$llu\n"
+        , update_every
+        , RATES_DETAIL
+        );
+
+    if(include_exited_childs)
+        buffer_sprintf(output,
+            "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
+            "DIMENSION cutime '' absolute 1 %2$llu\n"
+            "DIMENSION cstime '' absolute 1 %2$llu\n"
+            "DIMENSION cgtime '' absolute 1 %2$llu\n"
+            "DIMENSION cminflt '' absolute 1 %2$llu\n"
+            "DIMENSION cmajflt '' absolute 1 %2$llu\n"
+            , update_every
+            , RATES_DETAIL
+            );
 
 #ifndef PROFILING_MODE
-       unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
-       unsigned long long sunow;
+    unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
+    unsigned long long sunow;
 #endif /* PROFILING_MODE */
 
-       global_iterations_counter = 1;
-       for(;1; global_iterations_counter++) {
+    global_iterations_counter = 1;
+    for(;1; global_iterations_counter++) {
 #ifndef PROFILING_MODE
-               // delay until it is our time to run
-               while((sunow = time_usec()) < sunext)
-                       sleep_usec(sunext - sunow);
+        // delay until it is our time to run
+        while((sunow = time_usec()) < sunext)
+            sleep_usec(sunext - sunow);
 
-               // find the next time we need to run
-               while(time_usec() > sunext)
-                       sunext += update_every * 1000000ULL;
+        // find the next time we need to run
+        while(time_usec() > sunext)
+            sunext += update_every * 1000000ULL;
 #endif /* PROFILING_MODE */
 
-               if(!collect_data_for_all_processes_from_proc()) {
-                       error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
-                       printf("DISABLE\n");
-                       exit(1);
-               }
+        if(!collect_data_for_all_processes_from_proc()) {
+            error("Cannot collect /proc data for running processes. Disabling apps.plugin...");
+            printf("DISABLE\n");
+            exit(1);
+        }
 
-               calculate_netdata_statistics();
-               normalize_data(apps_groups_root_target);
+        calculate_netdata_statistics();
+        normalize_data(apps_groups_root_target);
 
-               unsigned long long dt = send_resource_usage_to_netdata();
+        unsigned long long dt = send_resource_usage_to_netdata();
 
-               // this is smart enough to show only newly added apps, when needed
-               send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps");
-               send_charts_updates_to_netdata(users_root_target, "users", "Users");
-               send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups");
+        // this is smart enough to show only newly added apps, when needed
+        send_charts_updates_to_netdata(apps_groups_root_target, "apps", "Apps");
+        send_charts_updates_to_netdata(users_root_target, "users", "Users");
+        send_charts_updates_to_netdata(groups_root_target, "groups", "User Groups");
 
-               send_collected_data_to_netdata(apps_groups_root_target, "apps", dt);
-               send_collected_data_to_netdata(users_root_target, "users", dt);
-               send_collected_data_to_netdata(groups_root_target, "groups", dt);
+        send_collected_data_to_netdata(apps_groups_root_target, "apps", dt);
+        send_collected_data_to_netdata(users_root_target, "users", dt);
+        send_collected_data_to_netdata(groups_root_target, "groups", dt);
 
-               show_guest_time_old = show_guest_time;
+        show_guest_time_old = show_guest_time;
 
-               //if(puts(buffer_tostring(output)) == EOF)
-               if(write(STDOUT_FILENO, buffer_tostring(output), buffer_strlen(output)) == -1)
-                       fatal("Cannot send chart values to netdata.");
+        //if(puts(buffer_tostring(output)) == EOF)
+        if(write(STDOUT_FILENO, buffer_tostring(output), buffer_strlen(output)) == -1)
+            fatal("Cannot send chart values to netdata.");
 
-               // fflush(stdout);
-               buffer_flush(output);
+        // fflush(stdout);
+        buffer_flush(output);
 
-               if(unlikely(debug))
-                       fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
+        if(unlikely(debug))
+            fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
 
-               current_t = time(NULL);
+        current_t = time(NULL);
 
 #ifndef PROFILING_MODE
-               // restart check (14400 seconds)
-               if(current_t - started_t > 14400) exit(0);
+        // restart check (14400 seconds)
+        if(current_t - started_t > 14400) exit(0);
 #else
-               if(current_t - started_t > 10) exit(0);
+        if(current_t - started_t > 10) exit(0);
 #endif /* PROFILING_MODE */
-       }
+    }
 }
index 71d206f23e45894f0d1cdb83364d18cef666cd8c..aa45fff44f6afcf17bd8a01a0eca9497666b9fe7 100644 (file)
--- a/src/avl.c
+++ b/src/avl.c
@@ -15,7 +15,7 @@
 
 
 /* Search |tree| for an item matching |item|, and return it if found.
-        Otherwise return |NULL|. */
+     Otherwise return |NULL|. */
 avl *avl_search(avl_tree *tree, avl *item) {
     avl *p;
 
@@ -36,8 +36,8 @@ avl *avl_search(avl_tree *tree, avl *item) {
 }
 
 /* Inserts |item| into |tree| and returns a pointer to |item|'s address.
-        If a duplicate item is found in the tree,
-        returns a pointer to the duplicate without inserting |item|.
+     If a duplicate item is found in the tree,
+     returns a pointer to the duplicate without inserting |item|.
  */
 avl *avl_insert(avl_tree *tree, avl *item) {
     avl *y, *z; /* Top node to update balance factor, and parent. */
@@ -134,7 +134,7 @@ avl *avl_insert(avl_tree *tree, avl *item) {
 }
 
 /* Deletes from |tree| and returns an item matching |item|.
-        Returns a null pointer if no matching item found. */
+     Returns a null pointer if no matching item found. */
 avl *avl_remove(avl_tree *tree, avl *item) {
     /* Stack of nodes. */
     avl *pa[AVL_MAX_HEIGHT]; /* Nodes. */
@@ -283,9 +283,9 @@ avl *avl_remove(avl_tree *tree, avl *item) {
 void avl_read_lock(avl_tree_lock *t) {
 #ifndef AVL_WITHOUT_PTHREADS
 #ifdef AVL_LOCK_WITH_MUTEX
-       pthread_mutex_lock(&t->mutex);
+    pthread_mutex_lock(&t->mutex);
 #else
-       pthread_rwlock_rdlock(&t->rwlock);
+    pthread_rwlock_rdlock(&t->rwlock);
 #endif
 #endif /* AVL_WITHOUT_PTHREADS */
 }
@@ -293,9 +293,9 @@ void avl_read_lock(avl_tree_lock *t) {
 void avl_write_lock(avl_tree_lock *t) {
 #ifndef AVL_WITHOUT_PTHREADS
 #ifdef AVL_LOCK_WITH_MUTEX
-       pthread_mutex_lock(&t->mutex);
+    pthread_mutex_lock(&t->mutex);
 #else
-       pthread_rwlock_wrlock(&t->rwlock);
+    pthread_rwlock_wrlock(&t->rwlock);
 #endif
 #endif /* AVL_WITHOUT_PTHREADS */
 }
@@ -303,9 +303,9 @@ void avl_write_lock(avl_tree_lock *t) {
 void avl_unlock(avl_tree_lock *t) {
 #ifndef AVL_WITHOUT_PTHREADS
 #ifdef AVL_LOCK_WITH_MUTEX
-       pthread_mutex_unlock(&t->mutex);
+    pthread_mutex_unlock(&t->mutex);
 #else
-       pthread_rwlock_unlock(&t->rwlock);
+    pthread_rwlock_unlock(&t->rwlock);
 #endif
 #endif /* AVL_WITHOUT_PTHREADS */
 }
@@ -313,42 +313,42 @@ void avl_unlock(avl_tree_lock *t) {
 /* ------------------------------------------------------------------------- */
 
 void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
-       avl_init(&t->avl_tree, compar);
+    avl_init(&t->avl_tree, compar);
 
 #ifndef AVL_WITHOUT_PTHREADS
-       int lock;
+    int lock;
 
 #ifdef AVL_LOCK_WITH_MUTEX
-       lock = pthread_mutex_init(&t->mutex, NULL);
+    lock = pthread_mutex_init(&t->mutex, NULL);
 #else
-       lock = pthread_rwlock_init(&t->rwlock, NULL);
+    lock = pthread_rwlock_init(&t->rwlock, NULL);
 #endif
 
-       if(lock != 0)
-               fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock);
+    if(lock != 0)
+        fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock);
 
 #endif /* AVL_WITHOUT_PTHREADS */
 }
 
 avl *avl_search_lock(avl_tree_lock *t, avl *a) {
-       avl_read_lock(t);
-       avl *ret = avl_search(&t->avl_tree, a);
-       avl_unlock(t);
-       return ret;
+    avl_read_lock(t);
+    avl *ret = avl_search(&t->avl_tree, a);
+    avl_unlock(t);
+    return ret;
 }
 
 avl * avl_remove_lock(avl_tree_lock *t, avl *a) {
-       avl_write_lock(t);
-       avl *ret = avl_remove(&t->avl_tree, a);
-       avl_unlock(t);
-       return ret;
+    avl_write_lock(t);
+    avl *ret = avl_remove(&t->avl_tree, a);
+    avl_unlock(t);
+    return ret;
 }
 
 avl *avl_insert_lock(avl_tree_lock *t, avl *a) {
-       avl_write_lock(t);
+    avl_write_lock(t);
     avl * ret = avl_insert(&t->avl_tree, a);
-       avl_unlock(t);
-       return ret;
+    avl_unlock(t);
+    return ret;
 }
 
 void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
index 98e60371899fdc77343b169a64dd125fba9525cd..79237ab25924ebff89d49b9b5a88a8f95a564323 100644 (file)
--- a/src/avl.h
+++ b/src/avl.h
@@ -32,18 +32,18 @@ typedef struct avl {
 
 /* An AVL tree */
 typedef struct avl_tree {
-       avl *root;
-       int (*compar)(void *a, void *b);
+    avl *root;
+    int (*compar)(void *a, void *b);
 } avl_tree;
 
 typedef struct avl_tree_lock {
-       avl_tree avl_tree;
+    avl_tree avl_tree;
 
 #ifndef AVL_WITHOUT_PTHREADS
 #ifdef AVL_LOCK_WITH_MUTEX
-       pthread_mutex_t mutex;
+    pthread_mutex_t mutex;
 #else /* AVL_LOCK_WITH_MUTEX */
-       pthread_rwlock_t rwlock;
+    pthread_rwlock_t rwlock;
 #endif /* AVL_LOCK_WITH_MUTEX */
 #endif /* AVL_WITHOUT_PTHREADS */
 } avl_tree_lock;
index c1fac930e238dc5d43a09e562fdc8837261b211f..74f26e3b2a95d912315bee8e66f170633e82055a 100644 (file)
@@ -642,15 +642,15 @@ void netdata_fix_chart_id(char *s) {
 // http://stackoverflow.com/questions/7666509/hash-function-for-string
 uint32_t simple_hash(const char *name)
 {
-       const char *s = name;
-       uint32_t hash = 5381;
-       int i;
+    const char *s = name;
+    uint32_t hash = 5381;
+    int i;
 
-       while((i = *s++)) hash = ((hash << 5) + hash) + i;
+    while((i = *s++)) hash = ((hash << 5) + hash) + i;
 
-       // fprintf(stderr, "HASH: %lu %s\n", hash, name);
+    // fprintf(stderr, "HASH: %lu %s\n", hash, name);
 
-       return hash;
+    return hash;
 }
 */
 
@@ -694,22 +694,22 @@ uint32_t simple_uhash(const char *name) {
 // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
 // one at a time hash
 uint32_t simple_hash(const char *name) {
-       unsigned char *s = (unsigned char *)name;
-       uint32_t h = 0;
+    unsigned char *s = (unsigned char *)name;
+    uint32_t h = 0;
 
-       while(*s) {
-               h += *s++;
-               h += (h << 10);
-               h ^= (h >> 6);
-       }
+    while(*s) {
+        h += *s++;
+        h += (h << 10);
+        h ^= (h >> 6);
+    }
 
-       h += (h << 3);
-       h ^= (h >> 11);
-       h += (h << 15);
+    h += (h << 3);
+    h ^= (h >> 11);
+    h += (h << 15);
 
-       // fprintf(stderr, "HASH: %u = %s\n", h, name);
+    // fprintf(stderr, "HASH: %u = %s\n", h, name);
 
-       return h;
+    return h;
 }
 */
 
@@ -782,16 +782,16 @@ void *mymmap(const char *filename, size_t size, int flags, int ksm) {
 #ifdef MADV_MERGEABLE
                 } else {
 /*
-                                       // test - load the file into memory
-                                       mem = calloc(1, size);
-                                       if(mem) {
-                                               if(lseek(fd, 0, SEEK_SET) == 0) {
-                                                       if(read(fd, mem, size) != (ssize_t)size)
-                                                               error("Cannot read from file '%s'", filename);
-                                               }
-                                               else
-                                                       error("Cannot seek to beginning of file '%s'.", filename);
-                                       }
+                    // test - load the file into memory
+                    mem = calloc(1, size);
+                    if(mem) {
+                        if(lseek(fd, 0, SEEK_SET) == 0) {
+                            if(read(fd, mem, size) != (ssize_t)size)
+                                error("Cannot read from file '%s'", filename);
+                        }
+                        else
+                            error("Cannot seek to beginning of file '%s'.", filename);
+                    }
 */
                     mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
                     if (mem != MAP_FAILED) {
index 5d24b6cabe39ab7951b9c683d45eda7c5b8b083d..8653e3b9450d7ce3e23098bd79072d863b5a87f2 100644 (file)
@@ -23,195 +23,195 @@ void sig_handler_logrotate(int signo)
 
 void sig_handler_save(int signo)
 {
-       if(signo) {
+    if(signo) {
         error_log_limit_reset();
-               info("Received signal %d to save the database...", signo);
-               rrdset_save_all();
-       }
+        info("Received signal %d to save the database...", signo);
+        rrdset_save_all();
+    }
 }
 
 static void chown_open_file(int fd, uid_t uid, gid_t gid) {
-       if(fd == -1) return;
+    if(fd == -1) return;
 
-       struct stat buf;
+    struct stat buf;
 
-       if(fstat(fd, &buf) == -1) {
-               error("Cannot fstat() fd %d", fd);
-               return;
-       }
+    if(fstat(fd, &buf) == -1) {
+        error("Cannot fstat() fd %d", fd);
+        return;
+    }
 
-       if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
-               if(fchown(fd, uid, gid) == -1)
-                       error("Cannot fchown() fd %d.", fd);
-       }
+    if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
+        if(fchown(fd, uid, gid) == -1)
+            error("Cannot fchown() fd %d.", fd);
+    }
 }
 
 int become_user(const char *username, int pid_fd)
 {
-       struct passwd *pw = getpwnam(username);
-       if(!pw) {
-               error("User %s is not present.", username);
-               return -1;
-       }
-
-       uid_t uid = pw->pw_uid;
-       gid_t gid = pw->pw_gid;
-
-       int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
-       gid_t *supplementary_groups = NULL;
-       if(ngroups) {
-               supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
-               if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
-                       error("Cannot get supplementary groups of user '%s'.", username);
-                       freez(supplementary_groups);
-                       supplementary_groups = NULL;
-                       ngroups = 0;
-               }
-       }
-
-       chown_open_file(STDOUT_FILENO, uid, gid);
-       chown_open_file(STDERR_FILENO, uid, gid);
-       chown_open_file(stdaccess_fd, uid, gid);
-       chown_open_file(pid_fd, uid, gid);
-
-       if(supplementary_groups && ngroups) {
-               if(setgroups(ngroups, supplementary_groups) == -1)
-                       error("Cannot set supplementary groups for user '%s'", username);
-
-               freez(supplementary_groups);
-               supplementary_groups = NULL;
-               ngroups = 0;
-       }
-
-       if(setresgid(gid, gid, gid) != 0) {
-               error("Cannot switch to user's %s group (gid: %u).", username, gid);
-               return -1;
-       }
-
-       if(setresuid(uid, uid, uid) != 0) {
-               error("Cannot switch to user %s (uid: %u).", username, uid);
-               return -1;
-       }
-
-       if(setgid(gid) != 0) {
-               error("Cannot switch to user's %s group (gid: %u).", username, gid);
-               return -1;
-       }
-       if(setegid(gid) != 0) {
-               error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
-               return -1;
-       }
-       if(setuid(uid) != 0) {
-               error("Cannot switch to user %s (uid: %u).", username, uid);
-               return -1;
-       }
-       if(seteuid(uid) != 0) {
-               error("Cannot effectively switch to user %s (uid: %u).", username, uid);
-               return -1;
-       }
-
-       return(0);
+    struct passwd *pw = getpwnam(username);
+    if(!pw) {
+        error("User %s is not present.", username);
+        return -1;
+    }
+
+    uid_t uid = pw->pw_uid;
+    gid_t gid = pw->pw_gid;
+
+    int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
+    gid_t *supplementary_groups = NULL;
+    if(ngroups) {
+        supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
+        if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
+            error("Cannot get supplementary groups of user '%s'.", username);
+            freez(supplementary_groups);
+            supplementary_groups = NULL;
+            ngroups = 0;
+        }
+    }
+
+    chown_open_file(STDOUT_FILENO, uid, gid);
+    chown_open_file(STDERR_FILENO, uid, gid);
+    chown_open_file(stdaccess_fd, uid, gid);
+    chown_open_file(pid_fd, uid, gid);
+
+    if(supplementary_groups && ngroups) {
+        if(setgroups(ngroups, supplementary_groups) == -1)
+            error("Cannot set supplementary groups for user '%s'", username);
+
+        freez(supplementary_groups);
+        supplementary_groups = NULL;
+        ngroups = 0;
+    }
+
+    if(setresgid(gid, gid, gid) != 0) {
+        error("Cannot switch to user's %s group (gid: %u).", username, gid);
+        return -1;
+    }
+
+    if(setresuid(uid, uid, uid) != 0) {
+        error("Cannot switch to user %s (uid: %u).", username, uid);
+        return -1;
+    }
+
+    if(setgid(gid) != 0) {
+        error("Cannot switch to user's %s group (gid: %u).", username, gid);
+        return -1;
+    }
+    if(setegid(gid) != 0) {
+        error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
+        return -1;
+    }
+    if(setuid(uid) != 0) {
+        error("Cannot switch to user %s (uid: %u).", username, uid);
+        return -1;
+    }
+    if(seteuid(uid) != 0) {
+        error("Cannot effectively switch to user %s (uid: %u).", username, uid);
+        return -1;
+    }
+
+    return(0);
 }
 
 void oom_score_adj(int score) {
-       int done = 0;
-       int fd = open("/proc/self/oom_score_adj", O_WRONLY);
-       if(fd != -1) {
-               char buf[10 + 1];
-               ssize_t len = snprintfz(buf, 10, "%d", score);
-               if(write(fd, buf, len) == len) done = 1;
-               close(fd);
-       }
-
-       if(!done)
-               error("Cannot adjust my Out-Of-Memory score to %d.", score);
-       else
-               info("Adjusted my Out-Of-Memory score to %d.", score);
+    int done = 0;
+    int fd = open("/proc/self/oom_score_adj", O_WRONLY);
+    if(fd != -1) {
+        char buf[10 + 1];
+        ssize_t len = snprintfz(buf, 10, "%d", score);
+        if(write(fd, buf, len) == len) done = 1;
+        close(fd);
+    }
+
+    if(!done)
+        error("Cannot adjust my Out-Of-Memory score to %d.", score);
+    else
+        info("Adjusted my Out-Of-Memory score to %d.", score);
 }
 
 int sched_setscheduler_idle(void) {
-       const struct sched_param param = {
-               .sched_priority = 0
-       };
+    const struct sched_param param = {
+        .sched_priority = 0
+    };
 
-       int i = sched_setscheduler(0, SCHED_IDLE, &param);
-       if(i != 0)
-               error("Cannot adjust my scheduling priority to IDLE.");
-       else
-               info("Adjusted my scheduling priority to IDLE.");
+    int i = sched_setscheduler(0, SCHED_IDLE, &param);
+    if(i != 0)
+        error("Cannot adjust my scheduling priority to IDLE.");
+    else
+        info("Adjusted my scheduling priority to IDLE.");
 
-       return i;
+    return i;
 }
 
 int become_daemon(int dont_fork, const char *user)
 {
-       if(!dont_fork) {
-               int i = fork();
-               if(i == -1) {
-                       perror("cannot fork");
-                       exit(1);
-               }
-               if(i != 0) {
-                       exit(0); // the parent
-               }
-
-               // become session leader
-               if (setsid() < 0) {
-                       perror("Cannot become session leader.");
-                       exit(2);
-               }
-
-               // fork() again
-               i = fork();
-               if(i == -1) {
-                       perror("cannot fork");
-                       exit(1);
-               }
-               if(i != 0) {
-                       exit(0); // the parent
-               }
-       }
-
-       // generate our pid file
-       int pidfd = -1;
-       if(pidfile[0]) {
-               pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644);
-               if(pidfd >= 0) {
-                       if(ftruncate(pidfd, 0) != 0)
-                               error("Cannot truncate pidfile '%s'.", pidfile);
-
-                       char b[100];
-                       sprintf(b, "%d\n", getpid());
-                       ssize_t i = write(pidfd, b, strlen(b));
-                       if(i <= 0)
-                               error("Cannot write pidfile '%s'.", pidfile);
-               }
-               else error("Failed to open pidfile '%s'.", pidfile);
-       }
-
-       // Set new file permissions
-       umask(0002);
-
-       // adjust my Out-Of-Memory score
-       oom_score_adj(1000);
-
-       // never become a problem
-       if(sched_setscheduler_idle() != 0) {
-               if(nice(19) == -1) error("Cannot lower my CPU priority.");
-               else info("Set my nice value to 19.");
-       }
-
-       if(user && *user) {
-               if(become_user(user, pidfd) != 0) {
-                       error("Cannot become user '%s'. Continuing as we are.", user);
-               }
-               else info("Successfully became user '%s'.", user);
-       }
-
-       if(pidfd != -1) {
-               close(pidfd);
-               pidfd = -1;
-       }
-
-       return(0);
+    if(!dont_fork) {
+        int i = fork();
+        if(i == -1) {
+            perror("cannot fork");
+            exit(1);
+        }
+        if(i != 0) {
+            exit(0); // the parent
+        }
+
+        // become session leader
+        if (setsid() < 0) {
+            perror("Cannot become session leader.");
+            exit(2);
+        }
+
+        // fork() again
+        i = fork();
+        if(i == -1) {
+            perror("cannot fork");
+            exit(1);
+        }
+        if(i != 0) {
+            exit(0); // the parent
+        }
+    }
+
+    // generate our pid file
+    int pidfd = -1;
+    if(pidfile[0]) {
+        pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644);
+        if(pidfd >= 0) {
+            if(ftruncate(pidfd, 0) != 0)
+                error("Cannot truncate pidfile '%s'.", pidfile);
+
+            char b[100];
+            sprintf(b, "%d\n", getpid());
+            ssize_t i = write(pidfd, b, strlen(b));
+            if(i <= 0)
+                error("Cannot write pidfile '%s'.", pidfile);
+        }
+        else error("Failed to open pidfile '%s'.", pidfile);
+    }
+
+    // Set new file permissions
+    umask(0002);
+
+    // adjust my Out-Of-Memory score
+    oom_score_adj(1000);
+
+    // never become a problem
+    if(sched_setscheduler_idle() != 0) {
+        if(nice(19) == -1) error("Cannot lower my CPU priority.");
+        else info("Set my nice value to 19.");
+    }
+
+    if(user && *user) {
+        if(become_user(user, pidfd) != 0) {
+            error("Cannot become user '%s'. Continuing as we are.", user);
+        }
+        else info("Successfully became user '%s'.", user);
+    }
+
+    if(pidfd != -1) {
+        close(pidfd);
+        pidfd = -1;
+    }
+
+    return(0);
 }
index 6f2a5902de1ea241b87f92c4b365d5c92b74992b..91d3b45f1f8be424be9e1e68133babac17423b0d 100644 (file)
@@ -4,24 +4,24 @@
 // dictionary statistics
 
 static inline void NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(DICTIONARY *dict) {
-       if(likely(dict->stats))
-               dict->stats->inserts++;
+    if(likely(dict->stats))
+        dict->stats->inserts++;
 }
 static inline void NETDATA_DICTIONARY_STATS_DELETES_PLUS1(DICTIONARY *dict) {
-       if(likely(dict->stats))
-               dict->stats->deletes++;
+    if(likely(dict->stats))
+        dict->stats->deletes++;
 }
 static inline void NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(DICTIONARY *dict) {
-       if(likely(dict->stats))
-               dict->stats->searches++;
+    if(likely(dict->stats))
+        dict->stats->searches++;
 }
 static inline void NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(DICTIONARY *dict) {
-       if(likely(dict->stats))
-               dict->stats->entries++;
+    if(likely(dict->stats))
+        dict->stats->entries++;
 }
 static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
-       if(likely(dict->stats))
-               dict->stats->entries--;
+    if(likely(dict->stats))
+        dict->stats->entries--;
 }
 
 
@@ -29,24 +29,24 @@ static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
 // dictionary locks
 
 static inline void dictionary_read_lock(DICTIONARY *dict) {
-       if(likely(dict->rwlock)) {
-               // debug(D_DICTIONARY, "Dictionary READ lock");
-               pthread_rwlock_rdlock(dict->rwlock);
-       }
+    if(likely(dict->rwlock)) {
+        // debug(D_DICTIONARY, "Dictionary READ lock");
+        pthread_rwlock_rdlock(dict->rwlock);
+    }
 }
 
 static inline void dictionary_write_lock(DICTIONARY *dict) {
-       if(likely(dict->rwlock)) {
-               // debug(D_DICTIONARY, "Dictionary WRITE lock");
-               pthread_rwlock_wrlock(dict->rwlock);
-       }
+    if(likely(dict->rwlock)) {
+        // debug(D_DICTIONARY, "Dictionary WRITE lock");
+        pthread_rwlock_wrlock(dict->rwlock);
+    }
 }
 
 static inline void dictionary_unlock(DICTIONARY *dict) {
-       if(likely(dict->rwlock)) {
-               // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
-               pthread_rwlock_unlock(dict->rwlock);
-       }
+    if(likely(dict->rwlock)) {
+        // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
+        pthread_rwlock_unlock(dict->rwlock);
+    }
 }
 
 
@@ -54,196 +54,196 @@ static inline void dictionary_unlock(DICTIONARY *dict) {
 // avl index
 
 static int name_value_compare(void* a, void* b) {
-       if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
-       else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
-       else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
+    if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
+    else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
+    else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
 }
 
 #define dictionary_name_value_index_add_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
 #define dictionary_name_value_index_del_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
 
 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
-       NAME_VALUE tmp;
-       tmp.hash = (hash)?hash:simple_hash(name);
-       tmp.name = (char *)name;
+    NAME_VALUE tmp;
+    tmp.hash = (hash)?hash:simple_hash(name);
+    tmp.name = (char *)name;
 
-       NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict);
-       return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp);
+    NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict);
+    return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp);
 }
 
 // ----------------------------------------------------------------------------
 // internal methods
 
 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
-       debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
+    debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
 
-       NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE));
+    NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE));
 
-       if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
-               nv->name = (char *)name;
-       else {
-               nv->name = strdupz(name);
-       }
+    if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
+        nv->name = (char *)name;
+    else {
+        nv->name = strdupz(name);
+    }
 
-       nv->hash = (hash)?hash:simple_hash(nv->name);
+    nv->hash = (hash)?hash:simple_hash(nv->name);
 
-       if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
-               nv->value = value;
-       else {
-               nv->value = mallocz(value_len);
-               memcpy(nv->value, value, value_len);
-       }
+    if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
+        nv->value = value;
+    else {
+        nv->value = mallocz(value_len);
+        memcpy(nv->value, value, value_len);
+    }
 
-       // index it
-       dictionary_name_value_index_add_nolock(dict, nv);
-       NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict);
+    // index it
+    dictionary_name_value_index_add_nolock(dict, nv);
+    NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict);
 
-       return nv;
+    return nv;
 }
 
 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
-       debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
+    debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
 
-       dictionary_name_value_index_del_nolock(dict, nv);
+    dictionary_name_value_index_del_nolock(dict, nv);
 
-       NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict);
+    NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict);
 
-       if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
-               debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
-               freez(nv->value);
-       }
+    if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
+        debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
+        freez(nv->value);
+    }
 
-       if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
-               debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
-               freez(nv->name);
-       }
+    if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
+        debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
+        freez(nv->name);
+    }
 
-       freez(nv);
+    freez(nv);
 }
 
 // ----------------------------------------------------------------------------
 // API - basic methods
 
 DICTIONARY *dictionary_create(uint8_t flags) {
-       debug(D_DICTIONARY, "Creating dictionary.");
+    debug(D_DICTIONARY, "Creating dictionary.");
 
-       DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
+    DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
 
-       if(flags & DICTIONARY_FLAG_WITH_STATISTICS)
-               dict->stats = callocz(1, sizeof(struct dictionary_stats));
+    if(flags & DICTIONARY_FLAG_WITH_STATISTICS)
+        dict->stats = callocz(1, sizeof(struct dictionary_stats));
 
-       if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
-               dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
-               pthread_rwlock_init(dict->rwlock, NULL);
-       }
+    if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
+        dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
+        pthread_rwlock_init(dict->rwlock, NULL);
+    }
 
-       avl_init(&dict->values_index, name_value_compare);
-       dict->flags = flags;
+    avl_init(&dict->values_index, name_value_compare);
+    dict->flags = flags;
 
-       return dict;
+    return dict;
 }
 
 void dictionary_destroy(DICTIONARY *dict) {
-       debug(D_DICTIONARY, "Destroying dictionary.");
+    debug(D_DICTIONARY, "Destroying dictionary.");
 
-       dictionary_write_lock(dict);
+    dictionary_write_lock(dict);
 
-       while(dict->values_index.root)
-               dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
+    while(dict->values_index.root)
+        dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
 
-       dictionary_unlock(dict);
+    dictionary_unlock(dict);
 
-       if(dict->stats)
-               freez(dict->stats);
+    if(dict->stats)
+        freez(dict->stats);
 
-       if(dict->rwlock)
-               freez(dict->rwlock);
+    if(dict->rwlock)
+        freez(dict->rwlock);
 
-       freez(dict);
+    freez(dict);
 }
 
 // ----------------------------------------------------------------------------
 
 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
-       debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
+    debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
 
-       uint32_t hash = simple_hash(name);
+    uint32_t hash = simple_hash(name);
 
-       dictionary_write_lock(dict);
+    dictionary_write_lock(dict);
 
-       NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
-       if(unlikely(!nv)) {
-               debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
+    NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
+    if(unlikely(!nv)) {
+        debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
 
-               nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
-               if(unlikely(!nv))
-                       fatal("Cannot create name_value.");
-       }
-       else {
-               debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
+        nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
+        if(unlikely(!nv))
+            fatal("Cannot create name_value.");
+    }
+    else {
+        debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
 
-               if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
-                       debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
-                       nv->value = value;
-               }
-               else {
-                       debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
+        if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
+            debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
+            nv->value = value;
+        }
+        else {
+            debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
 
-                       // copy the new value without breaking
-                       // any other thread accessing the same entry
-                       void *new = mallocz(value_len),
-                                       *old = nv->value;
+            // copy the new value without breaking
+            // any other thread accessing the same entry
+            void *new = mallocz(value_len),
+                    *old = nv->value;
 
-                       memcpy(new, value, value_len);
-                       nv->value = new;
+            memcpy(new, value, value_len);
+            nv->value = new;
 
-                       debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
-                       freez(old);
-               }
-       }
+            debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
+            freez(old);
+        }
+    }
 
-       dictionary_unlock(dict);
+    dictionary_unlock(dict);
 
-       return nv->value;
+    return nv->value;
 }
 
 void *dictionary_get(DICTIONARY *dict, const char *name) {
-       debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
+    debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
 
-       dictionary_read_lock(dict);
-       NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
-       dictionary_unlock(dict);
+    dictionary_read_lock(dict);
+    NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
+    dictionary_unlock(dict);
 
-       if(unlikely(!nv)) {
-               debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
-               return NULL;
-       }
+    if(unlikely(!nv)) {
+        debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
+        return NULL;
+    }
 
-       debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
-       return nv->value;
+    debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
+    return nv->value;
 }
 
 int dictionary_del(DICTIONARY *dict, const char *name) {
-       int ret;
+    int ret;
 
-       debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
+    debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
 
-       dictionary_write_lock(dict);
+    dictionary_write_lock(dict);
 
-       NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
-       if(unlikely(!nv)) {
-               debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
-               ret = -1;
-       }
-       else {
-               debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
-               dictionary_name_value_destroy_nolock(dict, nv);
-               ret = 0;
-       }
+    NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
+    if(unlikely(!nv)) {
+        debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
+        ret = -1;
+    }
+    else {
+        debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
+        dictionary_name_value_destroy_nolock(dict, nv);
+        ret = 0;
+    }
 
-       dictionary_unlock(dict);
+    dictionary_unlock(dict);
 
-       return ret;
+    return ret;
 }
 
 
@@ -253,36 +253,36 @@ int dictionary_del(DICTIONARY *dict, const char *name) {
 // do not user other dictionary calls while walking the dictionary - deadlock!
 
 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
-       int total = 0, ret = 0;
+    int total = 0, ret = 0;
 
-       if(a->avl_link[0]) {
-               ret = dictionary_walker(a->avl_link[0], callback, data);
-               if(ret < 0) return ret;
-               total += ret;
-       }
+    if(a->avl_link[0]) {
+        ret = dictionary_walker(a->avl_link[0], callback, data);
+        if(ret < 0) return ret;
+        total += ret;
+    }
 
-       ret = callback(((NAME_VALUE *)a)->value, data);
-       if(ret < 0) return ret;
-       total += ret;
+    ret = callback(((NAME_VALUE *)a)->value, data);
+    if(ret < 0) return ret;
+    total += ret;
 
-       if(a->avl_link[1]) {
-               ret = dictionary_walker(a->avl_link[1], callback, data);
-               if (ret < 0) return ret;
-               total += ret;
-       }
+    if(a->avl_link[1]) {
+        ret = dictionary_walker(a->avl_link[1], callback, data);
+        if (ret < 0) return ret;
+        total += ret;
+    }
 
-       return total;
+    return total;
 }
 
 int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) {
-       int ret = 0;
+    int ret = 0;
 
-       dictionary_read_lock(dict);
+    dictionary_read_lock(dict);
 
-       if(likely(dict->values_index.root))
-               ret = dictionary_walker(dict->values_index.root, callback, data);
+    if(likely(dict->values_index.root))
+        ret = dictionary_walker(dict->values_index.root, callback, data);
 
-       dictionary_unlock(dict);
+    dictionary_unlock(dict);
 
-       return ret;
+    return ret;
 }
index 4164b6dc7b28e9bd8b45ce89b628a65c67011aa2..6bebbfa857083d08722493bdc0150822bf336a22 100644 (file)
@@ -2,36 +2,36 @@
 #define NETDATA_DICTIONARY_H 1
 
 struct dictionary_stats {
-       unsigned long long inserts;
-       unsigned long long deletes;
-       unsigned long long searches;
-       unsigned long long entries;
+    unsigned long long inserts;
+    unsigned long long deletes;
+    unsigned long long searches;
+    unsigned long long entries;
 };
 
 typedef struct name_value {
-       avl avl;                                // the index - this has to be first!
+    avl avl;                // the index - this has to be first!
 
-       uint32_t hash;                  // a simple hash to speed up searching
-                                                       // we first compare hashes, and only if the hashes are equal we do string comparisons
+    uint32_t hash;          // a simple hash to speed up searching
+                            // we first compare hashes, and only if the hashes are equal we do string comparisons
 
-       char *name;
-       void *value;
+    char *name;
+    void *value;
 } NAME_VALUE;
 
 typedef struct dictionary {
-       avl_tree values_index;
+    avl_tree values_index;
 
-       uint8_t flags;
+    uint8_t flags;
 
-       struct dictionary_stats *stats;
-       pthread_rwlock_t *rwlock;
+    struct dictionary_stats *stats;
+    pthread_rwlock_t *rwlock;
 } DICTIONARY;
 
-#define DICTIONARY_FLAG_DEFAULT                                        0x00000000
-#define DICTIONARY_FLAG_SINGLE_THREADED                        0x00000001
-#define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE  0x00000002
-#define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE   0x00000004
-#define DICTIONARY_FLAG_WITH_STATISTICS                        0x00000008
+#define DICTIONARY_FLAG_DEFAULT                 0x00000000
+#define DICTIONARY_FLAG_SINGLE_THREADED         0x00000001
+#define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE   0x00000002
+#define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE    0x00000004
+#define DICTIONARY_FLAG_WITH_STATISTICS         0x00000008
 
 extern DICTIONARY *dictionary_create(uint8_t flags);
 extern void dictionary_destroy(DICTIONARY *dict);
index 7c7eac3c041ad64debda4ce7e763d30a373f15fa..d28aa4401ce464d4e97b2724a8b48be8314d8ebc 100644 (file)
@@ -7,13 +7,13 @@
 struct global_statistics {
     volatile uint16_t connected_clients;
 
-       volatile uint64_t web_requests;
+    volatile uint64_t web_requests;
     volatile uint64_t web_usec;
     volatile uint64_t web_usec_max;
-       volatile uint64_t bytes_received;
-       volatile uint64_t bytes_sent;
-       volatile uint64_t content_size;
-       volatile uint64_t compressed_content_size;
+    volatile uint64_t bytes_received;
+    volatile uint64_t bytes_sent;
+    volatile uint64_t content_size;
+    volatile uint64_t compressed_content_size;
 };
 
 extern volatile struct global_statistics global_statistics;
index 1cbc6f9c0362d23e139578eafc98935fabe9901f..2fac84cf2563b3e87a5212acd3ef49d49ba23544 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -5,7 +5,7 @@ unsigned long long debug_flags = DEBUG;
 
 int access_log_syslog = 1;
 int error_log_syslog = 1;
-int output_log_syslog = 1;     // debug log
+int output_log_syslog = 1;  // debug log
 
 int stdaccess_fd = -1;
 FILE *stdaccess = NULL;
@@ -124,79 +124,79 @@ time_t error_log_throttle_period = 1200;
 unsigned long error_log_errors_per_period = 200;
 
 int error_log_limit(int reset) {
-       static time_t start = 0;
-       static unsigned long counter = 0, prevented = 0;
-
-       // do not throttle if the period is 0
-       if(error_log_throttle_period == 0)
-               return 0;
-
-       // prevent all logs if the errors per period is 0
-       if(error_log_errors_per_period == 0)
-               return 1;
-
-       time_t now = time(NULL);
-       if(!start) start = now;
-
-       if(reset) {
-               if(prevented) {
-                       log_date(stderr);
-                       fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
-                                       , program_name
-                               , program_name
-                                       , prevented
-                                       , now - start
-                       );
-               }
-
-               start = now;
-               counter = 0;
-               prevented = 0;
-       }
-
-       // detect if we log too much
-       counter++;
-
-       if(now - start > error_log_throttle_period) {
-               if(prevented) {
-                       log_date(stderr);
-                       fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
-                                       , program_name
-                               , program_name
-                                       , prevented
-                                       , error_log_throttle_period
-                       );
-               }
-
-               // restart the period accounting
-               start = now;
-               counter = 1;
-               prevented = 0;
-
-               // log this error
-               return 0;
-       }
-
-       if(counter > error_log_errors_per_period) {
-               if(!prevented) {
-                       log_date(stderr);
-                       fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
-                                       , program_name
-                               , counter
-                               , now - start
-                               , error_log_errors_per_period
-                               , error_log_throttle_period
-                               , program_name
-                                       , start + error_log_throttle_period - now);
-               }
-
-               prevented++;
-
-               // prevent logging this error
-               return 1;
-       }
-
-       return 0;
+    static time_t start = 0;
+    static unsigned long counter = 0, prevented = 0;
+
+    // do not throttle if the period is 0
+    if(error_log_throttle_period == 0)
+        return 0;
+
+    // prevent all logs if the errors per period is 0
+    if(error_log_errors_per_period == 0)
+        return 1;
+
+    time_t now = time(NULL);
+    if(!start) start = now;
+
+    if(reset) {
+        if(prevented) {
+            log_date(stderr);
+            fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
+                    , program_name
+                    , program_name
+                    , prevented
+                    , now - start
+            );
+        }
+
+        start = now;
+        counter = 0;
+        prevented = 0;
+    }
+
+    // detect if we log too much
+    counter++;
+
+    if(now - start > error_log_throttle_period) {
+        if(prevented) {
+            log_date(stderr);
+            fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
+                    , program_name
+                    , program_name
+                    , prevented
+                    , error_log_throttle_period
+            );
+        }
+
+        // restart the period accounting
+        start = now;
+        counter = 1;
+        prevented = 0;
+
+        // log this error
+        return 0;
+    }
+
+    if(counter > error_log_errors_per_period) {
+        if(!prevented) {
+            log_date(stderr);
+            fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
+                    , program_name
+                    , counter
+                    , now - start
+                    , error_log_errors_per_period
+                    , error_log_throttle_period
+                    , program_name
+                    , start + error_log_throttle_period - now);
+        }
+
+        prevented++;
+
+        // prevent logging this error
+        return 1;
+    }
+
+    return 0;
 }
 
 // ----------------------------------------------------------------------------
@@ -208,17 +208,17 @@ int error_log_limit(int reset) {
 
 void log_date(FILE *out)
 {
-               char outstr[24];
-               time_t t;
-               struct tm *tmp, tmbuf;
+        char outstr[24];
+        time_t t;
+        struct tm *tmp, tmbuf;
 
-               t = time(NULL);
-               tmp = localtime_r(&t, &tmbuf);
+        t = time(NULL);
+        tmp = localtime_r(&t, &tmbuf);
 
-               if (tmp == NULL) return;
-               if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
+        if (tmp == NULL) return;
+        if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
 
-               fprintf(out, "%s: ", outstr);
+        fprintf(out, "%s: ", outstr);
 }
 
 // ----------------------------------------------------------------------------
@@ -226,22 +226,22 @@ void log_date(FILE *out)
 
 void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
 {
-       va_list args;
-
-       log_date(stdout);
-       va_start( args, fmt );
-       printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
-       vprintf(fmt, args);
-       va_end( args );
-       putchar('\n');
-
-       if(output_log_syslog) {
-               va_start( args, fmt );
-               vsyslog(LOG_ERR,  fmt, args );
-               va_end( args );
-       }
-
-       fflush(stdout);
+    va_list args;
+
+    log_date(stdout);
+    va_start( args, fmt );
+    printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+    vprintf(fmt, args);
+    va_end( args );
+    putchar('\n');
+
+    if(output_log_syslog) {
+        va_start( args, fmt );
+        vsyslog(LOG_ERR,  fmt, args );
+        va_end( args );
+    }
+
+    fflush(stdout);
 }
 
 // ----------------------------------------------------------------------------
@@ -249,26 +249,26 @@ void debug_int( const char *file, const char *function, const unsigned long line
 
 void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
 {
-       va_list args;
+    va_list args;
 
-       // prevent logging too much
-       if(error_log_limit(0)) return;
+    // prevent logging too much
+    if(error_log_limit(0)) return;
 
-       log_date(stderr);
+    log_date(stderr);
 
-       va_start( args, fmt );
-       if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
-       else            fprintf(stderr, "INFO: %s: ", program_name);
-       vfprintf( stderr, fmt, args );
-       va_end( args );
+    va_start( args, fmt );
+    if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+    else            fprintf(stderr, "INFO: %s: ", program_name);
+    vfprintf( stderr, fmt, args );
+    va_end( args );
 
-       fputc('\n', stderr);
+    fputc('\n', stderr);
 
-       if(error_log_syslog) {
-               va_start( args, fmt );
-               vsyslog(LOG_INFO,  fmt, args );
-               va_end( args );
-       }
+    if(error_log_syslog) {
+        va_start( args, fmt );
+        vsyslog(LOG_INFO,  fmt, args );
+        va_end( args );
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -276,56 +276,56 @@ void info_int( const char *file, const char *function, const unsigned long line,
 
 void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... )
 {
-       va_list args;
-
-       // prevent logging too much
-       if(error_log_limit(0)) return;
-
-       log_date(stderr);
-
-       va_start( args, fmt );
-       if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
-       else            fprintf(stderr, "%s: %s: ", prefix, program_name);
-       vfprintf( stderr, fmt, args );
-       va_end( args );
-
-       if(errno) {
-               char buf[1024];
-               fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
-               errno = 0;
-       }
-       else
-               fputc('\n', stderr);
-
-       if(error_log_syslog) {
-               va_start( args, fmt );
-               vsyslog(LOG_ERR,  fmt, args );
-               va_end( args );
-       }
+    va_list args;
+
+    // prevent logging too much
+    if(error_log_limit(0)) return;
+
+    log_date(stderr);
+
+    va_start( args, fmt );
+    if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
+    else            fprintf(stderr, "%s: %s: ", prefix, program_name);
+    vfprintf( stderr, fmt, args );
+    va_end( args );
+
+    if(errno) {
+        char buf[1024];
+        fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
+        errno = 0;
+    }
+    else
+        fputc('\n', stderr);
+
+    if(error_log_syslog) {
+        va_start( args, fmt );
+        vsyslog(LOG_ERR,  fmt, args );
+        va_end( args );
+    }
 }
 
 void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
 {
-       va_list args;
+    va_list args;
 
-       log_date(stderr);
+    log_date(stderr);
 
-       va_start( args, fmt );
-       if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
-       else            fprintf(stderr, "FATAL: %s: ", program_name);
-       vfprintf( stderr, fmt, args );
-       va_end( args );
+    va_start( args, fmt );
+    if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+    else            fprintf(stderr, "FATAL: %s: ", program_name);
+    vfprintf( stderr, fmt, args );
+    va_end( args );
 
-       perror(" # ");
-       fputc('\n', stderr);
+    perror(" # ");
+    fputc('\n', stderr);
 
-       if(error_log_syslog) {
-               va_start( args, fmt );
-               vsyslog(LOG_CRIT,  fmt, args );
-               va_end( args );
-       }
+    if(error_log_syslog) {
+        va_start( args, fmt );
+        vsyslog(LOG_CRIT,  fmt, args );
+        va_end( args );
+    }
 
-       netdata_cleanup_and_exit(1);
+    netdata_cleanup_and_exit(1);
 }
 
 // ----------------------------------------------------------------------------
@@ -333,21 +333,21 @@ void fatal_int( const char *file, const char *function, const unsigned long line
 
 void log_access( const char *fmt, ... )
 {
-       va_list args;
-
-       if(stdaccess) {
-               log_date(stdaccess);
-
-               va_start( args, fmt );
-               vfprintf( stdaccess, fmt, args );
-               va_end( args );
-               fputc('\n', stdaccess);
-       }
-
-       if(access_log_syslog) {
-               va_start( args, fmt );
-               vsyslog(LOG_INFO,  fmt, args );
-               va_end( args );
-       }
+    va_list args;
+
+    if(stdaccess) {
+        log_date(stdaccess);
+
+        va_start( args, fmt );
+        vfprintf( stdaccess, fmt, args );
+        va_end( args );
+        fputc('\n', stdaccess);
+    }
+
+    if(access_log_syslog) {
+        va_start( args, fmt );
+        vsyslog(LOG_INFO,  fmt, args );
+        va_end( args );
+    }
 }
 
index 576f5ee7cd3bde9b524c576256d85ba08c3bc142..f4503e2547b606c2f40629f3ecc3762adaedd64e 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -1,14 +1,14 @@
 #ifndef NETDATA_LOG_H
 #define NETDATA_LOG_H 1
 
-#define D_WEB_BUFFER           0x00000001
-#define D_WEB_CLIENT           0x00000002
-#define D_LISTENER             0x00000004
-#define D_WEB_DATA             0x00000008
-#define D_OPTIONS              0x00000010
+#define D_WEB_BUFFER        0x00000001
+#define D_WEB_CLIENT        0x00000002
+#define D_LISTENER          0x00000004
+#define D_WEB_DATA          0x00000008
+#define D_OPTIONS           0x00000010
 #define D_PROCNETDEV_LOOP   0x00000020
-#define D_RRD_STATS            0x00000040
-#define D_WEB_CLIENT_ACCESS    0x00000080
+#define D_RRD_STATS         0x00000040
+#define D_WEB_CLIENT_ACCESS 0x00000080
 #define D_TC_LOOP           0x00000100
 #define D_DEFLATE           0x00000200
 #define D_CONFIG            0x00000400
 #define D_CHILDS            0x00001000
 #define D_EXIT              0x00002000
 #define D_CHECKS            0x00004000
-#define D_NFACCT_LOOP          0x00008000
-#define D_PROCFILE                     0x00010000
-#define D_RRD_CALLS                    0x00020000
-#define D_DICTIONARY           0x00040000
-#define D_MEMORY                       0x00080000
+#define D_NFACCT_LOOP       0x00008000
+#define D_PROCFILE          0x00010000
+#define D_RRD_CALLS         0x00020000
+#define D_DICTIONARY        0x00040000
+#define D_MEMORY            0x00080000
 #define D_CGROUP            0x00100000
-#define D_REGISTRY                     0x00200000
+#define D_REGISTRY          0x00200000
 #define D_VARIABLES         0x00400000
 
 //#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
index b1acf8a6abc02dc0392d79d2a5c518df6130d300..646827fbd919de42422a70e0869d5eb19f823a34 100644 (file)
@@ -7,15 +7,15 @@ extern volatile sig_atomic_t netdata_exit;
  * This struct contains information about command line options.
  */
 struct option_def {
-       /** The option character */
-       const char val;
-       /** The name of the long option. */
-       const char *description;
-       /** Short descripton what the option does */
-       /** Name of the argument displayed in SYNOPSIS */
-       const char *arg_name;
-       /** Default value if not set */
-       const char *default_value;
+    /** The option character */
+    const char val;
+    /** The name of the long option. */
+    const char *description;
+    /** Short descripton what the option does */
+    /** Name of the argument displayed in SYNOPSIS */
+    const char *arg_name;
+    /** Default value if not set */
+    const char *default_value;
 };
 
 /**
index 8de62b720a26ae8c8db0e90ba140ef28a0156a46..007d6565fa30b6d5cd1563c66d3b759ea47b18cb 100644 (file)
@@ -2,83 +2,83 @@
 
 void *checks_main(void *ptr)
 {
-       if(ptr) { ; }
+    if(ptr) { ; }
 
-       info("CHECKS thread created with task id %d", gettid());
+    info("CHECKS thread created with task id %d", gettid());
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       unsigned long long usec = 0, susec = rrd_update_every * 1000000ULL, loop_usec = 0, total_susec = 0;
-       struct timeval now, last, loop;
+    unsigned long long usec = 0, susec = rrd_update_every * 1000000ULL, loop_usec = 0, total_susec = 0;
+    struct timeval now, last, loop;
 
-       RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
+    RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
 
-       check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
-       rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
-       rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+    check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
+    rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
+    rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
 
-       check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
-       rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
-       rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
+    check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
+    rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
+    rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
 
-       check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
-       rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
-       rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
-       rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
+    check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
+    rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
+    rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
+    rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
 
-       gettimeofday(&last, NULL);
-       while(1) {
-               usleep(susec);
+    gettimeofday(&last, NULL);
+    while(1) {
+        usleep(susec);
 
-               // find the time to sleep in order to wait exactly update_every seconds
-               gettimeofday(&now, NULL);
-               loop_usec = usec_dt(&now, &last);
-               usec = loop_usec - susec;
-               debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
+        // find the time to sleep in order to wait exactly update_every seconds
+        gettimeofday(&now, NULL);
+        loop_usec = usec_dt(&now, &last);
+        usec = loop_usec - susec;
+        debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
 
-               if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
-               else susec = rrd_update_every * 1000000ULL / 2ULL;
+        if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
+        else susec = rrd_update_every * 1000000ULL / 2ULL;
 
-               // --------------------------------------------------------------------
-               // Calculate loop time
+        // --------------------------------------------------------------------
+        // Calculate loop time
 
-               last.tv_sec = now.tv_sec;
-               last.tv_usec = now.tv_usec;
-               total_susec += loop_usec;
+        last.tv_sec = now.tv_sec;
+        last.tv_usec = now.tv_usec;
+        total_susec += loop_usec;
 
-               // --------------------------------------------------------------------
-               // check chart 1
+        // --------------------------------------------------------------------
+        // check chart 1
 
-               if(check1->counter_done) rrdset_next_usec(check1, loop_usec);
-               rrddim_set(check1, "absolute", 1000000);
-               rrddim_set(check1, "incremental", total_susec);
-               rrdset_done(check1);
+        if(check1->counter_done) rrdset_next_usec(check1, loop_usec);
+        rrddim_set(check1, "absolute", 1000000);
+        rrddim_set(check1, "incremental", total_susec);
+        rrdset_done(check1);
 
-               // --------------------------------------------------------------------
-               // check chart 2
+        // --------------------------------------------------------------------
+        // check chart 2
 
-               if(check2->counter_done) rrdset_next(check2);
-               rrddim_set(check2, "absolute", 1000000);
-               rrddim_set(check2, "incremental", total_susec);
-               rrdset_done(check2);
+        if(check2->counter_done) rrdset_next(check2);
+        rrddim_set(check2, "absolute", 1000000);
+        rrddim_set(check2, "incremental", total_susec);
+        rrdset_done(check2);
 
-               // --------------------------------------------------------------------
-               // check chart 3
+        // --------------------------------------------------------------------
+        // check chart 3
 
-               if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
-               if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
-               gettimeofday(&loop, NULL);
-               rrddim_set(check3, "caller", (long long) usec_dt(&loop, &check1->last_collected_time));
-               rrddim_set(check3, "netdata", (long long) usec_dt(&loop, &check2->last_collected_time));
-               if(apps_cpu) rrddim_set(check3, "apps.plugin", (long long) usec_dt(&loop, &apps_cpu->last_collected_time));
-               rrdset_done(check3);
-       }
+        if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
+        if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
+        gettimeofday(&loop, NULL);
+        rrddim_set(check3, "caller", (long long) usec_dt(&loop, &check1->last_collected_time));
+        rrddim_set(check3, "netdata", (long long) usec_dt(&loop, &check2->last_collected_time));
+        if(apps_cpu) rrddim_set(check3, "apps.plugin", (long long) usec_dt(&loop, &apps_cpu->last_collected_time));
+        rrdset_done(check3);
+    }
 
-       pthread_exit(NULL);
-       return NULL;
+    pthread_exit(NULL);
+    return NULL;
 }
 
index d0a9181ab2384e1c746c45d10648204569d34990..30c6d87088157aa6122e3bf0659cb23be40190fe 100644 (file)
@@ -4,51 +4,51 @@
 
 void *cpuidlejitter_main(void *ptr)
 {
-       if(ptr) { ; }
+    if(ptr) { ; }
 
-       info("CPU Idle Jitter thread created with task id %d", gettid());
+    info("CPU Idle Jitter thread created with task id %d", gettid());
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       int sleep_ms = (int) config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
-       if(sleep_ms <= 0) {
-               config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
-               sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
-       }
+    int sleep_ms = (int) config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
+    if(sleep_ms <= 0) {
+        config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
+        sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
+    }
 
-       RRDSET *st = rrdset_find("system.idlejitter");
-       if(!st) {
-               st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
-               rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
-       }
+    RRDSET *st = rrdset_find("system.idlejitter");
+    if(!st) {
+        st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
+        rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
+    }
 
-       struct timeval before, after;
-       unsigned long long counter;
-       for(counter = 0; 1 ;counter++) {
-               unsigned long long usec = 0, susec = 0;
+    struct timeval before, after;
+    unsigned long long counter;
+    for(counter = 0; 1 ;counter++) {
+        unsigned long long usec = 0, susec = 0;
 
-               while(susec < (rrd_update_every * 1000000ULL)) {
+        while(susec < (rrd_update_every * 1000000ULL)) {
 
-                       gettimeofday(&before, NULL);
-                       usleep(sleep_ms * 1000);
-                       gettimeofday(&after, NULL);
+            gettimeofday(&before, NULL);
+            usleep(sleep_ms * 1000);
+            gettimeofday(&after, NULL);
 
-                       // calculate the time it took for a full loop
-                       usec = usec_dt(&after, &before);
-                       susec += usec;
-               }
-               usec -= (sleep_ms * 1000);
+            // calculate the time it took for a full loop
+            usec = usec_dt(&after, &before);
+            susec += usec;
+        }
+        usec -= (sleep_ms * 1000);
 
-               if(counter) rrdset_next(st);
-               rrddim_set(st, "jitter", usec);
-               rrdset_done(st);
-       }
+        if(counter) rrdset_next(st);
+        rrddim_set(st, "jitter", usec);
+        rrdset_done(st);
+    }
 
-       pthread_exit(NULL);
-       return NULL;
+    pthread_exit(NULL);
+    return NULL;
 }
 
index b61f9e53de83d8c57d1973d47e043d9711a6aa8a..58d667c364fcee44843e73d1033f27aa34dbc738 100644 (file)
 #include "common.h"
 
 struct mynfacct {
-       const char *name;
-       uint64_t pkts;
-       uint64_t bytes;
-       struct nfacct *nfacct;
+    const char *name;
+    uint64_t pkts;
+    uint64_t bytes;
+    struct nfacct *nfacct;
 };
 
 struct nfacct_list {
-       int size;
-       int len;
-       struct mynfacct data[];
+    int size;
+    int len;
+    struct mynfacct data[];
 } *nfacct_list = NULL;
 
 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
-       if(data) {};
-
-       if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
-               int size = (nfacct_list) ? nfacct_list->size : 0;
-               int len = (nfacct_list) ? nfacct_list->len : 0;
-               size++;
-
-               info("nfacct.plugin: increasing nfacct_list to size %d", size);
-
-               nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
-               if(!nfacct_list) {
-                       error("nfacct.plugin: cannot allocate nfacct_list.");
-                       return MNL_CB_OK;
-               }
-
-               nfacct_list->data[len].nfacct = nfacct_alloc();
-               if(!nfacct_list->data[size - 1].nfacct) {
-                       error("nfacct.plugin: nfacct_alloc() failed.");
-                       free(nfacct_list);
-                       nfacct_list = NULL;
-                       return MNL_CB_OK;
-               }
-
-               nfacct_list->size = size;
-               nfacct_list->len = len;
-       }
-
-       if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
-               error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
-               return MNL_CB_OK;
-       }
-
-       nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
-       nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
-       nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
-
-       nfacct_list->len++;
-       return MNL_CB_OK;
+    if(data) {};
+
+    if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
+        int size = (nfacct_list) ? nfacct_list->size : 0;
+        int len = (nfacct_list) ? nfacct_list->len : 0;
+        size++;
+
+        info("nfacct.plugin: increasing nfacct_list to size %d", size);
+
+        nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
+        if(!nfacct_list) {
+            error("nfacct.plugin: cannot allocate nfacct_list.");
+            return MNL_CB_OK;
+        }
+
+        nfacct_list->data[len].nfacct = nfacct_alloc();
+        if(!nfacct_list->data[size - 1].nfacct) {
+            error("nfacct.plugin: nfacct_alloc() failed.");
+            free(nfacct_list);
+            nfacct_list = NULL;
+            return MNL_CB_OK;
+        }
+
+        nfacct_list->size = size;
+        nfacct_list->len = len;
+    }
+
+    if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
+        error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
+        return MNL_CB_OK;
+    }
+
+    nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
+    nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
+    nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
+
+    nfacct_list->len++;
+    return MNL_CB_OK;
 }
 
 void *nfacct_main(void *ptr) {
-       if(ptr) { ; }
+    if(ptr) { ; }
 
-       info("NFACCT thread created with task id %d", gettid());
+    info("NFACCT thread created with task id %d", gettid());
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
 
-       char buf[MNL_SOCKET_BUFFER_SIZE];
-       struct mnl_socket *nl = NULL;
-       struct nlmsghdr *nlh = NULL;
-       unsigned int seq = 0, portid = 0;
+    char buf[MNL_SOCKET_BUFFER_SIZE];
+    struct mnl_socket *nl = NULL;
+    struct nlmsghdr *nlh = NULL;
+    unsigned int seq = 0, portid = 0;
 
-       seq = time(NULL) - 1;
+    seq = time(NULL) - 1;
 
-       nl  = mnl_socket_open(NETLINK_NETFILTER);
-       if(!nl) {
-               error("nfacct.plugin: mnl_socket_open() failed");
-               pthread_exit(NULL);
-               return NULL;
-       }
+    nl  = mnl_socket_open(NETLINK_NETFILTER);
+    if(!nl) {
+        error("nfacct.plugin: mnl_socket_open() failed");
+        pthread_exit(NULL);
+        return NULL;
+    }
 
-       if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
-               mnl_socket_close(nl);
-               error("nfacct.plugin: mnl_socket_bind() failed");
-               pthread_exit(NULL);
-               return NULL;
-       }
-       portid = mnl_socket_get_portid(nl);
+    if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+        mnl_socket_close(nl);
+        error("nfacct.plugin: mnl_socket_bind() failed");
+        pthread_exit(NULL);
+        return NULL;
+    }
+    portid = mnl_socket_get_portid(nl);
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       struct timeval last, now;
-       unsigned long long usec = 0, susec = 0;
-       RRDSET *st = NULL;
+    struct timeval last, now;
+    unsigned long long usec = 0, susec = 0;
+    RRDSET *st = NULL;
 
-       gettimeofday(&last, NULL);
+    gettimeofday(&last, NULL);
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       while(1) {
-               if(unlikely(netdata_exit)) break;
+    while(1) {
+        if(unlikely(netdata_exit)) break;
 
-               seq++;
+        seq++;
 
-               nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
-               if(!nlh) {
-                       mnl_socket_close(nl);
-                       error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+        nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
+        if(!nlh) {
+            mnl_socket_close(nl);
+            error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
+            pthread_exit(NULL);
+            return NULL;
+        }
 
-               if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-                       error("nfacct.plugin: mnl_socket_send");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+        if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+            error("nfacct.plugin: mnl_socket_send");
+            pthread_exit(NULL);
+            return NULL;
+        }
 
-               if(nfacct_list) nfacct_list->len = 0;
+        if(nfacct_list) nfacct_list->len = 0;
 
-               int ret;
-               while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
-                       if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
-               }
+        int ret;
+        while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
+            if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
+        }
 
-               if (ret == -1) {
-                       error("nfacct.plugin: error communicating with kernel.");
-                       pthread_exit(NULL);
-                       return NULL;
-               }
+        if (ret == -1) {
+            error("nfacct.plugin: error communicating with kernel.");
+            pthread_exit(NULL);
+            return NULL;
+        }
 
-               // --------------------------------------------------------------------
+        // --------------------------------------------------------------------
 
-               gettimeofday(&now, NULL);
-               usec = usecdiff(&now, &last) - susec;
-               debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
+        gettimeofday(&now, NULL);
+        usec = usecdiff(&now, &last) - susec;
+        debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
 
-               if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
-               else susec = rrd_update_every * 1000000ULL / 2ULL;
+        if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
+        else susec = rrd_update_every * 1000000ULL / 2ULL;
 
 
-               // --------------------------------------------------------------------
+        // --------------------------------------------------------------------
 
-               if(nfacct_list && nfacct_list->len) {
-                       int i;
+        if(nfacct_list && nfacct_list->len) {
+            int i;
 
-                       st = rrdset_find_bytype("netfilter", "nfacct_packets");
-                       if(!st) {
-                               st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
+            st = rrdset_find_bytype("netfilter", "nfacct_packets");
+            if(!st) {
+                st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
 
-                               for(i = 0; i < nfacct_list->len ; i++)
-                                       rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
+                for(i = 0; i < nfacct_list->len ; i++)
+                    rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
 
-                       for(i = 0; i < nfacct_list->len ; i++) {
-                               RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+            for(i = 0; i < nfacct_list->len ; i++) {
+                RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
 
-                               if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
-                               if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
-                       }
+                if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
+                if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
+            }
 
-                       rrdset_done(st);
+            rrdset_done(st);
 
-                       // ----------------------------------------------------------------
+            // ----------------------------------------------------------------
 
-                       st = rrdset_find_bytype("netfilter", "nfacct_bytes");
-                       if(!st) {
-                               st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
+            st = rrdset_find_bytype("netfilter", "nfacct_bytes");
+            if(!st) {
+                st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
 
-                               for(i = 0; i < nfacct_list->len ; i++)
-                                       rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
+                for(i = 0; i < nfacct_list->len ; i++)
+                    rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
 
-                       for(i = 0; i < nfacct_list->len ; i++) {
-                               RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+            for(i = 0; i < nfacct_list->len ; i++) {
+                RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
 
-                               if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
-                               if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
-                       }
+                if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
+                if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
+            }
 
-                       rrdset_done(st);
-               }
+            rrdset_done(st);
+        }
 
-               // --------------------------------------------------------------------
+        // --------------------------------------------------------------------
 
-               usleep(susec);
+        usleep(susec);
 
-               // copy current to last
-               bcopy(&now, &last, sizeof(struct timeval));
-       }
+        // copy current to last
+        bcopy(&now, &last, sizeof(struct timeval));
+    }
 
-       mnl_socket_close(nl);
-       pthread_exit(NULL);
-       return NULL;
+    mnl_socket_close(nl);
+    pthread_exit(NULL);
+    return NULL;
 }
 #endif
index ac45775a855cce39a5b14eb2662e671ce41d0be4..a1bf314de7c34bf4a44081763773e4a750cb7e86 100644 (file)
 
 void *proc_main(void *ptr)
 {
-       (void)ptr;
-
-       info("PROC Plugin thread created with task id %d", gettid());
-
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
-
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
-
-       // disable (by default) various interface that are not needed
-       config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
-       config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
-
-       // when ZERO, attempt to do it
-       int vdo_proc_net_dev                    = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
-       int vdo_proc_diskstats                  = !config_get_boolean("plugin:proc", "/proc/diskstats", 1);
-       int vdo_proc_net_snmp                   = !config_get_boolean("plugin:proc", "/proc/net/snmp", 1);
-       int vdo_proc_net_snmp6                  = !config_get_boolean("plugin:proc", "/proc/net/snmp6", 1);
-       int vdo_proc_net_netstat                = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
-       int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
-       int vdo_proc_net_ip_vs_stats    = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
-       int vdo_proc_net_stat_synproxy  = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
-       int vdo_proc_stat                               = !config_get_boolean("plugin:proc", "/proc/stat", 1);
-       int vdo_proc_meminfo                    = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
-       int vdo_proc_vmstat                     = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
-       int vdo_proc_net_rpc_nfsd               = !config_get_boolean("plugin:proc", "/proc/net/rpc/nfsd", 1);
-       int vdo_proc_sys_kernel_random_entropy_avail    = !config_get_boolean("plugin:proc", "/proc/sys/kernel/random/entropy_avail", 1);
-       int vdo_proc_interrupts                 = !config_get_boolean("plugin:proc", "/proc/interrupts", 1);
-       int vdo_proc_softirqs                   = !config_get_boolean("plugin:proc", "/proc/softirqs", 1);
-       int vdo_proc_loadavg                    = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
-       int vdo_sys_kernel_mm_ksm               = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
-       int vdo_cpu_netdata                     = !config_get_boolean("plugin:proc", "netdata server resources", 1);
-
-       // keep track of the time each module was called
-       unsigned long long sutime_proc_net_dev = 0ULL;
-       unsigned long long sutime_proc_diskstats = 0ULL;
-       unsigned long long sutime_proc_net_snmp = 0ULL;
-       unsigned long long sutime_proc_net_snmp6 = 0ULL;
-       unsigned long long sutime_proc_net_netstat = 0ULL;
-       unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
-       unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
-       unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
-       unsigned long long sutime_proc_stat = 0ULL;
-       unsigned long long sutime_proc_meminfo = 0ULL;
-       unsigned long long sutime_proc_vmstat = 0ULL;
-       unsigned long long sutime_proc_net_rpc_nfsd = 0ULL;
-       unsigned long long sutime_proc_sys_kernel_random_entropy_avail = 0ULL;
-       unsigned long long sutime_proc_interrupts = 0ULL;
-       unsigned long long sutime_proc_softirqs = 0ULL;
-       unsigned long long sutime_proc_loadavg = 0ULL;
-       unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
-
-       // the next time we will run - aligned properly
-       unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
-       unsigned long long sunow;
-
-       for(;1;) {
-               if(unlikely(netdata_exit)) break;
-
-               // delay until it is our time to run
-               while((sunow = time_usec()) < sunext)
-                       sleep_usec(sunext - sunow);
-
-               // find the next time we need to run
-               while(time_usec() > sunext)
-                       sunext += rrd_update_every * 1000000ULL;
-
-               if(unlikely(netdata_exit)) break;
-
-               // BEGIN -- the job to be done
-
-               if(!vdo_sys_kernel_mm_ksm) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
-
-                       sunow = time_usec();
-                       vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
-                       sutime_sys_kernel_mm_ksm = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_loadavg) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
-                       sunow = time_usec();
-                       vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
-                       sutime_proc_loadavg = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_interrupts) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
-                       sunow = time_usec();
-                       vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
-                       sutime_proc_interrupts = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_softirqs) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
-                       sunow = time_usec();
-                       vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
-                       sutime_proc_softirqs = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_sys_kernel_random_entropy_avail) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
-                       sunow = time_usec();
-                       vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
-                       sutime_proc_sys_kernel_random_entropy_avail = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_dev) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
-                       sunow = time_usec();
-                       vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
-                       sutime_proc_net_dev = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_diskstats) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
-                       sunow = time_usec();
-                       vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
-                       sutime_proc_diskstats = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_snmp) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
-                       sunow = time_usec();
-                       vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
-                       sutime_proc_net_snmp = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_snmp6) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
-                       sunow = time_usec();
-                       vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
-                       sutime_proc_net_snmp6 = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_netstat) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
-                       sunow = time_usec();
-                       vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
-                       sutime_proc_net_netstat = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_stat_conntrack) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
-                       sunow = time_usec();
-                       vdo_proc_net_stat_conntrack     = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
-                       sutime_proc_net_stat_conntrack = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_ip_vs_stats) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
-                       sunow = time_usec();
-                       vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
-                       sutime_proc_net_ip_vs_stats = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_stat_synproxy) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
-                       sunow = time_usec();
-                       vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
-                       sutime_proc_net_stat_synproxy = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_stat) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
-                       sunow = time_usec();
-                       vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
-                       sutime_proc_stat = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_meminfo) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
-                       sunow = time_usec();
-                       vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
-                       sutime_proc_meminfo = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_vmstat) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
-                       sunow = time_usec();
-                       vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
-                       sutime_proc_vmstat = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               if(!vdo_proc_net_rpc_nfsd) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
-                       sunow = time_usec();
-                       vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
-                       sutime_proc_net_rpc_nfsd = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
-
-               // END -- the job is done
-
-               // --------------------------------------------------------------------
-
-               if(!vdo_cpu_netdata) {
+    (void)ptr;
+
+    info("PROC Plugin thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
+
+    // disable (by default) various interface that are not needed
+    config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
+    config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
+
+    // when ZERO, attempt to do it
+    int vdo_proc_net_dev            = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
+    int vdo_proc_diskstats          = !config_get_boolean("plugin:proc", "/proc/diskstats", 1);
+    int vdo_proc_net_snmp           = !config_get_boolean("plugin:proc", "/proc/net/snmp", 1);
+    int vdo_proc_net_snmp6          = !config_get_boolean("plugin:proc", "/proc/net/snmp6", 1);
+    int vdo_proc_net_netstat        = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
+    int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
+    int vdo_proc_net_ip_vs_stats    = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
+    int vdo_proc_net_stat_synproxy  = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
+    int vdo_proc_stat               = !config_get_boolean("plugin:proc", "/proc/stat", 1);
+    int vdo_proc_meminfo            = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
+    int vdo_proc_vmstat             = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
+    int vdo_proc_net_rpc_nfsd       = !config_get_boolean("plugin:proc", "/proc/net/rpc/nfsd", 1);
+    int vdo_proc_sys_kernel_random_entropy_avail    = !config_get_boolean("plugin:proc", "/proc/sys/kernel/random/entropy_avail", 1);
+    int vdo_proc_interrupts         = !config_get_boolean("plugin:proc", "/proc/interrupts", 1);
+    int vdo_proc_softirqs           = !config_get_boolean("plugin:proc", "/proc/softirqs", 1);
+    int vdo_proc_loadavg            = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
+    int vdo_sys_kernel_mm_ksm       = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
+    int vdo_cpu_netdata             = !config_get_boolean("plugin:proc", "netdata server resources", 1);
+
+    // keep track of the time each module was called
+    unsigned long long sutime_proc_net_dev = 0ULL;
+    unsigned long long sutime_proc_diskstats = 0ULL;
+    unsigned long long sutime_proc_net_snmp = 0ULL;
+    unsigned long long sutime_proc_net_snmp6 = 0ULL;
+    unsigned long long sutime_proc_net_netstat = 0ULL;
+    unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
+    unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
+    unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
+    unsigned long long sutime_proc_stat = 0ULL;
+    unsigned long long sutime_proc_meminfo = 0ULL;
+    unsigned long long sutime_proc_vmstat = 0ULL;
+    unsigned long long sutime_proc_net_rpc_nfsd = 0ULL;
+    unsigned long long sutime_proc_sys_kernel_random_entropy_avail = 0ULL;
+    unsigned long long sutime_proc_interrupts = 0ULL;
+    unsigned long long sutime_proc_softirqs = 0ULL;
+    unsigned long long sutime_proc_loadavg = 0ULL;
+    unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
+
+    // the next time we will run - aligned properly
+    unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
+    unsigned long long sunow;
+
+    for(;1;) {
+        if(unlikely(netdata_exit)) break;
+
+        // delay until it is our time to run
+        while((sunow = time_usec()) < sunext)
+            sleep_usec(sunext - sunow);
+
+        // find the next time we need to run
+        while(time_usec() > sunext)
+            sunext += rrd_update_every * 1000000ULL;
+
+        if(unlikely(netdata_exit)) break;
+
+        // BEGIN -- the job to be done
+
+        if(!vdo_sys_kernel_mm_ksm) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
+
+            sunow = time_usec();
+            vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
+            sutime_sys_kernel_mm_ksm = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_loadavg) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
+            sunow = time_usec();
+            vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
+            sutime_proc_loadavg = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_interrupts) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
+            sunow = time_usec();
+            vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
+            sutime_proc_interrupts = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_softirqs) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
+            sunow = time_usec();
+            vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
+            sutime_proc_softirqs = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_sys_kernel_random_entropy_avail) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
+            sunow = time_usec();
+            vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
+            sutime_proc_sys_kernel_random_entropy_avail = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_dev) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
+            sunow = time_usec();
+            vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
+            sutime_proc_net_dev = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_diskstats) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
+            sunow = time_usec();
+            vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
+            sutime_proc_diskstats = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_snmp) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
+            sunow = time_usec();
+            vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
+            sutime_proc_net_snmp = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_snmp6) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
+            sunow = time_usec();
+            vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
+            sutime_proc_net_snmp6 = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_netstat) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
+            sunow = time_usec();
+            vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
+            sutime_proc_net_netstat = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_stat_conntrack) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
+            sunow = time_usec();
+            vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
+            sutime_proc_net_stat_conntrack = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_ip_vs_stats) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
+            sunow = time_usec();
+            vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
+            sutime_proc_net_ip_vs_stats = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_stat_synproxy) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
+            sunow = time_usec();
+            vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
+            sutime_proc_net_stat_synproxy = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_stat) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
+            sunow = time_usec();
+            vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
+            sutime_proc_stat = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_meminfo) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
+            sunow = time_usec();
+            vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
+            sutime_proc_meminfo = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_vmstat) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
+            sunow = time_usec();
+            vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
+            sutime_proc_vmstat = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_net_rpc_nfsd) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
+            sunow = time_usec();
+            vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
+            sutime_proc_net_rpc_nfsd = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        // END -- the job is done
+
+        // --------------------------------------------------------------------
+
+        if(!vdo_cpu_netdata) {
             global_statistics_charts();
-                       registry_statistics();
-               }
-       }
+            registry_statistics();
+        }
+    }
 
-       pthread_exit(NULL);
-       return NULL;
+    pthread_exit(NULL);
+    return NULL;
 }
index b7ccfba2574af54a5045e080966e0e41e50e31d0..7d521818ed50133be8ab96e766375c9f6375c7c0 100644 (file)
@@ -1,7 +1,7 @@
 #include "common.h"
 
-#define RRD_TYPE_TC                                    "tc"
-#define RRD_TYPE_TC_LEN                                strlen(RRD_TYPE_TC)
+#define RRD_TYPE_TC                 "tc"
+#define RRD_TYPE_TC_LEN             strlen(RRD_TYPE_TC)
 
 // ----------------------------------------------------------------------------
 // /sbin/tc processor
 #define TC_LINE_MAX 1024
 
 struct tc_class {
-       avl avl;
-
-       char *id;
-       uint32_t hash;
-
-       char *name;
-
-       char *leafid;
-       uint32_t leaf_hash;
-
-       char *parentid;
-       uint32_t parent_hash;
-
-       char hasparent;
-       char isleaf;
-       unsigned long long bytes;
-       unsigned long long packets;
-       unsigned long long dropped;
-       unsigned long long overlimits;
-       unsigned long long requeues;
-       unsigned long long lended;
-       unsigned long long borrowed;
-       unsigned long long giants;
-       unsigned long long tokens;
-       unsigned long long ctokens;
-
-       RRDDIM *rd_bytes;
-       RRDDIM *rd_packets;
-       RRDDIM *rd_dropped;
-
-       char name_updated;
-       char updated;   // updated bytes
-       int seen;               // seen in the tc list (even without bytes)
-
-       struct tc_class *next;
-       struct tc_class *prev;
+    avl avl;
+
+    char *id;
+    uint32_t hash;
+
+    char *name;
+
+    char *leafid;
+    uint32_t leaf_hash;
+
+    char *parentid;
+    uint32_t parent_hash;
+
+    char hasparent;
+    char isleaf;
+    unsigned long long bytes;
+    unsigned long long packets;
+    unsigned long long dropped;
+    unsigned long long overlimits;
+    unsigned long long requeues;
+    unsigned long long lended;
+    unsigned long long borrowed;
+    unsigned long long giants;
+    unsigned long long tokens;
+    unsigned long long ctokens;
+
+    RRDDIM *rd_bytes;
+    RRDDIM *rd_packets;
+    RRDDIM *rd_dropped;
+
+    char name_updated;
+    char updated;   // updated bytes
+    int seen;       // seen in the tc list (even without bytes)
+
+    struct tc_class *next;
+    struct tc_class *prev;
 };
 
 struct tc_device {
-       avl avl;
+    avl avl;
 
-       char *id;
-       uint32_t hash;
+    char *id;
+    uint32_t hash;
 
-       char *name;
-       char *family;
+    char *name;
+    char *family;
 
-       char name_updated;
-       char family_updated;
+    char name_updated;
+    char family_updated;
 
-       char enabled;
-       char enabled_bytes;
-       char enabled_packets;
-       char enabled_dropped;
+    char enabled;
+    char enabled_bytes;
+    char enabled_packets;
+    char enabled_dropped;
 
-       RRDSET *st_bytes;
-       RRDSET *st_packets;
-       RRDSET *st_dropped;
+    RRDSET *st_bytes;
+    RRDSET *st_packets;
+    RRDSET *st_dropped;
 
-       avl_tree classes_index;
+    avl_tree classes_index;
 
-       struct tc_class *classes;
+    struct tc_class *classes;
 
-       struct tc_device *next;
-       struct tc_device *prev;
+    struct tc_device *next;
+    struct tc_device *prev;
 };
 
 
@@ -84,25 +84,25 @@ struct tc_device *tc_device_root = NULL;
 // tc_device index
 
 static int tc_device_compare(void* a, void* b) {
-       if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
-       else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
-       else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
+    if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
+    else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
+    else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
 }
 
 avl_tree tc_device_root_index = {
-               NULL,
-               tc_device_compare
+        NULL,
+        tc_device_compare
 };
 
 #define tc_device_index_add(st) avl_insert(&tc_device_root_index, (avl *)(st))
 #define tc_device_index_del(st) avl_remove(&tc_device_root_index, (avl *)(st))
 
 static inline struct tc_device *tc_device_index_find(const char *id, uint32_t hash) {
-       struct tc_device tmp;
-       tmp.id = (char *)id;
-       tmp.hash = (hash)?hash:simple_hash(tmp.id);
+    struct tc_device tmp;
+    tmp.id = (char *)id;
+    tmp.hash = (hash)?hash:simple_hash(tmp.id);
 
-       return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp);
+    return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp);
 }
 
 
@@ -110,764 +110,764 @@ static inline struct tc_device *tc_device_index_find(const char *id, uint32_t ha
 // tc_class index
 
 static int tc_class_compare(void* a, void* b) {
-       if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
-       else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
-       else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
+    if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
+    else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
+    else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
 }
 
 #define tc_class_index_add(st, rd) avl_insert(&((st)->classes_index), (avl *)(rd))
 #define tc_class_index_del(st, rd) avl_remove(&((st)->classes_index), (avl *)(rd))
 
 static inline struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) {
-       struct tc_class tmp;
-       tmp.id = (char *)id;
-       tmp.hash = (hash)?hash:simple_hash(tmp.id);
+    struct tc_class tmp;
+    tmp.id = (char *)id;
+    tmp.hash = (hash)?hash:simple_hash(tmp.id);
 
-       return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp);
+    return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp);
 }
 
 // ----------------------------------------------------------------------------
 
 static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
-       debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
-
-       if(c->next) c->next->prev = c->prev;
-       if(c->prev) c->prev->next = c->next;
-       if(n->classes == c) {
-               if(c->next) n->classes = c->next;
-               else n->classes = c->prev;
-       }
-
-       tc_class_index_del(n, c);
-
-       freez(c->id);
-       freez(c->name);
-       freez(c->leafid);
-       freez(c->parentid);
-       freez(c);
+    debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
+
+    if(c->next) c->next->prev = c->prev;
+    if(c->prev) c->prev->next = c->next;
+    if(n->classes == c) {
+        if(c->next) n->classes = c->next;
+        else n->classes = c->prev;
+    }
+
+    tc_class_index_del(n, c);
+
+    freez(c->id);
+    freez(c->name);
+    freez(c->leafid);
+    freez(c->parentid);
+    freez(c);
 }
 
 static inline void tc_device_classes_cleanup(struct tc_device *d) {
-       static int cleanup_every = 999;
-
-       if(unlikely(cleanup_every > 0)) {
-               cleanup_every = (int) config_get_number("plugin:tc", "cleanup unused classes every", 60);
-               if(cleanup_every < 0) cleanup_every = -cleanup_every;
-       }
-
-       d->name_updated = 0;
-       d->family_updated = 0;
-
-       struct tc_class *c = d->classes;
-       while(c) {
-               if(unlikely(cleanup_every > 0 && c->seen >= cleanup_every)) {
-                       struct tc_class *nc = c->next;
-                       tc_class_free(d, c);
-                       c = nc;
-               }
-               else {
-                       c->updated = 0;
-                       c->name_updated = 0;
-
-                       c = c->next;
-               }
-       }
+    static int cleanup_every = 999;
+
+    if(unlikely(cleanup_every > 0)) {
+        cleanup_every = (int) config_get_number("plugin:tc", "cleanup unused classes every", 60);
+        if(cleanup_every < 0) cleanup_every = -cleanup_every;
+    }
+
+    d->name_updated = 0;
+    d->family_updated = 0;
+
+    struct tc_class *c = d->classes;
+    while(c) {
+        if(unlikely(cleanup_every > 0 && c->seen >= cleanup_every)) {
+            struct tc_class *nc = c->next;
+            tc_class_free(d, c);
+            c = nc;
+        }
+        else {
+            c->updated = 0;
+            c->name_updated = 0;
+
+            c = c->next;
+        }
+    }
 }
 
 static inline void tc_device_commit(struct tc_device *d) {
-       static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1;
-
-       if(unlikely(enable_new_interfaces == -1)) {
-               enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
-               enable_bytes          = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-               enable_packets        = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-               enable_dropped        = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       }
-
-       // we only need to add leaf classes
-       struct tc_class *c, *x;
-       unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0;
-       int active_classes = 0;
-
-       // set all classes
-       for(c = d->classes ; c ; c = c->next) {
-               c->isleaf = 1;
-               c->hasparent = 0;
-       }
-
-       // mark the classes as leafs and parents
-       for(c = d->classes ; c ; c = c->next) {
-               if(unlikely(!c->updated)) continue;
-
-               for(x = d->classes ; x ; x = x->next) {
-                       if(unlikely(!x->updated)) continue;
-
-                       if(unlikely(c == x)) continue;
-
-                       if(x->parentid && (
-                               (               c->hash      == x->parent_hash && strcmp(c->id,     x->parentid) == 0) ||
-                               (c->leafid   && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
-                               // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
-                               c->isleaf = 0;
-                               x->hasparent = 1;
-                       }
-               }
-       }
-
-       // debugging:
-       /*
-       for ( c = d->classes ; c ; c = c->next) {
-               if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device %s, class %s, OK", d->name, c->id);
-               else debug(D_TC_LOOP, "TC: Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
-       }
-       */
-
-       // we need at least a class
-       for(c = d->classes ; c ; c = c->next) {
-               // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
-               if(!c->updated) continue;
-               if(c->isleaf && c->hasparent) {
-                       active_classes++;
-                       bytes_sum += c->bytes;
-                       packets_sum += c->packets;
-                       dropped_sum += c->dropped;
-               }
-       }
-
-       if(unlikely(!active_classes)) {
-               debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
-               tc_device_classes_cleanup(d);
-               return;
-       }
-
-       if(unlikely(d->enabled == -1)) {
-               char var_name[CONFIG_MAX_NAME + 1];
-               snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
-               d->enabled         = config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
-
-               snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
-               d->enabled_bytes   = config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
-
-               snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
-               d->enabled_packets = config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
-
-               snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
-               d->enabled_dropped = config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
-       }
-
-       if(likely(d->enabled)) {
-               // --------------------------------------------------------------------
-               // bytes
-
-               if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
-                       d->enabled_bytes = CONFIG_ONDEMAND_YES;
-
-                       if(unlikely(!d->st_bytes)) {
-                               d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
-                               if(unlikely(!d->st_bytes)) {
-                                       debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
-                                       d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
-                               }
-                       }
-                       else {
-                               debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
-                               rrdset_next_plugins(d->st_bytes);
-
-                               if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
-                                       rrdset_set_name(d->st_bytes, d->name);
-                                       d->name_updated = 0;
-                               }
-
-                               // FIXME
-                               // update the family
-                       }
-
-                       for(c = d->classes ; c ; c = c->next) {
-                               if(unlikely(!c->updated)) continue;
-
-                               if(c->isleaf && c->hasparent) {
-                                       c->seen++;
-
-                                       if(unlikely(!c->rd_bytes)) {
-                                               c->rd_bytes = rrddim_find(d->st_bytes, c->id);
-                                               if(unlikely(!c->rd_bytes)) {
-                                                       debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
-
-                                                       // new class, we have to add it
-                                                       c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
-                                               }
-                                               else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
-                                       }
-
-                                       rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
-
-                                       // if it has a name, different to the id
-                                       if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
-                                               // update the rrd dimension with the new name
-                                               debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
-                                               rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
-                                       }
-                               }
-                       }
-                       rrdset_done(d->st_bytes);
-               }
-
-               // --------------------------------------------------------------------
-               // packets
-               
-               if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
-                       d->enabled_packets = CONFIG_ONDEMAND_YES;
-
-                       if(unlikely(!d->st_packets)) {
-                               char id[RRD_ID_LENGTH_MAX + 1];
-                               char name[RRD_ID_LENGTH_MAX + 1];
-                               snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
-                               snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
-
-                               d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
-                               if(unlikely(!d->st_packets)) {
-                                       debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
-                                       d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
-                               }
-                       }
-                       else {
-                               debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
-                               rrdset_next_plugins(d->st_packets);
-
-                               // FIXME
-                               // update the family
-                       }
-
-                       for(c = d->classes ; c ; c = c->next) {
-                               if(unlikely(!c->updated)) continue;
-
-                               if(c->isleaf && c->hasparent) {
-                                       if(unlikely(!c->rd_packets)) {
-                                               c->rd_packets = rrddim_find(d->st_packets, c->id);
-                                               if(unlikely(!c->rd_packets)) {
-                                                       debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
-
-                                                       // new class, we have to add it
-                                                       c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
-                                               }
-                                               else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
-                                       }
-
-                                       rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
-
-                                       // if it has a name, different to the id
-                                       if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
-                                               // update the rrd dimension with the new name
-                                               debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
-                                               rrddim_set_name(d->st_packets, c->rd_packets, c->name);
-                                       }
-                               }
-                       }
-                       rrdset_done(d->st_packets);
-               }
-
-               // --------------------------------------------------------------------
-               // dropped
-               
-               if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
-                       d->enabled_dropped = CONFIG_ONDEMAND_YES;
-                       
-                       if(unlikely(!d->st_dropped)) {
-                               char id[RRD_ID_LENGTH_MAX + 1];
-                               char name[RRD_ID_LENGTH_MAX + 1];
-                               snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
-                               snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
-
-                               d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
-                               if(unlikely(!d->st_dropped)) {
-                                       debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
-                                       d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
-                               }
-                       }
-                       else {
-                               debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
-                               rrdset_next_plugins(d->st_dropped);
-
-                               // FIXME
-                               // update the family
-                       }
-
-                       for(c = d->classes ; c ; c = c->next) {
-                               if(unlikely(!c->updated)) continue;
-
-                               if(c->isleaf && c->hasparent) {
-                                       if(unlikely(!c->rd_dropped)) {
-                                               c->rd_dropped = rrddim_find(d->st_dropped, c->id);
-                                               if(unlikely(!c->rd_dropped)) {
-                                                       debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
-
-                                                       // new class, we have to add it
-                                                       c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
-                                               }
-                                               else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
-                                       }
-
-                                       rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
-
-                                       // if it has a name, different to the id
-                                       if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
-                                               // update the rrd dimension with the new name
-                                               debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
-                                               rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
-                                       }
-                               }
-                       }
-                       rrdset_done(d->st_dropped);
-               }
-       }
-
-       tc_device_classes_cleanup(d);
+    static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1;
+
+    if(unlikely(enable_new_interfaces == -1)) {
+        enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
+        enable_bytes          = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        enable_packets        = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        enable_dropped        = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    }
+
+    // we only need to add leaf classes
+    struct tc_class *c, *x;
+    unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0;
+    int active_classes = 0;
+
+    // set all classes
+    for(c = d->classes ; c ; c = c->next) {
+        c->isleaf = 1;
+        c->hasparent = 0;
+    }
+
+    // mark the classes as leafs and parents
+    for(c = d->classes ; c ; c = c->next) {
+        if(unlikely(!c->updated)) continue;
+
+        for(x = d->classes ; x ; x = x->next) {
+            if(unlikely(!x->updated)) continue;
+
+            if(unlikely(c == x)) continue;
+
+            if(x->parentid && (
+                (               c->hash      == x->parent_hash && strcmp(c->id,     x->parentid) == 0) ||
+                (c->leafid   && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
+                // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
+                c->isleaf = 0;
+                x->hasparent = 1;
+            }
+        }
+    }
+
+    // debugging:
+    /*
+    for ( c = d->classes ; c ; c = c->next) {
+        if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device %s, class %s, OK", d->name, c->id);
+        else debug(D_TC_LOOP, "TC: Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
+    }
+    */
+
+    // we need at least a class
+    for(c = d->classes ; c ; c = c->next) {
+        // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
+        if(!c->updated) continue;
+        if(c->isleaf && c->hasparent) {
+            active_classes++;
+            bytes_sum += c->bytes;
+            packets_sum += c->packets;
+            dropped_sum += c->dropped;
+        }
+    }
+
+    if(unlikely(!active_classes)) {
+        debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
+        tc_device_classes_cleanup(d);
+        return;
+    }
+
+    if(unlikely(d->enabled == -1)) {
+        char var_name[CONFIG_MAX_NAME + 1];
+        snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
+        d->enabled         = config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
+
+        snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
+        d->enabled_bytes   = config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
+
+        snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
+        d->enabled_packets = config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
+
+        snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
+        d->enabled_dropped = config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
+    }
+
+    if(likely(d->enabled)) {
+        // --------------------------------------------------------------------
+        // bytes
+
+        if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
+            d->enabled_bytes = CONFIG_ONDEMAND_YES;
+
+            if(unlikely(!d->st_bytes)) {
+                d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
+                if(unlikely(!d->st_bytes)) {
+                    debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
+                    d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
+                }
+            }
+            else {
+                debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
+                rrdset_next_plugins(d->st_bytes);
+
+                if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
+                    rrdset_set_name(d->st_bytes, d->name);
+                    d->name_updated = 0;
+                }
+
+                // FIXME
+                // update the family
+            }
+
+            for(c = d->classes ; c ; c = c->next) {
+                if(unlikely(!c->updated)) continue;
+
+                if(c->isleaf && c->hasparent) {
+                    c->seen++;
+
+                    if(unlikely(!c->rd_bytes)) {
+                        c->rd_bytes = rrddim_find(d->st_bytes, c->id);
+                        if(unlikely(!c->rd_bytes)) {
+                            debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
+
+                            // new class, we have to add it
+                            c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
+                        }
+                        else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
+                    }
+
+                    rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
+
+                    // if it has a name, different to the id
+                    if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
+                        // update the rrd dimension with the new name
+                        debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
+                        rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
+                    }
+                }
+            }
+            rrdset_done(d->st_bytes);
+        }
+
+        // --------------------------------------------------------------------
+        // packets
+        
+        if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
+            d->enabled_packets = CONFIG_ONDEMAND_YES;
+
+            if(unlikely(!d->st_packets)) {
+                char id[RRD_ID_LENGTH_MAX + 1];
+                char name[RRD_ID_LENGTH_MAX + 1];
+                snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
+                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
+
+                d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
+                if(unlikely(!d->st_packets)) {
+                    debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
+                    d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
+                }
+            }
+            else {
+                debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
+                rrdset_next_plugins(d->st_packets);
+
+                // FIXME
+                // update the family
+            }
+
+            for(c = d->classes ; c ; c = c->next) {
+                if(unlikely(!c->updated)) continue;
+
+                if(c->isleaf && c->hasparent) {
+                    if(unlikely(!c->rd_packets)) {
+                        c->rd_packets = rrddim_find(d->st_packets, c->id);
+                        if(unlikely(!c->rd_packets)) {
+                            debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
+
+                            // new class, we have to add it
+                            c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
+                        }
+                        else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
+                    }
+
+                    rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
+
+                    // if it has a name, different to the id
+                    if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
+                        // update the rrd dimension with the new name
+                        debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
+                        rrddim_set_name(d->st_packets, c->rd_packets, c->name);
+                    }
+                }
+            }
+            rrdset_done(d->st_packets);
+        }
+
+        // --------------------------------------------------------------------
+        // dropped
+        
+        if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
+            d->enabled_dropped = CONFIG_ONDEMAND_YES;
+            
+            if(unlikely(!d->st_dropped)) {
+                char id[RRD_ID_LENGTH_MAX + 1];
+                char name[RRD_ID_LENGTH_MAX + 1];
+                snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
+                snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
+
+                d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
+                if(unlikely(!d->st_dropped)) {
+                    debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
+                    d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
+                }
+            }
+            else {
+                debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
+                rrdset_next_plugins(d->st_dropped);
+
+                // FIXME
+                // update the family
+            }
+
+            for(c = d->classes ; c ; c = c->next) {
+                if(unlikely(!c->updated)) continue;
+
+                if(c->isleaf && c->hasparent) {
+                    if(unlikely(!c->rd_dropped)) {
+                        c->rd_dropped = rrddim_find(d->st_dropped, c->id);
+                        if(unlikely(!c->rd_dropped)) {
+                            debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
+
+                            // new class, we have to add it
+                            c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
+                        }
+                        else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
+                    }
+
+                    rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
+
+                    // if it has a name, different to the id
+                    if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
+                        // update the rrd dimension with the new name
+                        debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
+                        rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
+                    }
+                }
+            }
+            rrdset_done(d->st_dropped);
+        }
+    }
+
+    tc_device_classes_cleanup(d);
 }
 
 static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
 {
-       struct tc_class *c = tc_class_index_find(d, id, 0);
-       if(likely(c)) {
-               freez(c->name);
-               c->name = NULL;
-
-               if(likely(name && *name && strcmp(c->id, name) != 0)) {
-                       debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
-                       c->name = strdupz(name);
-                       c->name_updated = 1;
-               }
-       }
+    struct tc_class *c = tc_class_index_find(d, id, 0);
+    if(likely(c)) {
+        freez(c->name);
+        c->name = NULL;
+
+        if(likely(name && *name && strcmp(c->id, name) != 0)) {
+            debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
+            c->name = strdupz(name);
+            c->name_updated = 1;
+        }
+    }
 }
 
 static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
-       freez(d->name);
-       d->name = NULL;
-
-       if(likely(name && *name && strcmp(d->id, name) != 0)) {
-               debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
-               d->name = strdupz(name);
-               d->name_updated = 1;
-       }
+    freez(d->name);
+    d->name = NULL;
+
+    if(likely(name && *name && strcmp(d->id, name) != 0)) {
+        debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
+        d->name = strdupz(name);
+        d->name_updated = 1;
+    }
 }
 
 static inline void tc_device_set_device_family(struct tc_device *d, char *family) {
-       freez(d->family);
-       d->family = NULL;
-
-       if(likely(family && *family && strcmp(d->id, family) != 0)) {
-               debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
-               d->family = strdupz(family);
-               d->family_updated = 1;
-       }
-       // no need for null termination - it is already null
+    freez(d->family);
+    d->family = NULL;
+
+    if(likely(family && *family && strcmp(d->id, family) != 0)) {
+        debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
+        d->family = strdupz(family);
+        d->family_updated = 1;
+    }
+    // no need for null termination - it is already null
 }
 
 static inline struct tc_device *tc_device_create(char *id)
 {
-       struct tc_device *d = tc_device_index_find(id, 0);
+    struct tc_device *d = tc_device_index_find(id, 0);
 
-       if(!d) {
-               debug(D_TC_LOOP, "TC: Creating device '%s'", id);
+    if(!d) {
+        debug(D_TC_LOOP, "TC: Creating device '%s'", id);
 
-               d = callocz(1, sizeof(struct tc_device));
+        d = callocz(1, sizeof(struct tc_device));
 
-               d->id = strdupz(id);
-               d->hash = simple_hash(d->id);
-               d->enabled = -1;
+        d->id = strdupz(id);
+        d->hash = simple_hash(d->id);
+        d->enabled = -1;
 
-               avl_init(&d->classes_index, tc_class_compare);
-               tc_device_index_add(d);
+        avl_init(&d->classes_index, tc_class_compare);
+        tc_device_index_add(d);
 
-               if(!tc_device_root) {
-                       tc_device_root = d;
-               }
-               else {
-                       d->next = tc_device_root;
-                       tc_device_root->prev = d;
-                       tc_device_root = d;
-               }
-       }
+        if(!tc_device_root) {
+            tc_device_root = d;
+        }
+        else {
+            d->next = tc_device_root;
+            tc_device_root->prev = d;
+            tc_device_root = d;
+        }
+    }
 
-       return(d);
+    return(d);
 }
 
 static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
 {
-       struct tc_class *c = tc_class_index_find(n, id, 0);
+    struct tc_class *c = tc_class_index_find(n, id, 0);
 
-       if(!c) {
-               debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
+    if(!c) {
+        debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
 
-               c = callocz(1, sizeof(struct tc_class));
+        c = callocz(1, sizeof(struct tc_class));
 
-               if(n->classes) n->classes->prev = c;
-               c->next = n->classes;
-               n->classes = c;
+        if(n->classes) n->classes->prev = c;
+        c->next = n->classes;
+        n->classes = c;
 
-               c->id = strdupz(id);
-               c->hash = simple_hash(c->id);
+        c->id = strdupz(id);
+        c->hash = simple_hash(c->id);
 
-               if(parentid && *parentid) {
-                       c->parentid = strdupz(parentid);
-                       c->parent_hash = simple_hash(c->parentid);
-               }
+        if(parentid && *parentid) {
+            c->parentid = strdupz(parentid);
+            c->parent_hash = simple_hash(c->parentid);
+        }
 
-               if(leafid && *leafid) {
-                       c->leafid = strdupz(leafid);
-                       c->leaf_hash = simple_hash(c->leafid);
-               }
+        if(leafid && *leafid) {
+            c->leafid = strdupz(leafid);
+            c->leaf_hash = simple_hash(c->leafid);
+        }
 
-               tc_class_index_add(n, c);
-       }
+        tc_class_index_add(n, c);
+    }
 
-       c->seen = 1;
+    c->seen = 1;
 
-       return(c);
+    return(c);
 }
 
 static inline void tc_device_free(struct tc_device *n)
 {
-       if(n->next) n->next->prev = n->prev;
-       if(n->prev) n->prev->next = n->next;
-       if(tc_device_root == n) {
-               if(n->next) tc_device_root = n->next;
-               else tc_device_root = n->prev;
-       }
+    if(n->next) n->next->prev = n->prev;
+    if(n->prev) n->prev->next = n->next;
+    if(tc_device_root == n) {
+        if(n->next) tc_device_root = n->next;
+        else tc_device_root = n->prev;
+    }
 
-       tc_device_index_del(n);
+    tc_device_index_del(n);
 
-       while(n->classes) tc_class_free(n, n->classes);
+    while(n->classes) tc_class_free(n, n->classes);
 
-       freez(n->id);
-       freez(n->name);
-       freez(n->family);
-       freez(n);
+    freez(n->id);
+    freez(n->name);
+    freez(n->family);
+    freez(n);
 }
 
 static inline void tc_device_free_all()
 {
-       while(tc_device_root)
-               tc_device_free(tc_device_root);
+    while(tc_device_root)
+        tc_device_free(tc_device_root);
 }
 
 #define MAX_WORDS 20
 
 static inline int tc_space(char c) {
-       switch(c) {
-       case ' ':
-       case '\t':
-       case '\r':
-       case '\n':
-               return 1;
-
-       default:
-               return 0;
-       }
+    switch(c) {
+    case ' ':
+    case '\t':
+    case '\r':
+    case '\n':
+        return 1;
+
+    default:
+        return 0;
+    }
 }
 
 static inline void tc_split_words(char *str, char **words, int max_words) {
-       char *s = str;
-       int i = 0;
+    char *s = str;
+    int i = 0;
 
-       // skip all white space
-       while(tc_space(*s)) s++;
+    // skip all white space
+    while(tc_space(*s)) s++;
 
-       // store the first word
-       words[i++] = s;
+    // store the first word
+    words[i++] = s;
 
-       // while we have something
-       while(*s) {
-               // if it is a space
-               if(unlikely(tc_space(*s))) {
+    // while we have something
+    while(*s) {
+        // if it is a space
+        if(unlikely(tc_space(*s))) {
 
-                       // terminate the word
-                       *s++ = '\0';
+            // terminate the word
+            *s++ = '\0';
 
-                       // skip all white space
-                       while(tc_space(*s)) s++;
+            // skip all white space
+            while(tc_space(*s)) s++;
 
-                       // if we reached the end, stop
-                       if(!*s) break;
+            // if we reached the end, stop
+            if(!*s) break;
 
-                       // store the next word
-                       if(i < max_words) words[i++] = s;
-                       else break;
-               }
-               else s++;
-       }
+            // store the next word
+            if(i < max_words) words[i++] = s;
+            else break;
+        }
+        else s++;
+    }
 
-       // terminate the words
-       while(i < max_words) words[i++] = NULL;
+    // terminate the words
+    while(i < max_words) words[i++] = NULL;
 }
 
 pid_t tc_child_pid = 0;
 void *tc_main(void *ptr) {
-       (void)ptr;
+    (void)ptr;
 
-       info("TC thread created with task id %d", gettid());
+    info("TC thread created with task id %d", gettid());
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       struct rusage thread;
-       RRDSET *stcpu = NULL, *sttime = NULL;
+    struct rusage thread;
+    RRDSET *stcpu = NULL, *sttime = NULL;
 
-       char buffer[TC_LINE_MAX+1] = "";
-       char *words[MAX_WORDS] = { NULL };
+    char buffer[TC_LINE_MAX+1] = "";
+    char *words[MAX_WORDS] = { NULL };
 
-       uint32_t BEGIN_HASH = simple_hash("BEGIN");
-       uint32_t END_HASH = simple_hash("END");
-       uint32_t CLASS_HASH = simple_hash("class");
-       uint32_t SENT_HASH = simple_hash("Sent");
-       uint32_t LENDED_HASH = simple_hash("lended:");
-       uint32_t TOKENS_HASH = simple_hash("tokens:");
-       uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME");
-       uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP");
-       uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME");
-       uint32_t WORKTIME_HASH = simple_hash("WORKTIME");
+    uint32_t BEGIN_HASH = simple_hash("BEGIN");
+    uint32_t END_HASH = simple_hash("END");
+    uint32_t CLASS_HASH = simple_hash("class");
+    uint32_t SENT_HASH = simple_hash("Sent");
+    uint32_t LENDED_HASH = simple_hash("lended:");
+    uint32_t TOKENS_HASH = simple_hash("tokens:");
+    uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME");
+    uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP");
+    uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME");
+    uint32_t WORKTIME_HASH = simple_hash("WORKTIME");
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-       uint32_t MYPID_HASH = simple_hash("MYPID");
+    uint32_t MYPID_HASH = simple_hash("MYPID");
 #endif
-       uint32_t first_hash;
-
-       snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
-       char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
-       
-       for(;1;) {
-               if(unlikely(netdata_exit)) break;
-
-               FILE *fp;
-               struct tc_device *device = NULL;
-               struct tc_class *class = NULL;
-
-               snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
-               debug(D_TC_LOOP, "executing '%s'", buffer);
-
-               fp = mypopen(buffer, &tc_child_pid);
-               if(unlikely(!fp)) {
-                       error("TC: Cannot popen(\"%s\", \"r\").", buffer);
-                       pthread_exit(NULL);
-                       return NULL;
-               }
-
-               while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
-                       if(unlikely(netdata_exit)) break;
-
-                       buffer[TC_LINE_MAX] = '\0';
-                       // debug(D_TC_LOOP, "TC: read '%s'", buffer);
-
-                       tc_split_words(buffer, words, MAX_WORDS);
-
-                       if(unlikely(!words[0] || !*words[0])) {
-                               // debug(D_TC_LOOP, "empty line");
-                               continue;
-                       }
-                       // else debug(D_TC_LOOP, "First word is '%s'", words[0]);
-
-                       first_hash = simple_hash(words[0]);
-
-                       if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
-                               // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
-
-                               // words[1] : class type
-                               // words[2] : N:XX
-                               // words[3] : parent or root
-                               if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
-                                       //char *type     = words[1];  // the class: htb, fq_codel, etc
-
-                                       // we are only interested for HTB classes
-                                       //if(strcmp(type, "htb") != 0) continue;
-
-                                       char *id       = words[2];      // the class major:minor
-                                       char *parent   = words[3];      // 'parent' or 'root'
-                                       char *parentid = words[4];      // the parent's id
-                                       char *leaf     = words[5];      // 'leaf'
-                                       char *leafid   = words[6];      // leafid
-
-                                       if(strcmp(parent, "root") == 0) {
-                                               parentid = NULL;
-                                               leafid = NULL;
-                                       }
-                                       else if(!leaf || strcmp(leaf, "leaf") != 0)
-                                               leafid = NULL;
-
-                                       char leafbuf[20 + 1] = "";
-                                       if(leafid && leafid[strlen(leafid) - 1] == ':') {
-                                               strncpyz(leafbuf, leafid, 20 - 1);
-                                               strcat(leafbuf, "1");
-                                               leafid = leafbuf;
-                                       }
-
-                                       class = tc_class_add(device, id, parentid, leafid);
-                               }
-                               else {
-                                       // clear the last class
-                                       class = NULL;
-                               }
-                       }
-                       else if(unlikely(first_hash == END_HASH && strcmp(words[0], "END") == 0)) {
-                               // debug(D_TC_LOOP, "END line");
-
-                               if(likely(device)) {
-                                       if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
-                                               error("Cannot set pthread cancel state to DISABLE.");
-
-                                       tc_device_commit(device);
-                                       // tc_device_free(device);
-
-                                       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-                                               error("Cannot set pthread cancel state to ENABLE.");
-                               }
-
-                               device = NULL;
-                               class = NULL;
-                       }
-                       else if(unlikely(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0)) {
-                               // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]);
-
-                               if(likely(words[1] && *words[1])) {
-                                       device = tc_device_create(words[1]);
-                               }
-                               else {
-                                       // tc_device_free(device);
-                                       device = NULL;
-                               }
-
-                               class = NULL;
-                       }
-                       else if(unlikely(device && class && first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0)) {
-                               // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
-                               if(likely(words[1] && *words[1])) {
-                                       class->bytes = strtoull(words[1], NULL, 10);
-                                       class->updated = 1;
-                               }
-                               else {
-                                       class->updated = 0;
-                               }
-
-                               if(likely(words[3] && *words[3]))
-                                       class->packets = strtoull(words[3], NULL, 10);
-
-                               if(likely(words[6] && *words[6]))
-                                       class->dropped = strtoull(words[6], NULL, 10);
-
-                               if(likely(words[8] && *words[8]))
-                                       class->overlimits = strtoull(words[8], NULL, 10);
-
-                               if(likely(words[10] && *words[10]))
-                                       class->requeues = strtoull(words[8], NULL, 10);
-                       }
-                       else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) {
-                               // debug(D_TC_LOOP, "LENDED line '%s'", words[1]);
-                               if(likely(words[1] && *words[1]))
-                                       class->lended = strtoull(words[1], NULL, 10);
-
-                               if(likely(words[3] && *words[3]))
-                                       class->borrowed = strtoull(words[3], NULL, 10);
-
-                               if(likely(words[5] && *words[5]))
-                                       class->giants = strtoull(words[5], NULL, 10);
-                       }
-                       else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) {
-                               // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]);
-                               if(likely(words[1] && *words[1]))
-                                       class->tokens = strtoull(words[1], NULL, 10);
-
-                               if(likely(words[3] && *words[3]))
-                                       class->ctokens = strtoull(words[3], NULL, 10);
-                       }
-                       else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) {
-                               // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]);
-                               if(likely(words[1] && *words[1]))
-                                       tc_device_set_device_name(device, words[1]);
-                       }
-                       else if(unlikely(device && first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0)) {
-                               // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]);
-                               if(likely(words[1] && *words[1]))
-                                       tc_device_set_device_family(device, words[1]);
-                       }
-                       else if(unlikely(device && first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0)) {
-                               // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]);
-                               char *id    = words[1];
-                               char *path  = words[2];
-                               if(likely(id && *id && path && *path))
-                                       tc_device_set_class_name(device, id, path);
-                       }
-                       else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) {
-                               // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
-                               getrusage(RUSAGE_THREAD, &thread);
-
-                               if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
-                               if(unlikely(!stcpu)) {
-                                       stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
-                                       rrddim_add(stcpu, "user",  NULL,  1, 1000, RRDDIM_INCREMENTAL);
-                                       rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(stcpu);
-
-                               rrddim_set(stcpu, "user"  , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
-                               rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
-                               rrdset_done(stcpu);
-
-                               if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
-                               if(unlikely(!sttime)) {
-                                       sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
-                                       rrddim_add(sttime, "run_time",  "run time",  1, 1, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next(sttime);
-
-                               rrddim_set(sttime, "run_time", atoll(words[1]));
-                               rrdset_done(sttime);
-
-                       }
+    uint32_t first_hash;
+
+    snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
+    char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
+    
+    for(;1;) {
+        if(unlikely(netdata_exit)) break;
+
+        FILE *fp;
+        struct tc_device *device = NULL;
+        struct tc_class *class = NULL;
+
+        snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
+        debug(D_TC_LOOP, "executing '%s'", buffer);
+
+        fp = mypopen(buffer, &tc_child_pid);
+        if(unlikely(!fp)) {
+            error("TC: Cannot popen(\"%s\", \"r\").", buffer);
+            pthread_exit(NULL);
+            return NULL;
+        }
+
+        while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
+            if(unlikely(netdata_exit)) break;
+
+            buffer[TC_LINE_MAX] = '\0';
+            // debug(D_TC_LOOP, "TC: read '%s'", buffer);
+
+            tc_split_words(buffer, words, MAX_WORDS);
+
+            if(unlikely(!words[0] || !*words[0])) {
+                // debug(D_TC_LOOP, "empty line");
+                continue;
+            }
+            // else debug(D_TC_LOOP, "First word is '%s'", words[0]);
+
+            first_hash = simple_hash(words[0]);
+
+            if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
+                // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
+
+                // words[1] : class type
+                // words[2] : N:XX
+                // words[3] : parent or root
+                if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
+                    //char *type     = words[1];  // the class: htb, fq_codel, etc
+
+                    // we are only interested for HTB classes
+                    //if(strcmp(type, "htb") != 0) continue;
+
+                    char *id       = words[2];  // the class major:minor
+                    char *parent   = words[3];  // 'parent' or 'root'
+                    char *parentid = words[4];  // the parent's id
+                    char *leaf     = words[5];  // 'leaf'
+                    char *leafid   = words[6];  // leafid
+
+                    if(strcmp(parent, "root") == 0) {
+                        parentid = NULL;
+                        leafid = NULL;
+                    }
+                    else if(!leaf || strcmp(leaf, "leaf") != 0)
+                        leafid = NULL;
+
+                    char leafbuf[20 + 1] = "";
+                    if(leafid && leafid[strlen(leafid) - 1] == ':') {
+                        strncpyz(leafbuf, leafid, 20 - 1);
+                        strcat(leafbuf, "1");
+                        leafid = leafbuf;
+                    }
+
+                    class = tc_class_add(device, id, parentid, leafid);
+                }
+                else {
+                    // clear the last class
+                    class = NULL;
+                }
+            }
+            else if(unlikely(first_hash == END_HASH && strcmp(words[0], "END") == 0)) {
+                // debug(D_TC_LOOP, "END line");
+
+                if(likely(device)) {
+                    if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
+                        error("Cannot set pthread cancel state to DISABLE.");
+
+                    tc_device_commit(device);
+                    // tc_device_free(device);
+
+                    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+                        error("Cannot set pthread cancel state to ENABLE.");
+                }
+
+                device = NULL;
+                class = NULL;
+            }
+            else if(unlikely(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0)) {
+                // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]);
+
+                if(likely(words[1] && *words[1])) {
+                    device = tc_device_create(words[1]);
+                }
+                else {
+                    // tc_device_free(device);
+                    device = NULL;
+                }
+
+                class = NULL;
+            }
+            else if(unlikely(device && class && first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0)) {
+                // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
+                if(likely(words[1] && *words[1])) {
+                    class->bytes = strtoull(words[1], NULL, 10);
+                    class->updated = 1;
+                }
+                else {
+                    class->updated = 0;
+                }
+
+                if(likely(words[3] && *words[3]))
+                    class->packets = strtoull(words[3], NULL, 10);
+
+                if(likely(words[6] && *words[6]))
+                    class->dropped = strtoull(words[6], NULL, 10);
+
+                if(likely(words[8] && *words[8]))
+                    class->overlimits = strtoull(words[8], NULL, 10);
+
+                if(likely(words[10] && *words[10]))
+                    class->requeues = strtoull(words[8], NULL, 10);
+            }
+            else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) {
+                // debug(D_TC_LOOP, "LENDED line '%s'", words[1]);
+                if(likely(words[1] && *words[1]))
+                    class->lended = strtoull(words[1], NULL, 10);
+
+                if(likely(words[3] && *words[3]))
+                    class->borrowed = strtoull(words[3], NULL, 10);
+
+                if(likely(words[5] && *words[5]))
+                    class->giants = strtoull(words[5], NULL, 10);
+            }
+            else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) {
+                // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]);
+                if(likely(words[1] && *words[1]))
+                    class->tokens = strtoull(words[1], NULL, 10);
+
+                if(likely(words[3] && *words[3]))
+                    class->ctokens = strtoull(words[3], NULL, 10);
+            }
+            else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) {
+                // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]);
+                if(likely(words[1] && *words[1]))
+                    tc_device_set_device_name(device, words[1]);
+            }
+            else if(unlikely(device && first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0)) {
+                // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]);
+                if(likely(words[1] && *words[1]))
+                    tc_device_set_device_family(device, words[1]);
+            }
+            else if(unlikely(device && first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0)) {
+                // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]);
+                char *id    = words[1];
+                char *path  = words[2];
+                if(likely(id && *id && path && *path))
+                    tc_device_set_class_name(device, id, path);
+            }
+            else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) {
+                // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
+                getrusage(RUSAGE_THREAD, &thread);
+
+                if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
+                if(unlikely(!stcpu)) {
+                    stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
+                    rrddim_add(stcpu, "user",  NULL,  1, 1000, RRDDIM_INCREMENTAL);
+                    rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(stcpu);
+
+                rrddim_set(stcpu, "user"  , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
+                rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
+                rrdset_done(stcpu);
+
+                if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
+                if(unlikely(!sttime)) {
+                    sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
+                    rrddim_add(sttime, "run_time",  "run time",  1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(sttime);
+
+                rrddim_set(sttime, "run_time", atoll(words[1]));
+                rrdset_done(sttime);
+
+            }
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-                       else if(unlikely(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0))) {
-                               // debug(D_TC_LOOP, "MYPID line '%s'", words[1]);
-                               char *id = words[1];
-                               pid_t pid = atol(id);
+            else if(unlikely(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0))) {
+                // debug(D_TC_LOOP, "MYPID line '%s'", words[1]);
+                char *id = words[1];
+                pid_t pid = atol(id);
 
-                               if(likely(pid)) tc_child_pid = pid;
+                if(likely(pid)) tc_child_pid = pid;
 
-                               debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
-                       }
+                debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
+            }
 #endif
-                       //else {
-                       //      debug(D_TC_LOOP, "IGNORED line");
-                       //}
-               }
-
-               // fgets() failed or loop broke
-               int code = mypclose(fp, tc_child_pid);
-               tc_child_pid = 0;
-
-               if(unlikely(device)) {
-                       // tc_device_free(device);
-                       device = NULL;
-                       class = NULL;
-               }
-
-               if(unlikely(netdata_exit)) {
-                       tc_device_free_all();
-                       pthread_exit(NULL);
-                       return NULL;
-               }
-
-               if(code == 1 || code == 127) {
-                       // 1 = DISABLE
-                       // 127 = cannot even run it
-                       error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
-
-                       tc_device_free_all();
-                       pthread_exit(NULL);
-                       return NULL;
-               }
-
-               sleep((unsigned int) rrd_update_every);
-       }
-
-       pthread_exit(NULL);
-       return NULL;
+            //else {
+            //  debug(D_TC_LOOP, "IGNORED line");
+            //}
+        }
+
+        // fgets() failed or loop broke
+        int code = mypclose(fp, tc_child_pid);
+        tc_child_pid = 0;
+
+        if(unlikely(device)) {
+            // tc_device_free(device);
+            device = NULL;
+            class = NULL;
+        }
+
+        if(unlikely(netdata_exit)) {
+            tc_device_free_all();
+            pthread_exit(NULL);
+            return NULL;
+        }
+
+        if(code == 1 || code == 127) {
+            // 1 = DISABLE
+            // 127 = cannot even run it
+            error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
+
+            tc_device_free_all();
+            pthread_exit(NULL);
+            return NULL;
+        }
+
+        sleep((unsigned int) rrd_update_every);
+    }
+
+    pthread_exit(NULL);
+    return NULL;
 }
index 7e106bf81942b60a167a801efb08bc00580887f0..a91650554ac656177527ab16e6e871b8a0b00f9a 100644 (file)
@@ -5,544 +5,544 @@ struct plugind *pluginsd_root = NULL;
 #define MAX_WORDS 20
 
 static inline int pluginsd_space(char c) {
-       switch(c) {
-       case ' ':
-       case '\t':
-       case '\r':
-       case '\n':
-       case '=':
-               return 1;
-
-       default:
-               return 0;
-       }
+    switch(c) {
+    case ' ':
+    case '\t':
+    case '\r':
+    case '\n':
+    case '=':
+        return 1;
+
+    default:
+        return 0;
+    }
 }
 
 static int pluginsd_split_words(char *str, char **words, int max_words) {
-       char *s = str, quote = 0;
-       int i = 0, j;
-
-       // skip all white space
-       while(unlikely(pluginsd_space(*s))) s++;
-
-       // check for quote
-       if(unlikely(*s == '\'' || *s == '"')) {
-               quote = *s;     // remember the quote
-               s++;            // skip the quote
-       }
-
-       // store the first word
-       words[i++] = s;
-
-       // while we have something
-       while(likely(*s)) {
-               // if it is escape
-               if(unlikely(*s == '\\' && s[1])) {
-                       s += 2;
-                       continue;
-               }
-
-               // if it is quote
-               else if(unlikely(*s == quote)) {
-                       quote = 0;
-                       *s = ' ';
-                       continue;
-               }
-
-               // if it is a space
-               else if(unlikely(quote == 0 && pluginsd_space(*s))) {
-
-                       // terminate the word
-                       *s++ = '\0';
-
-                       // skip all white space
-                       while(likely(pluginsd_space(*s))) s++;
-
-                       // check for quote
-                       if(unlikely(*s == '\'' || *s == '"')) {
-                               quote = *s;     // remember the quote
-                               s++;            // skip the quote
-                       }
-
-                       // if we reached the end, stop
-                       if(unlikely(!*s)) break;
-
-                       // store the next word
-                       if(likely(i < max_words)) words[i++] = s;
-                       else break;
-               }
-
-               // anything else
-               else s++;
-       }
-
-       // terminate the words
-       j = i;
-       while(likely(j < max_words)) words[j++] = NULL;
-
-       return i;
+    char *s = str, quote = 0;
+    int i = 0, j;
+
+    // skip all white space
+    while(unlikely(pluginsd_space(*s))) s++;
+
+    // check for quote
+    if(unlikely(*s == '\'' || *s == '"')) {
+        quote = *s; // remember the quote
+        s++;        // skip the quote
+    }
+
+    // store the first word
+    words[i++] = s;
+
+    // while we have something
+    while(likely(*s)) {
+        // if it is escape
+        if(unlikely(*s == '\\' && s[1])) {
+            s += 2;
+            continue;
+        }
+
+        // if it is quote
+        else if(unlikely(*s == quote)) {
+            quote = 0;
+            *s = ' ';
+            continue;
+        }
+
+        // if it is a space
+        else if(unlikely(quote == 0 && pluginsd_space(*s))) {
+
+            // terminate the word
+            *s++ = '\0';
+
+            // skip all white space
+            while(likely(pluginsd_space(*s))) s++;
+
+            // check for quote
+            if(unlikely(*s == '\'' || *s == '"')) {
+                quote = *s; // remember the quote
+                s++;        // skip the quote
+            }
+
+            // if we reached the end, stop
+            if(unlikely(!*s)) break;
+
+            // store the next word
+            if(likely(i < max_words)) words[i++] = s;
+            else break;
+        }
+
+        // anything else
+        else s++;
+    }
+
+    // terminate the words
+    j = i;
+    while(likely(j < max_words)) words[j++] = NULL;
+
+    return i;
 }
 
 
 void *pluginsd_worker_thread(void *arg)
 {
-       struct plugind *cd = (struct plugind *)arg;
-       char line[PLUGINSD_LINE_MAX + 1];
+    struct plugind *cd = (struct plugind *)arg;
+    char line[PLUGINSD_LINE_MAX + 1];
 
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-       unsigned long long usec = 0, susec = 0;
-       struct timeval last = {0, 0} , now = {0, 0};
+    unsigned long long usec = 0, susec = 0;
+    struct timeval last = {0, 0} , now = {0, 0};
 #endif
 
-       char *words[MAX_WORDS] = { NULL };
-       uint32_t SET_HASH = simple_hash("SET");
-       uint32_t BEGIN_HASH = simple_hash("BEGIN");
-       uint32_t END_HASH = simple_hash("END");
-       uint32_t FLUSH_HASH = simple_hash("FLUSH");
-       uint32_t CHART_HASH = simple_hash("CHART");
-       uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
-       uint32_t DISABLE_HASH = simple_hash("DISABLE");
+    char *words[MAX_WORDS] = { NULL };
+    uint32_t SET_HASH = simple_hash("SET");
+    uint32_t BEGIN_HASH = simple_hash("BEGIN");
+    uint32_t END_HASH = simple_hash("END");
+    uint32_t FLUSH_HASH = simple_hash("FLUSH");
+    uint32_t CHART_HASH = simple_hash("CHART");
+    uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
+    uint32_t DISABLE_HASH = simple_hash("DISABLE");
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-       uint32_t MYPID_HASH = simple_hash("MYPID");
-       uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
+    uint32_t MYPID_HASH = simple_hash("MYPID");
+    uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
 #endif
 
-       size_t count = 0;
-
-       while(likely(1)) {
-               if(unlikely(netdata_exit)) break;
-
-               FILE *fp = mypopen(cd->cmd, &cd->pid);
-               if(unlikely(!fp)) {
-                       error("Cannot popen(\"%s\", \"r\").", cd->cmd);
-                       break;
-               }
-
-               info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
-
-               RRDSET *st = NULL;
-               char *s;
-               uint32_t hash;
-
-               while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
-                       if(unlikely(netdata_exit)) break;
-
-                       line[PLUGINSD_LINE_MAX] = '\0';
-
-                       // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
-
-                       int w = pluginsd_split_words(line, words, MAX_WORDS);
-                       s = words[0];
-                       if(unlikely(!s || !*s || !w)) {
-                               // debug(D_PLUGINSD, "PLUGINSD: empty line");
-                               continue;
-                       }
-
-                       // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
-
-                       hash = simple_hash(s);
-
-                       if(likely(hash == SET_HASH && !strcmp(s, "SET"))) {
-                               char *dimension = words[1];
-                               char *value = words[2];
-
-                               if(unlikely(!dimension || !*dimension)) {
-                                       error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               if(unlikely(!value || !*value)) value = NULL;
-
-                               if(unlikely(!st)) {
-                                       error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
-
-                               if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
-                       }
-                       else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
-                               char *id = words[1];
-                               char *microseconds_txt = words[2];
-
-                               if(unlikely(!id)) {
-                                       error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               st = rrdset_find(id);
-                               if(unlikely(!st)) {
-                                       error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               if(likely(st->counter_done)) {
-                                       unsigned long long microseconds = 0;
-                                       if(microseconds_txt && *microseconds_txt) microseconds = strtoull(microseconds_txt, NULL, 10);
-                                       if(microseconds) rrdset_next_usec(st, microseconds);
-                                       else rrdset_next_plugins(st);
-                               }
-                       }
-                       else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
-                               if(unlikely(!st)) {
-                                       error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
-
-                               rrdset_done(st);
-                               st = NULL;
-
-                               count++;
-                       }
-                       else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
-                               debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
-                               st = NULL;
-                       }
-                       else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
-                               int noname = 0;
-                               st = NULL;
-
-                               if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
-                                       noname = 1;
-
-                               char *type = words[1];
-                               char *id = NULL;
-                               if(likely(type)) {
-                                       id = strchr(type, '.');
-                                       if(likely(id)) { *id = '\0'; id++; }
-                               }
-                               char *name = words[2];
-                               char *title = words[3];
-                               char *units = words[4];
-                               char *family = words[5];
-                               char *context = words[6];
-                               char *chart = words[7];
-                               char *priority_s = words[8];
-                               char *update_every_s = words[9];
-
-                               if(unlikely(!type || !*type || !id || !*id)) {
-                                       error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               int priority = 1000;
-                               if(likely(priority_s)) priority = atoi(priority_s);
-
-                               int update_every = cd->update_every;
-                               if(likely(update_every_s)) update_every = atoi(update_every_s);
-                               if(unlikely(!update_every)) update_every = cd->update_every;
-
-                               int chart_type = RRDSET_TYPE_LINE;
-                               if(unlikely(chart)) chart_type = rrdset_type_id(chart);
-
-                               if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
-                               if(unlikely(!family || !*family)) family = NULL;
-                               if(unlikely(!context || !*context)) context = NULL;
-
-                               st = rrdset_find_bytype(type, id);
-                               if(unlikely(!st)) {
-                                       debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
-                                               , type, id
-                                               , name?name:""
-                                               , family?family:""
-                                               , context?context:""
-                                               , rrdset_type_name(chart_type)
-                                               , priority
-                                               , update_every
-                                               );
-
-                                       st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
-                                       cd->update_every = update_every;
-                               }
-                               else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
-                       }
-                       else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
-                               char *id = words[1];
-                               char *name = words[2];
-                               char *algorithm = words[3];
-                               char *multiplier_s = words[4];
-                               char *divisor_s = words[5];
-                               char *options = words[6];
-
-                               if(unlikely(!id || !*id)) {
-                                       error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               if(unlikely(!st)) {
-                                       error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
-                                       cd->enabled = 0;
-                                       killpid(cd->pid, SIGTERM);
-                                       break;
-                               }
-
-                               long multiplier = 1;
-                               if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
-                               if(unlikely(!multiplier)) multiplier = 1;
-
-                               long divisor = 1;
-                               if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
-                               if(unlikely(!divisor)) divisor = 1;
-
-                               if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
-
-                               if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
-                                       , st->id
-                                       , id
-                                       , name?name:""
-                                       , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
-                                       , multiplier
-                                       , divisor
-                                       , options?options:""
-                                       );
-
-                               RRDDIM *rd = rrddim_find(st, id);
-                               if(unlikely(!rd)) {
-                                       rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
-                                       rd->flags = 0x00000000;
-                                       if(options && *options) {
-                                               if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
-                                               if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
-                                               if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
-                                       }
-                               }
-                               else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
-                       }
-                       else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
-                               error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
-                               cd->enabled = 0;
-                               killpid(cd->pid, SIGTERM);
-                               break;
-                       }
+    size_t count = 0;
+
+    while(likely(1)) {
+        if(unlikely(netdata_exit)) break;
+
+        FILE *fp = mypopen(cd->cmd, &cd->pid);
+        if(unlikely(!fp)) {
+            error("Cannot popen(\"%s\", \"r\").", cd->cmd);
+            break;
+        }
+
+        info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
+
+        RRDSET *st = NULL;
+        char *s;
+        uint32_t hash;
+
+        while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
+            if(unlikely(netdata_exit)) break;
+
+            line[PLUGINSD_LINE_MAX] = '\0';
+
+            // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
+
+            int w = pluginsd_split_words(line, words, MAX_WORDS);
+            s = words[0];
+            if(unlikely(!s || !*s || !w)) {
+                // debug(D_PLUGINSD, "PLUGINSD: empty line");
+                continue;
+            }
+
+            // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
+
+            hash = simple_hash(s);
+
+            if(likely(hash == SET_HASH && !strcmp(s, "SET"))) {
+                char *dimension = words[1];
+                char *value = words[2];
+
+                if(unlikely(!dimension || !*dimension)) {
+                    error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                if(unlikely(!value || !*value)) value = NULL;
+
+                if(unlikely(!st)) {
+                    error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
+
+                if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
+            }
+            else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
+                char *id = words[1];
+                char *microseconds_txt = words[2];
+
+                if(unlikely(!id)) {
+                    error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                st = rrdset_find(id);
+                if(unlikely(!st)) {
+                    error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                if(likely(st->counter_done)) {
+                    unsigned long long microseconds = 0;
+                    if(microseconds_txt && *microseconds_txt) microseconds = strtoull(microseconds_txt, NULL, 10);
+                    if(microseconds) rrdset_next_usec(st, microseconds);
+                    else rrdset_next_plugins(st);
+                }
+            }
+            else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
+                if(unlikely(!st)) {
+                    error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
+
+                rrdset_done(st);
+                st = NULL;
+
+                count++;
+            }
+            else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
+                debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
+                st = NULL;
+            }
+            else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
+                int noname = 0;
+                st = NULL;
+
+                if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
+                    noname = 1;
+
+                char *type = words[1];
+                char *id = NULL;
+                if(likely(type)) {
+                    id = strchr(type, '.');
+                    if(likely(id)) { *id = '\0'; id++; }
+                }
+                char *name = words[2];
+                char *title = words[3];
+                char *units = words[4];
+                char *family = words[5];
+                char *context = words[6];
+                char *chart = words[7];
+                char *priority_s = words[8];
+                char *update_every_s = words[9];
+
+                if(unlikely(!type || !*type || !id || !*id)) {
+                    error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                int priority = 1000;
+                if(likely(priority_s)) priority = atoi(priority_s);
+
+                int update_every = cd->update_every;
+                if(likely(update_every_s)) update_every = atoi(update_every_s);
+                if(unlikely(!update_every)) update_every = cd->update_every;
+
+                int chart_type = RRDSET_TYPE_LINE;
+                if(unlikely(chart)) chart_type = rrdset_type_id(chart);
+
+                if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
+                if(unlikely(!family || !*family)) family = NULL;
+                if(unlikely(!context || !*context)) context = NULL;
+
+                st = rrdset_find_bytype(type, id);
+                if(unlikely(!st)) {
+                    debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
+                        , type, id
+                        , name?name:""
+                        , family?family:""
+                        , context?context:""
+                        , rrdset_type_name(chart_type)
+                        , priority
+                        , update_every
+                        );
+
+                    st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
+                    cd->update_every = update_every;
+                }
+                else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
+            }
+            else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
+                char *id = words[1];
+                char *name = words[2];
+                char *algorithm = words[3];
+                char *multiplier_s = words[4];
+                char *divisor_s = words[5];
+                char *options = words[6];
+
+                if(unlikely(!id || !*id)) {
+                    error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                if(unlikely(!st)) {
+                    error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
+                    cd->enabled = 0;
+                    killpid(cd->pid, SIGTERM);
+                    break;
+                }
+
+                long multiplier = 1;
+                if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
+                if(unlikely(!multiplier)) multiplier = 1;
+
+                long divisor = 1;
+                if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
+                if(unlikely(!divisor)) divisor = 1;
+
+                if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
+
+                if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
+                    , st->id
+                    , id
+                    , name?name:""
+                    , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
+                    , multiplier
+                    , divisor
+                    , options?options:""
+                    );
+
+                RRDDIM *rd = rrddim_find(st, id);
+                if(unlikely(!rd)) {
+                    rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
+                    rd->flags = 0x00000000;
+                    if(options && *options) {
+                        if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
+                        if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
+                        if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
+                    }
+                }
+                else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
+            }
+            else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
+                error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
+                cd->enabled = 0;
+                killpid(cd->pid, SIGTERM);
+                break;
+            }
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-                       else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
-                               char *pid_s = words[1];
-                               pid_t pid = strtod(pid_s, NULL, 0);
-
-                               if(likely(pid)) cd->pid = pid;
-                               debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
-                       }
-                       else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
-                               error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
-
-                               gettimeofday(&now, NULL);
-                               if(unlikely(!usec && !susec)) {
-                                       // our first run
-                                       susec = cd->rrd_update_every * 1000000ULL;
-                               }
-                               else {
-                                       // second+ run
-                                       usec = usecdiff(&now, &last) - susec;
-                                       error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
-                                       if(unlikely(usec < (rrd_update_every * 1000000ULL / 2ULL))) susec = (rrd_update_every * 1000000ULL) - usec;
-                                       else susec = rrd_update_every * 1000000ULL / 2ULL;
-                               }
-
-                               error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
-                               usleep(susec);
-                               killpid(cd->pid, SIGCONT);
-                               bcopy(&now, &last, sizeof(struct timeval));
-                               break;
-                       }
+            else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
+                char *pid_s = words[1];
+                pid_t pid = strtod(pid_s, NULL, 0);
+
+                if(likely(pid)) cd->pid = pid;
+                debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
+            }
+            else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
+                error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
+
+                gettimeofday(&now, NULL);
+                if(unlikely(!usec && !susec)) {
+                    // our first run
+                    susec = cd->rrd_update_every * 1000000ULL;
+                }
+                else {
+                    // second+ run
+                    usec = usecdiff(&now, &last) - susec;
+                    error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
+                    if(unlikely(usec < (rrd_update_every * 1000000ULL / 2ULL))) susec = (rrd_update_every * 1000000ULL) - usec;
+                    else susec = rrd_update_every * 1000000ULL / 2ULL;
+                }
+
+                error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
+                usleep(susec);
+                killpid(cd->pid, SIGCONT);
+                bcopy(&now, &last, sizeof(struct timeval));
+                break;
+            }
 #endif
-                       else {
-                               error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
-                               cd->enabled = 0;
-                               killpid(cd->pid, SIGTERM);
-                               break;
-                       }
-               }
-               if(likely(count)) {
-                       cd->successful_collections += count;
-                       cd->serial_failures = 0;
-               }
-               else
-                       cd->serial_failures++;
-
-               info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
-
-               // get the return code
-               int code = mypclose(fp, cd->pid);
-
-               if(netdata_exit) {
-                       cd->pid = 0;
-                       cd->enabled = 0;
-                       cd->obsolete = 1;
-                       pthread_exit(NULL);
-                       return NULL;
-               }
-
-               if(code != 0) {
-                       // the plugin reports failure
-
-                       if(likely(!cd->successful_collections)) {
-                               // nothing collected - disable it
-                               error("PLUGINSD: '%s' exited with error code %d. Disabling it.", cd->fullfilename, code);
-                               cd->enabled = 0;
-                       }
-                       else {
-                               // we have collected something
-
-                               if(likely(cd->serial_failures <= 10)) {
-                                       error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). Waiting a bit before starting it again.", cd->fullfilename, code, cd->successful_collections);
-                                       sleep((unsigned int) (cd->update_every * 10));
-                               }
-                               else {
-                                       error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). We tried %zu times to restart it, but it failed to generate data. Disabling it.", cd->fullfilename, code, cd->successful_collections, cd->serial_failures);
-                                       cd->enabled = 0;
-                               }
-                       }
-               }
-               else {
-                       // the plugin reports success
-
-                       if(unlikely(!cd->successful_collections)) {
-                               // we have collected nothing so far
-
-                               if(likely(cd->serial_failures <= 10)) {
-                                       error("PLUGINSD: '%s' (pid %d) does not generate useful output but it reports success (exits with 0). Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
-                                       sleep((unsigned int) (cd->update_every * 10));
-                               }
-                               else {
-                                       error("PLUGINSD: '%s' (pid %d) does not generate useful output, although it reports success (exits with 0), but we have tried %zu times to collect something. Disabling it.", cd->fullfilename, cd->pid, cd->serial_failures);
-                                       cd->enabled = 0;
-                               }
-                       }
-                       else
-                               sleep((unsigned int) cd->update_every);
-               }
-               cd->pid = 0;
-
-               if(unlikely(!cd->enabled))
-                       break;
-       }
-
-       cd->obsolete = 1;
-       pthread_exit(NULL);
-       return NULL;
+            else {
+                error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
+                cd->enabled = 0;
+                killpid(cd->pid, SIGTERM);
+                break;
+            }
+        }
+        if(likely(count)) {
+            cd->successful_collections += count;
+            cd->serial_failures = 0;
+        }
+        else
+            cd->serial_failures++;
+
+        info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
+
+        // get the return code
+        int code = mypclose(fp, cd->pid);
+
+        if(netdata_exit) {
+            cd->pid = 0;
+            cd->enabled = 0;
+            cd->obsolete = 1;
+            pthread_exit(NULL);
+            return NULL;
+        }
+
+        if(code != 0) {
+            // the plugin reports failure
+
+            if(likely(!cd->successful_collections)) {
+                // nothing collected - disable it
+                error("PLUGINSD: '%s' exited with error code %d. Disabling it.", cd->fullfilename, code);
+                cd->enabled = 0;
+            }
+            else {
+                // we have collected something
+
+                if(likely(cd->serial_failures <= 10)) {
+                    error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). Waiting a bit before starting it again.", cd->fullfilename, code, cd->successful_collections);
+                    sleep((unsigned int) (cd->update_every * 10));
+                }
+                else {
+                    error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). We tried %zu times to restart it, but it failed to generate data. Disabling it.", cd->fullfilename, code, cd->successful_collections, cd->serial_failures);
+                    cd->enabled = 0;
+                }
+            }
+        }
+        else {
+            // the plugin reports success
+
+            if(unlikely(!cd->successful_collections)) {
+                // we have collected nothing so far
+
+                if(likely(cd->serial_failures <= 10)) {
+                    error("PLUGINSD: '%s' (pid %d) does not generate useful output but it reports success (exits with 0). Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
+                    sleep((unsigned int) (cd->update_every * 10));
+                }
+                else {
+                    error("PLUGINSD: '%s' (pid %d) does not generate useful output, although it reports success (exits with 0), but we have tried %zu times to collect something. Disabling it.", cd->fullfilename, cd->pid, cd->serial_failures);
+                    cd->enabled = 0;
+                }
+            }
+            else
+                sleep((unsigned int) cd->update_every);
+        }
+        cd->pid = 0;
+
+        if(unlikely(!cd->enabled))
+            break;
+    }
+
+    cd->obsolete = 1;
+    pthread_exit(NULL);
+    return NULL;
 }
 
 void *pluginsd_main(void *ptr)
 {
-       if(ptr) { ; }
+    if(ptr) { ; }
 
-       info("PLUGINS.D thread created with task id %d", gettid());
-
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
-
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
-
-       char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
-       int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
-       int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
-       DIR *dir = NULL;
-       struct dirent *file = NULL;
-       struct plugind *cd;
-
-       // enable the apps plugin by default
-       // config_get_boolean("plugins", "apps", 1);
-
-       if(scan_frequency < 1) scan_frequency = 1;
-
-       while(likely(1)) {
-               if(unlikely(netdata_exit)) break;
-
-               dir = opendir(dir_name);
-               if(unlikely(!dir)) {
-                       error("Cannot open directory '%s'.", dir_name);
-                       pthread_exit(NULL);
-                       return NULL;
-               }
-
-               while(likely((file = readdir(dir)))) {
-                       if(unlikely(netdata_exit)) break;
-
-                       debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name);
-
-                       if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
-
-                       int len = (int) strlen(file->d_name);
-                       if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
-                       if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
-                               debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX);
-                               continue;
-                       }
-
-                       char pluginname[CONFIG_MAX_NAME + 1];
-                       snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
-                       int enabled = config_get_boolean("plugins", pluginname, automatic_run);
-
-                       if(unlikely(!enabled)) {
-                               debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
-                               continue;
-                       }
-
-                       // check if it runs already
-                       for(cd = pluginsd_root ; likely(cd) ; cd = cd->next) {
-                               if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
-                       }
-                       if(likely(cd && !cd->obsolete)) {
-                               debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename);
-                               continue;
-                       }
-
-                       // it is not running
-                       // allocate a new one, or use the obsolete one
-                       if(unlikely(!cd)) {
-                               cd = callocz(sizeof(struct plugind), 1);
-
-                               snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
-
-                               strncpyz(cd->filename, file->d_name, FILENAME_MAX);
-                               snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
-
-                               cd->enabled = enabled;
-                               cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
-                               cd->started_t = time(NULL);
-
-                               char *def = "";
-                               snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
-
-                               // link it
-                               if(likely(pluginsd_root)) cd->next = pluginsd_root;
-                               pluginsd_root = cd;
-                       }
-                       cd->obsolete = 0;
-
-                       if(unlikely(!cd->enabled)) continue;
-
-                       // spawn a new thread for it
-                       if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) {
-                               error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename);
-                               cd->obsolete = 1;
-                       }
-                       else if(unlikely(pthread_detach(cd->thread) != 0))
-                               error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename);
-               }
-
-               closedir(dir);
-               sleep((unsigned int) scan_frequency);
-       }
+    info("PLUGINS.D thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
+
+    char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
+    int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
+    int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
+    DIR *dir = NULL;
+    struct dirent *file = NULL;
+    struct plugind *cd;
+
+    // enable the apps plugin by default
+    // config_get_boolean("plugins", "apps", 1);
+
+    if(scan_frequency < 1) scan_frequency = 1;
+
+    while(likely(1)) {
+        if(unlikely(netdata_exit)) break;
+
+        dir = opendir(dir_name);
+        if(unlikely(!dir)) {
+            error("Cannot open directory '%s'.", dir_name);
+            pthread_exit(NULL);
+            return NULL;
+        }
+
+        while(likely((file = readdir(dir)))) {
+            if(unlikely(netdata_exit)) break;
+
+            debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name);
+
+            if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
+
+            int len = (int) strlen(file->d_name);
+            if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
+            if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
+                debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX);
+                continue;
+            }
+
+            char pluginname[CONFIG_MAX_NAME + 1];
+            snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
+            int enabled = config_get_boolean("plugins", pluginname, automatic_run);
+
+            if(unlikely(!enabled)) {
+                debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
+                continue;
+            }
+
+            // check if it runs already
+            for(cd = pluginsd_root ; likely(cd) ; cd = cd->next) {
+                if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
+            }
+            if(likely(cd && !cd->obsolete)) {
+                debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename);
+                continue;
+            }
+
+            // it is not running
+            // allocate a new one, or use the obsolete one
+            if(unlikely(!cd)) {
+                cd = callocz(sizeof(struct plugind), 1);
+
+                snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
+
+                strncpyz(cd->filename, file->d_name, FILENAME_MAX);
+                snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
+
+                cd->enabled = enabled;
+                cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
+                cd->started_t = time(NULL);
+
+                char *def = "";
+                snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
+
+                // link it
+                if(likely(pluginsd_root)) cd->next = pluginsd_root;
+                pluginsd_root = cd;
+            }
+            cd->obsolete = 0;
+
+            if(unlikely(!cd->enabled)) continue;
+
+            // spawn a new thread for it
+            if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) {
+                error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename);
+                cd->obsolete = 1;
+            }
+            else if(unlikely(pthread_detach(cd->thread) != 0))
+                error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename);
+        }
+
+        closedir(dir);
+        sleep((unsigned int) scan_frequency);
+    }
 
-       pthread_exit(NULL);
-       return NULL;
+    pthread_exit(NULL);
+    return NULL;
 }
index 7e49b184146c03e87c9e19e4977968047113ff7b..6f1fbd6e10fe85793a5f3c99871ab7e48ac284de 100644 (file)
@@ -7,28 +7,28 @@
 #define PLUGINSD_LINE_MAX 1024
 
 struct plugind {
-       char id[CONFIG_MAX_NAME+1];                     // config node id
+    char id[CONFIG_MAX_NAME+1];         // config node id
 
-       char filename[FILENAME_MAX+1];          // just the filename
-       char fullfilename[FILENAME_MAX+1];      // with path
-       char cmd[PLUGINSD_CMD_MAX+1];           // the command that is executes
+    char filename[FILENAME_MAX+1];      // just the filename
+    char fullfilename[FILENAME_MAX+1];  // with path
+    char cmd[PLUGINSD_CMD_MAX+1];       // the command that is executes
 
-       pid_t pid;
-       pthread_t thread;
+    pid_t pid;
+    pthread_t thread;
 
-       size_t successful_collections;          // the number of times we have seen
-                                                                               // values collected from this plugin
+    size_t successful_collections;      // the number of times we have seen
+                                        // values collected from this plugin
 
-       size_t serial_failures;                         // the number of times the plugin started
-                                                                               // without collecting values
+    size_t serial_failures;             // the number of times the plugin started
+                                        // without collecting values
 
-       int update_every;                                       // the plugin default data collection frequency
-       int obsolete;                                           // do not touch this structure after setting this to 1
-       int enabled;                                            // if this is enabled or not
+    int update_every;                   // the plugin default data collection frequency
+    int obsolete;                       // do not touch this structure after setting this to 1
+    int enabled;                        // if this is enabled or not
 
-       time_t started_t;
+    time_t started_t;
 
-       struct plugind *next;
+    struct plugind *next;
 };
 
 extern struct plugind *pluginsd_root;
index a603c72db302bcc4f465c46a9dcc4040d38a377c..eee08b5ed9010fe6532625bf6d3e0cc969feffc9 100644 (file)
@@ -2,42 +2,42 @@
 
 /*
 struct mypopen {
-       pid_t pid;
-       FILE *fp;
-       struct mypopen *next;
-       struct mypopen *prev;
+    pid_t pid;
+    FILE *fp;
+    struct mypopen *next;
+    struct mypopen *prev;
 };
 
 static struct mypopen *mypopen_root = NULL;
 
 static void mypopen_add(FILE *fp, pid_t *pid) {
-       struct mypopen *mp = malloc(sizeof(struct mypopen));
-       if(!mp) {
-               fatal("Cannot allocate %zu bytes", sizeof(struct mypopen))
-               return;
-       }
-
-       mp->fp = fp;
-       mp->pid = pid;
-       mp->next = popen_root;
-       mp->prev = NULL;
-       if(mypopen_root) mypopen_root->prev = mp;
-       mypopen_root = mp;
+    struct mypopen *mp = malloc(sizeof(struct mypopen));
+    if(!mp) {
+        fatal("Cannot allocate %zu bytes", sizeof(struct mypopen))
+        return;
+    }
+
+    mp->fp = fp;
+    mp->pid = pid;
+    mp->next = popen_root;
+    mp->prev = NULL;
+    if(mypopen_root) mypopen_root->prev = mp;
+    mypopen_root = mp;
 }
 
 static void mypopen_del(FILE *fp) {
-       struct mypopen *mp;
-
-       for(mp = mypopen_root; mp; mp = mp->next)
-               if(mp->fd == fp) break;
-
-       if(!mp) error("Cannot find mypopen() file pointer in open childs.");
-       else {
-               if(mp->next) mp->next->prev = mp->prev;
-               if(mp->prev) mp->prev->next = mp->next;
-               if(mypopen_root == mp) mypopen_root = mp->next;
-               free(mp);
-       }
+    struct mypopen *mp;
+
+    for(mp = mypopen_root; mp; mp = mp->next)
+        if(mp->fd == fp) break;
+
+    if(!mp) error("Cannot find mypopen() file pointer in open childs.");
+    else {
+        if(mp->next) mp->next->prev = mp->prev;
+        if(mp->prev) mp->prev->next = mp->next;
+        if(mypopen_root == mp) mypopen_root = mp->next;
+        free(mp);
+    }
 }
 */
 #define PIPE_READ 0
@@ -45,141 +45,141 @@ static void mypopen_del(FILE *fp) {
 
 FILE *mypopen(const char *command, pid_t *pidptr)
 {
-       int pipefd[2];
-
-       if(pipe(pipefd) == -1) return NULL;
-
-       int pid = fork();
-       if(pid == -1) {
-               close(pipefd[PIPE_READ]);
-               close(pipefd[PIPE_WRITE]);
-               return NULL;
-       }
-       if(pid != 0) {
-               // the parent
-               *pidptr = pid;
-               close(pipefd[PIPE_WRITE]);
-               FILE *fp = fdopen(pipefd[PIPE_READ], "r");
-               /*mypopen_add(fp, pid);*/
-               return(fp);
-       }
-       // the child
-
-       // close all files
-       int i;
-       for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
-               if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
-
-       // move the pipe to stdout
-       if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
-               dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
-               close(pipefd[PIPE_WRITE]);
-       }
+    int pipefd[2];
+
+    if(pipe(pipefd) == -1) return NULL;
+
+    int pid = fork();
+    if(pid == -1) {
+        close(pipefd[PIPE_READ]);
+        close(pipefd[PIPE_WRITE]);
+        return NULL;
+    }
+    if(pid != 0) {
+        // the parent
+        *pidptr = pid;
+        close(pipefd[PIPE_WRITE]);
+        FILE *fp = fdopen(pipefd[PIPE_READ], "r");
+        /*mypopen_add(fp, pid);*/
+        return(fp);
+    }
+    // the child
+
+    // close all files
+    int i;
+    for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
+        if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
+
+    // move the pipe to stdout
+    if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
+        dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
+        close(pipefd[PIPE_WRITE]);
+    }
 
 #ifdef DETACH_PLUGINS_FROM_NETDATA
-       // this was an attempt to detach the child and use the suspend mode charts.d
-       // unfortunatelly it does not work as expected.
+    // this was an attempt to detach the child and use the suspend mode charts.d
+    // unfortunatelly it does not work as expected.
 
-       // fork again to become session leader
-       pid = fork();
-       if(pid == -1)
-               error("pre-execution of command '%s' on pid %d: Cannot fork 2nd time.", command, getpid());
+    // fork again to become session leader
+    pid = fork();
+    if(pid == -1)
+        error("pre-execution of command '%s' on pid %d: Cannot fork 2nd time.", command, getpid());
 
-       if(pid != 0) {
-               // the parent
-               exit(0);
-       }
+    if(pid != 0) {
+        // the parent
+        exit(0);
+    }
 
-       // set a new process group id for just this child
-       if( setpgid(0, 0) != 0 )
-               error("pre-execution of command '%s' on pid %d: Cannot set a new process group.", command, getpid());
+    // set a new process group id for just this child
+    if( setpgid(0, 0) != 0 )
+        error("pre-execution of command '%s' on pid %d: Cannot set a new process group.", command, getpid());
 
-       if( getpgid(0) != getpid() )
-               error("pre-execution of command '%s' on pid %d: Cannot set a new process group. Process group set is incorrect. Expected %d, found %d", command, getpid(), getpid(), getpgid(0));
+    if( getpgid(0) != getpid() )
+        error("pre-execution of command '%s' on pid %d: Cannot set a new process group. Process group set is incorrect. Expected %d, found %d", command, getpid(), getpid(), getpgid(0));
 
-       if( setsid() != 0 )
-               error("pre-execution of command '%s' on pid %d: Cannot set session id.", command, getpid());
+    if( setsid() != 0 )
+        error("pre-execution of command '%s' on pid %d: Cannot set session id.", command, getpid());
 
-       fprintf(stdout, "MYPID %d\n", getpid());
-       fflush(NULL);
+    fprintf(stdout, "MYPID %d\n", getpid());
+    fflush(NULL);
 #endif
 
-       // reset all signals
-       {
-               sigset_t sigset;
-               sigfillset(&sigset);
-
-               if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
-                       error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
-               
-               // We only need to reset ignored signals.
-               // Signals with signal handlers are reset by default.
-               struct sigaction sa;
-               sigemptyset(&sa.sa_mask);
-               sa.sa_handler = SIG_DFL;
-               sa.sa_flags = 0;
-               
-               if(sigaction(SIGUSR1, &sa, NULL) == -1)
-                       error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
-
-               if(sigaction(SIGPIPE, &sa, NULL) == -1)
-                       error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
-       }
-
-
-       info("executing command: '%s' on pid %d.", command, getpid());
-       execl("/bin/sh", "sh", "-c", command, NULL);
-       exit(1);
+    // reset all signals
+    {
+        sigset_t sigset;
+        sigfillset(&sigset);
+
+        if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
+            error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
+        
+        // We only need to reset ignored signals.
+        // Signals with signal handlers are reset by default.
+        struct sigaction sa;
+        sigemptyset(&sa.sa_mask);
+        sa.sa_handler = SIG_DFL;
+        sa.sa_flags = 0;
+        
+        if(sigaction(SIGUSR1, &sa, NULL) == -1)
+            error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
+
+        if(sigaction(SIGPIPE, &sa, NULL) == -1)
+            error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
+    }
+
+
+    info("executing command: '%s' on pid %d.", command, getpid());
+    execl("/bin/sh", "sh", "-c", command, NULL);
+    exit(1);
 }
 
 int mypclose(FILE *fp, pid_t pid) {
-       debug(D_EXIT, "Request to mypclose() on pid %d", pid);
-
-       /*mypopen_del(fp);*/
-       fclose(fp);
-
-       siginfo_t info;
-       if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) {
-               switch(info.si_code) {
-                       case CLD_EXITED:
-                               if(info.si_status)
-                                       error("child pid %d exited with code %d.", info.si_pid, info.si_status);
-                               return(info.si_status);
-                               break;
-
-                       case CLD_KILLED:
-                               error("child pid %d killed by signal %d.", info.si_pid, info.si_status);
-                               return(-1);
-                               break;
-
-                       case CLD_DUMPED:
-                               error("child pid %d core dumped by signal %d.", info.si_pid, info.si_status);
-                               return(-2);
-                               break;
-
-                       case CLD_STOPPED:
-                               error("child pid %d stopped by signal %d.", info.si_pid, info.si_status);
-                               return(0);
-                               break;
-
-                       case CLD_TRAPPED:
-                               error("child pid %d trapped by signal %d.", info.si_pid, info.si_status);
-                               return(-4);
-                               break;
-
-                       case CLD_CONTINUED:
-                               error("child pid %d continued by signal %d.", info.si_pid, info.si_status);
-                               return(0);
-                               break;
-
-                       default:
-                               error("child pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
-                               return(-5);
-                               break;
-               }
-       }
-       else
-               error("Cannot waitid() for pid %d", pid);
-       
-       return 0;
+    debug(D_EXIT, "Request to mypclose() on pid %d", pid);
+
+    /*mypopen_del(fp);*/
+    fclose(fp);
+
+    siginfo_t info;
+    if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) {
+        switch(info.si_code) {
+            case CLD_EXITED:
+                if(info.si_status)
+                    error("child pid %d exited with code %d.", info.si_pid, info.si_status);
+                return(info.si_status);
+                break;
+
+            case CLD_KILLED:
+                error("child pid %d killed by signal %d.", info.si_pid, info.si_status);
+                return(-1);
+                break;
+
+            case CLD_DUMPED:
+                error("child pid %d core dumped by signal %d.", info.si_pid, info.si_status);
+                return(-2);
+                break;
+
+            case CLD_STOPPED:
+                error("child pid %d stopped by signal %d.", info.si_pid, info.si_status);
+                return(0);
+                break;
+
+            case CLD_TRAPPED:
+                error("child pid %d trapped by signal %d.", info.si_pid, info.si_status);
+                return(-4);
+                break;
+
+            case CLD_CONTINUED:
+                error("child pid %d continued by signal %d.", info.si_pid, info.si_status);
+                return(0);
+                break;
+
+            default:
+                error("child pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
+                return(-5);
+                break;
+        }
+    }
+    else
+        error("Cannot waitid() for pid %d", pid);
+    
+    return 0;
 }
index f47cd4469243d04cf55d6d010eb7e38a7a3dcc18..459d5a133b29fd2e5024e20b7b37ab92b1c6f2df 100644 (file)
 #define DISK_TYPE_CONTAINER 3
 
 static struct disk {
-       char *disk;                             // the name of the disk (sda, sdb, etc)
-       unsigned long major;
-       unsigned long minor;
-       int sector_size;
-       int type;
-       char *mount_point;
-
-       // disk options caching
-       int configured;
-       int do_io;
-       int do_ops;
-       int do_mops;
-       int do_iotime;
-       int do_qops;
-       int do_util;
-       int do_backlog;
-       int do_space;
-       int do_inodes;
-
-       struct disk *next;
+    char *disk;             // the name of the disk (sda, sdb, etc)
+    unsigned long major;
+    unsigned long minor;
+    int sector_size;
+    int type;
+    char *mount_point;
+
+    // disk options caching
+    int configured;
+    int do_io;
+    int do_ops;
+    int do_mops;
+    int do_iotime;
+    int do_qops;
+    int do_util;
+    int do_backlog;
+    int do_space;
+    int do_inodes;
+
+    struct disk *next;
 } *disk_root = NULL;
 
 static struct mountinfo *disk_mountinfo_root = NULL;
 
 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
-       static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
-       static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
-       static char path_find_block_device[FILENAME_MAX + 1] = "";
-       struct disk *d;
-
-       // search for it in our RAM list.
-       // this is sequential, but since we just walk through
-       // and the number of disks / partitions in a system
-       // should not be that many, it should be acceptable
-       for(d = disk_root; d ; d = d->next)
-               if(unlikely(d->major == major && d->minor == minor))
-                       break;
-
-       // if we found it, return it
-       if(likely(d))
-               return d;
-
-       // not found
-       // create a new disk structure
-       d = (struct disk *)mallocz(sizeof(struct disk));
-
-       d->disk = strdupz(disk);
-       d->major = major;
-       d->minor = minor;
-       d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
-       d->configured = 0;
-       d->sector_size = 512; // the default, will be changed below
-       d->next = NULL;
-
-       // append it to the list
-       if(!disk_root)
-               disk_root = d;
-       else {
-               struct disk *last;
-               for(last = disk_root; last->next ;last = last->next);
-               last->next = d;
-       }
-
-       // ------------------------------------------------------------------------
-       // find the type of the device
-
-       char buffer[FILENAME_MAX + 1];
-
-       // get the default path for finding info about the block device
-       if(unlikely(!path_find_block_device[0])) {
-               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
-               snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
-       }
-
-       // find if it is a partition
-       // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
-       snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
-       if(access(buffer, R_OK) == 0) {
-               d->type = DISK_TYPE_PARTITION;
-       } else {
-               // find if it is a container
-               // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries
-               snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
-               DIR *dirp = opendir(buffer);    
-               if (dirp != NULL) {
-                       struct dirent *dp;
-                       while( (dp = readdir(dirp)) ) {
-                               // . and .. are also files in empty folders.
-                               if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
-                                       continue;
-                               }
-
-                               d->type = DISK_TYPE_CONTAINER;
-
-                               // Stop the loop after we found one file.
-                               break;
-                       }
-                       if(closedir(dirp) == -1)
-                               error("Unable to close dir %s", buffer);
-               }
-       }
-
-       // ------------------------------------------------------------------------
-       // check if we can find its mount point
-
-       // mountinfo_find() can be called with NULL disk_mountinfo_root
-       struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
-       if(unlikely(!mi)) {
-               // mountinfo_free() can be called with NULL disk_mountinfo_root
-               mountinfo_free(disk_mountinfo_root);
-
-               // re-read mountinfo in case something changed
-               disk_mountinfo_root = mountinfo_read();
-
-               // search again for this disk
-               mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
-       }
-
-       if(mi)
-               d->mount_point = strdupz(mi->mount_point);
-               // no need to check for NULL
-       else
-               d->mount_point = NULL;
-
-       // ------------------------------------------------------------------------
-       // find the disk sector size
-
-       if(!path_to_get_hw_sector_size[0]) {
-               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
-               snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
-       }
-       if(!path_to_get_hw_sector_size_partitions[0]) {
-               snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
-               snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
-       }
-
-       {
-               char tf[FILENAME_MAX + 1], *t;
-               strncpyz(tf, d->disk, FILENAME_MAX);
-
-               // replace all / with !
-               for(t = tf; *t ;t++)
-                       if(*t == '/') *t = '!';
-
-               if(d->type == DISK_TYPE_PARTITION)
-                       snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf);
-               else
-                       snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf);
-
-               FILE *fpss = fopen(buffer, "r");
-               if(fpss) {
-                       char buffer2[1024 + 1];
-                       char *tmp = fgets(buffer2, 1024, fpss);
-
-                       if(tmp) {
-                               d->sector_size = atoi(tmp);
-                               if(d->sector_size <= 0) {
-                                       error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->disk, buffer);
-                                       d->sector_size = 512;
-                               }
-                       }
-                       else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->disk, buffer);
-
-                       fclose(fpss);
-               }
-               else error("Cannot read sector size for device %s from %s. Assuming 512.", d->disk, buffer);
-       }
-
-       return d;
+    static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
+    static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
+    static char path_find_block_device[FILENAME_MAX + 1] = "";
+    struct disk *d;
+
+    // search for it in our RAM list.
+    // this is sequential, but since we just walk through
+    // and the number of disks / partitions in a system
+    // should not be that many, it should be acceptable
+    for(d = disk_root; d ; d = d->next)
+        if(unlikely(d->major == major && d->minor == minor))
+            break;
+
+    // if we found it, return it
+    if(likely(d))
+        return d;
+
+    // not found
+    // create a new disk structure
+    d = (struct disk *)mallocz(sizeof(struct disk));
+
+    d->disk = strdupz(disk);
+    d->major = major;
+    d->minor = minor;
+    d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
+    d->configured = 0;
+    d->sector_size = 512; // the default, will be changed below
+    d->next = NULL;
+
+    // append it to the list
+    if(!disk_root)
+        disk_root = d;
+    else {
+        struct disk *last;
+        for(last = disk_root; last->next ;last = last->next);
+        last->next = d;
+    }
+
+    // ------------------------------------------------------------------------
+    // find the type of the device
+
+    char buffer[FILENAME_MAX + 1];
+
+    // get the default path for finding info about the block device
+    if(unlikely(!path_find_block_device[0])) {
+        snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
+        snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
+    }
+
+    // find if it is a partition
+    // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
+    snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
+    if(access(buffer, R_OK) == 0) {
+        d->type = DISK_TYPE_PARTITION;
+    } else {
+        // find if it is a container
+        // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries
+        snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
+        DIR *dirp = opendir(buffer);    
+        if (dirp != NULL) {
+            struct dirent *dp;
+            while( (dp = readdir(dirp)) ) {
+                // . and .. are also files in empty folders.
+                if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
+                    continue;
+                }
+
+                d->type = DISK_TYPE_CONTAINER;
+
+                // Stop the loop after we found one file.
+                break;
+            }
+            if(closedir(dirp) == -1)
+                error("Unable to close dir %s", buffer);
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // check if we can find its mount point
+
+    // mountinfo_find() can be called with NULL disk_mountinfo_root
+    struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
+    if(unlikely(!mi)) {
+        // mountinfo_free() can be called with NULL disk_mountinfo_root
+        mountinfo_free(disk_mountinfo_root);
+
+        // re-read mountinfo in case something changed
+        disk_mountinfo_root = mountinfo_read();
+
+        // search again for this disk
+        mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
+    }
+
+    if(mi)
+        d->mount_point = strdupz(mi->mount_point);
+        // no need to check for NULL
+    else
+        d->mount_point = NULL;
+
+    // ------------------------------------------------------------------------
+    // find the disk sector size
+
+    if(!path_to_get_hw_sector_size[0]) {
+        snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
+        snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
+    }
+    if(!path_to_get_hw_sector_size_partitions[0]) {
+        snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
+        snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
+    }
+
+    {
+        char tf[FILENAME_MAX + 1], *t;
+        strncpyz(tf, d->disk, FILENAME_MAX);
+
+        // replace all / with !
+        for(t = tf; *t ;t++)
+            if(*t == '/') *t = '!';
+
+        if(d->type == DISK_TYPE_PARTITION)
+            snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf);
+        else
+            snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf);
+
+        FILE *fpss = fopen(buffer, "r");
+        if(fpss) {
+            char buffer2[1024 + 1];
+            char *tmp = fgets(buffer2, 1024, fpss);
+
+            if(tmp) {
+                d->sector_size = atoi(tmp);
+                if(d->sector_size <= 0) {
+                    error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->disk, buffer);
+                    d->sector_size = 512;
+                }
+            }
+            else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->disk, buffer);
+
+            fclose(fpss);
+        }
+        else error("Cannot read sector size for device %s from %s. Assuming 512.", d->disk, buffer);
+    }
+
+    return d;
 }
 
 static inline int select_positive_option(int option1, int option2) {
-       if(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES)
-               return CONFIG_ONDEMAND_YES;
-       else if(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND)
-               return CONFIG_ONDEMAND_ONDEMAND;
+    if(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES)
+        return CONFIG_ONDEMAND_YES;
+    else if(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND)
+        return CONFIG_ONDEMAND_ONDEMAND;
 
-       return CONFIG_ONDEMAND_NO;
+    return CONFIG_ONDEMAND_NO;
 }
 
 int do_proc_diskstats(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static struct statvfs buff_statvfs;
-       static struct stat buff_stat;
-       static int      global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
-                               global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
-                               global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
-                               global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
-                               global_enable_performance_for_mountpoints = CONFIG_ONDEMAND_NO,
-                               global_enable_performance_for_virtual_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
-                               global_enable_space_for_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_io = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_util = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_space = CONFIG_ONDEMAND_ONDEMAND,
-                               global_do_inodes = CONFIG_ONDEMAND_ONDEMAND,
-                               globals_initialized = 0;
-
-       if(unlikely(!globals_initialized)) {
-               global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
-
-               global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
-               global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
-               global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
-               global_enable_performance_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", global_enable_performance_for_mountpoints);
-               global_enable_performance_for_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", global_enable_performance_for_virtual_mountpoints);
-               global_enable_space_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", global_enable_space_for_mountpoints);
-
-               global_do_io      = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
-               global_do_ops     = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
-               global_do_mops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
-               global_do_iotime  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
-               global_do_qops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
-               global_do_util    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
-               global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
-               global_do_space   = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", global_do_space);
-               global_do_inodes  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", global_do_inodes);
-
-               globals_initialized = 1;
-       }
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
-               ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       for(l = 0; l < lines ;l++) {
-               // --------------------------------------------------------------------------
-               // Read parameters
-
-               char *disk;
-               unsigned long long      major = 0, minor = 0,
-                                                       reads = 0,  mreads = 0,  readsectors = 0,  readms = 0,
-                                                       writes = 0, mwrites = 0, writesectors = 0, writems = 0,
-                                                       queued_ios = 0, busy_ms = 0, backlog_ms = 0,
-                                                       space_avail = 0, space_avail_root = 0, space_used = 0,
-                                                       inodes_avail = 0, inodes_avail_root = 0, inodes_used = 0;
-
-               unsigned long long      last_reads = 0,  last_readsectors = 0,  last_readms = 0,
-                                                       last_writes = 0, last_writesectors = 0, last_writems = 0,
-                                                       last_busy_ms = 0;
-
-               words = procfile_linewords(ff, l);
-               if(words < 14) continue;
-
-               major                   = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
-               minor                   = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-               disk                    = procfile_lineword(ff, l, 2);
-
-               // # of reads completed # of writes completed
-               // This is the total number of reads or writes completed successfully.
-               reads                   = strtoull(procfile_lineword(ff, l, 3), NULL, 10);      // rd_ios
-               writes                  = strtoull(procfile_lineword(ff, l, 7), NULL, 10);      // wr_ios
-
-               // # of reads merged # of writes merged
-               // Reads and writes which are adjacent to each other may be merged for
-           // efficiency.  Thus two 4K reads may become one 8K read before it is
-           // ultimately handed to the disk, and so it will be counted (and queued)
-               mreads                  = strtoull(procfile_lineword(ff, l, 4), NULL, 10);      // rd_merges_or_rd_sec
-               mwrites                 = strtoull(procfile_lineword(ff, l, 8), NULL, 10);      // wr_merges
-
-               // # of sectors read # of sectors written
-               // This is the total number of sectors read or written successfully.
-               readsectors     = strtoull(procfile_lineword(ff, l, 5), NULL, 10);      // rd_sec_or_wr_ios
-               writesectors    = strtoull(procfile_lineword(ff, l, 9), NULL, 10);      // wr_sec
-
-               // # of milliseconds spent reading # of milliseconds spent writing
-               // This is the total number of milliseconds spent by all reads or writes (as
-               // measured from __make_request() to end_that_request_last()).
-               readms                  = strtoull(procfile_lineword(ff, l, 6), NULL, 10);      // rd_ticks_or_wr_sec
-               writems                 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);     // wr_ticks
-
-               // # of I/Os currently in progress
-               // The only field that should go to zero. Incremented as requests are
-               // given to appropriate struct request_queue and decremented as they finish.
-               queued_ios              = strtoull(procfile_lineword(ff, l, 11), NULL, 10);     // ios_pgr
-
-               // # of milliseconds spent doing I/Os
-               // This field increases so long as field queued_ios is nonzero.
-               busy_ms                 = strtoull(procfile_lineword(ff, l, 12), NULL, 10);     // tot_ticks
-
-               // weighted # of milliseconds spent doing I/Os
-               // This field is incremented at each I/O start, I/O completion, I/O
-               // merge, or read of these stats by the number of I/Os in progress
-               // (field queued_ios) times the number of milliseconds spent doing I/O since the
-               // last update of this field.  This can provide an easy measure of both
-               // I/O completion time and the backlog that may be accumulating.
-               backlog_ms              = strtoull(procfile_lineword(ff, l, 13), NULL, 10);     // rq_ticks
-
-
-               // --------------------------------------------------------------------------
-               // remove slashes from disk names
-               char *s;
-               for(s = disk; *s ;s++)
-                       if(*s == '/') *s = '_';
-
-               // --------------------------------------------------------------------------
-               // get a disk structure for the disk
-
-               struct disk *d = get_disk(major, minor, disk);
-
-
-               // --------------------------------------------------------------------------
-               // Set its family based on mount point
-
-               char *family = d->mount_point;
-               if(!family) family = disk;
-
-
-               // --------------------------------------------------------------------------
-               // Check the configuration for the device
-
-               if(unlikely(!d->configured)) {
-                       char var_name[4096 + 1];
-                       snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
-
-                       int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
-                       if(def_enable == CONFIG_ONDEMAND_NO) {
-                               // the user does not want any metrics for this disk
-                               d->do_io = CONFIG_ONDEMAND_NO;
-                               d->do_ops = CONFIG_ONDEMAND_NO;
-                               d->do_mops = CONFIG_ONDEMAND_NO;
-                               d->do_iotime = CONFIG_ONDEMAND_NO;
-                               d->do_qops = CONFIG_ONDEMAND_NO;
-                               d->do_util = CONFIG_ONDEMAND_NO;
-                               d->do_backlog = CONFIG_ONDEMAND_NO;
-                               d->do_space = CONFIG_ONDEMAND_NO;
-                               d->do_inodes = CONFIG_ONDEMAND_NO;
-                       }
-                       else {
-                               // this disk is enabled
-                               // check its direct settings
-
-                               int def_performance = CONFIG_ONDEMAND_ONDEMAND;
-                               int def_space = (d->mount_point)?CONFIG_ONDEMAND_ONDEMAND:CONFIG_ONDEMAND_NO;
-
-                               // since this is 'on demand' we can figure the performance settings
-                               // based on the type of disk
-
-                               switch(d->type) {
-                                       case DISK_TYPE_PHYSICAL:
-                                               def_performance = global_enable_performance_for_physical_disks;
-                                               break;
-
-                                       case DISK_TYPE_PARTITION:
-                                               def_performance = global_enable_performance_for_partitions;
-                                               break;
-
-                                       case DISK_TYPE_CONTAINER:
-                                               def_performance = global_enable_performance_for_virtual_disks;
-
-                                               if(d->mount_point)
-                                                       def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
-
-                                               break;
-                               }
-
-                               if(d->mount_point)
-                                       def_performance = select_positive_option(def_performance, global_enable_performance_for_mountpoints);
-
-                               // ------------------------------------------------------------
-                               // now we have def_performance and def_space
-                               // to work further
-
-                               // def_performance
-                               // check the user configuration (this will also show our 'on demand' decision)
-                               def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
-
-                               int ddo_io = CONFIG_ONDEMAND_NO,
-                                       ddo_ops = CONFIG_ONDEMAND_NO,
-                                       ddo_mops = CONFIG_ONDEMAND_NO,
-                                       ddo_iotime = CONFIG_ONDEMAND_NO,
-                                       ddo_qops = CONFIG_ONDEMAND_NO,
-                                       ddo_util = CONFIG_ONDEMAND_NO,
-                                       ddo_backlog = CONFIG_ONDEMAND_NO;
-
-                               // we enable individual performance charts only when def_performance is not disabled
-                               if(def_performance != CONFIG_ONDEMAND_NO) {
-                                       ddo_io = global_do_io,
-                                       ddo_ops = global_do_ops,
-                                       ddo_mops = global_do_mops,
-                                       ddo_iotime = global_do_iotime,
-                                       ddo_qops = global_do_qops,
-                                       ddo_util = global_do_util,
-                                       ddo_backlog = global_do_backlog;
-                               }
-
-                               d->do_io      = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
-                               d->do_ops     = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
-                               d->do_mops    = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
-                               d->do_iotime  = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
-                               d->do_qops    = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
-                               d->do_util    = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
-                               d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
-
-                               // def_space
-                               if(d->mount_point) {
-                                       // check the user configuration (this will also show our 'on demand' decision)
-                                       def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
-
-                                       int ddo_space = def_space,
-                                               ddo_inodes = def_space;
-
-                                       d->do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
-                                       d->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
-                               }
-                               else {
-                                       // don't show settings for this disk
-                                       d->do_space = CONFIG_ONDEMAND_NO;
-                                       d->do_inodes = CONFIG_ONDEMAND_NO;
-                               }
-                       }
-
-                       d->configured = 1;
-               }
-
-               RRDSET *st;
-
-               // --------------------------------------------------------------------------
-               // Do performance metrics
-
-               if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
-                       d->do_io = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
-                       if(!st) {
-                               st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
-
-                               rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       last_readsectors  = rrddim_set(st, "reads", readsectors);
-                       last_writesectors = rrddim_set(st, "writes", writesectors);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
-                       d->do_ops = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_ops", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       last_reads  = rrddim_set(st, "reads", reads);
-                       last_writes = rrddim_set(st, "writes", writes);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
-                       d->do_qops = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_qops", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       rrddim_set(st, "operations", queued_ios);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
-                       d->do_backlog = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_backlog", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       rrddim_set(st, "backlog", backlog_ms);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
-                       d->do_util = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_util", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       last_busy_ms = rrddim_set(st, "utilization", busy_ms);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
-                       d->do_mops = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_mops", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       rrddim_set(st, "reads", mreads);
-                       rrddim_set(st, "writes", mwrites);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
-                       d->do_iotime = CONFIG_ONDEMAND_YES;
-
-                       st = rrdset_find_bytype("disk_iotime", disk);
-                       if(!st) {
-                               st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next_usec(st, dt);
-
-                       last_readms  = rrddim_set(st, "reads", readms);
-                       last_writems = rrddim_set(st, "writes", writems);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-               // calculate differential charts
-               // only if this is not the first time we run
-
-               if(dt) {
-                       if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
-                               (d->do_ops    == CONFIG_ONDEMAND_YES || (d->do_ops    == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
-                               st = rrdset_find_bytype("disk_await", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                       rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next_usec(st, dt);
-
-                               rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
-                               rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
-                               rrdset_done(st);
-                       }
-
-                       if( (d->do_io  == CONFIG_ONDEMAND_YES || (d->do_io  == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
-                               (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
-                               st = rrdset_find_bytype("disk_avgsz", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
-                                       rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next_usec(st, dt);
-
-                               rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
-                               rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
-                               rrdset_done(st);
-                       }
-
-                       if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
-                               (d->do_ops  == CONFIG_ONDEMAND_YES || (d->do_ops  == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
-                               st = rrdset_find_bytype("disk_svctm", disk);
-                               if(!st) {
-                                       st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next_usec(st, dt);
-
-                               rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
-                               rrdset_done(st);
-                       }
-               }
-
-               // --------------------------------------------------------------------------
-               // space metrics
-
-               if(d->mount_point && (d->do_space || d->do_inodes) ) {
-                       // collect space metrics using statvfs
-
-                       if (statvfs(d->mount_point, &buff_statvfs) < 0)
-                               error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
-                       else {
-                               space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
-                               space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
-                               space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
-
-                               inodes_avail = buff_statvfs.f_favail;
-                               inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
-                               inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
-
-                               // verify we collected the metrics for the right disk.
-                               // if not the mountpoint has changed.
-
-                               if(stat(d->mount_point, &buff_stat) == -1)
-                                       error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
-                               else {
-                                       if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
-
-                                               // --------------------------------------------------------------------------
-
-                                               if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
-                                                       st = rrdset_find_bytype("disk_space", disk);
-                                                       if(!st) {
-                                                               st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
-                                                               st->isdetail = 1;
-
-                                                               rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
-                                                               rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
-                                                               rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
-                                                       }
-                                                       else rrdset_next_usec(st, dt);
-
-                                                       rrddim_set(st, "avail", space_avail);
-                                                       rrddim_set(st, "used", space_used);
-                                                       rrddim_set(st, "reserved_for_root", space_avail_root);
-                                                       rrdset_done(st);
-                                               }
-
-                                               // --------------------------------------------------------------------------
-
-                                               if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
-                                                       st = rrdset_find_bytype("disk_inodes", disk);
-                                                       if(!st) {
-                                                               st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
-                                                               st->isdetail = 1;
-
-                                                               rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                                               rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
-                                                               rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
-                                                       }
-                                                       else rrdset_next_usec(st, dt);
-
-                                                       rrddim_set(st, "avail", inodes_avail);
-                                                       rrddim_set(st, "used", inodes_used);
-                                                       rrddim_set(st, "reserved_for_root", inodes_avail_root);
-                                                       rrdset_done(st);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static struct statvfs buff_statvfs;
+    static struct stat buff_stat;
+    static int  global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
+                global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
+                global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
+                global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
+                global_enable_performance_for_mountpoints = CONFIG_ONDEMAND_NO,
+                global_enable_performance_for_virtual_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
+                global_enable_space_for_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_io = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_util = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_space = CONFIG_ONDEMAND_ONDEMAND,
+                global_do_inodes = CONFIG_ONDEMAND_ONDEMAND,
+                globals_initialized = 0;
+
+    if(unlikely(!globals_initialized)) {
+        global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
+
+        global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
+        global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
+        global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
+        global_enable_performance_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", global_enable_performance_for_mountpoints);
+        global_enable_performance_for_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", global_enable_performance_for_virtual_mountpoints);
+        global_enable_space_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", global_enable_space_for_mountpoints);
+
+        global_do_io      = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
+        global_do_ops     = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
+        global_do_mops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
+        global_do_iotime  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
+        global_do_qops    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
+        global_do_util    = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
+        global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
+        global_do_space   = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", global_do_space);
+        global_do_inodes  = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", global_do_inodes);
+
+        globals_initialized = 1;
+    }
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
+        ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    for(l = 0; l < lines ;l++) {
+        // --------------------------------------------------------------------------
+        // Read parameters
+
+        char *disk;
+        unsigned long long  major = 0, minor = 0,
+                            reads = 0,  mreads = 0,  readsectors = 0,  readms = 0,
+                            writes = 0, mwrites = 0, writesectors = 0, writems = 0,
+                            queued_ios = 0, busy_ms = 0, backlog_ms = 0,
+                            space_avail = 0, space_avail_root = 0, space_used = 0,
+                            inodes_avail = 0, inodes_avail_root = 0, inodes_used = 0;
+
+        unsigned long long  last_reads = 0,  last_readsectors = 0,  last_readms = 0,
+                            last_writes = 0, last_writesectors = 0, last_writems = 0,
+                            last_busy_ms = 0;
+
+        words = procfile_linewords(ff, l);
+        if(words < 14) continue;
+
+        major           = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
+        minor           = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        disk            = procfile_lineword(ff, l, 2);
+
+        // # of reads completed # of writes completed
+        // This is the total number of reads or writes completed successfully.
+        reads           = strtoull(procfile_lineword(ff, l, 3), NULL, 10);  // rd_ios
+        writes          = strtoull(procfile_lineword(ff, l, 7), NULL, 10);  // wr_ios
+
+        // # of reads merged # of writes merged
+        // Reads and writes which are adjacent to each other may be merged for
+        // efficiency.  Thus two 4K reads may become one 8K read before it is
+        // ultimately handed to the disk, and so it will be counted (and queued)
+        mreads          = strtoull(procfile_lineword(ff, l, 4), NULL, 10);  // rd_merges_or_rd_sec
+        mwrites         = strtoull(procfile_lineword(ff, l, 8), NULL, 10);  // wr_merges
+
+        // # of sectors read # of sectors written
+        // This is the total number of sectors read or written successfully.
+        readsectors     = strtoull(procfile_lineword(ff, l, 5), NULL, 10);  // rd_sec_or_wr_ios
+        writesectors    = strtoull(procfile_lineword(ff, l, 9), NULL, 10);  // wr_sec
+
+        // # of milliseconds spent reading # of milliseconds spent writing
+        // This is the total number of milliseconds spent by all reads or writes (as
+        // measured from __make_request() to end_that_request_last()).
+        readms          = strtoull(procfile_lineword(ff, l, 6), NULL, 10);  // rd_ticks_or_wr_sec
+        writems         = strtoull(procfile_lineword(ff, l, 10), NULL, 10); // wr_ticks
+
+        // # of I/Os currently in progress
+        // The only field that should go to zero. Incremented as requests are
+        // given to appropriate struct request_queue and decremented as they finish.
+        queued_ios      = strtoull(procfile_lineword(ff, l, 11), NULL, 10); // ios_pgr
+
+        // # of milliseconds spent doing I/Os
+        // This field increases so long as field queued_ios is nonzero.
+        busy_ms         = strtoull(procfile_lineword(ff, l, 12), NULL, 10); // tot_ticks
+
+        // weighted # of milliseconds spent doing I/Os
+        // This field is incremented at each I/O start, I/O completion, I/O
+        // merge, or read of these stats by the number of I/Os in progress
+        // (field queued_ios) times the number of milliseconds spent doing I/O since the
+        // last update of this field.  This can provide an easy measure of both
+        // I/O completion time and the backlog that may be accumulating.
+        backlog_ms      = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
+
+
+        // --------------------------------------------------------------------------
+        // remove slashes from disk names
+        char *s;
+        for(s = disk; *s ;s++)
+            if(*s == '/') *s = '_';
+
+        // --------------------------------------------------------------------------
+        // get a disk structure for the disk
+
+        struct disk *d = get_disk(major, minor, disk);
+
+
+        // --------------------------------------------------------------------------
+        // Set its family based on mount point
+
+        char *family = d->mount_point;
+        if(!family) family = disk;
+
+
+        // --------------------------------------------------------------------------
+        // Check the configuration for the device
+
+        if(unlikely(!d->configured)) {
+            char var_name[4096 + 1];
+            snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
+
+            int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
+            if(def_enable == CONFIG_ONDEMAND_NO) {
+                // the user does not want any metrics for this disk
+                d->do_io = CONFIG_ONDEMAND_NO;
+                d->do_ops = CONFIG_ONDEMAND_NO;
+                d->do_mops = CONFIG_ONDEMAND_NO;
+                d->do_iotime = CONFIG_ONDEMAND_NO;
+                d->do_qops = CONFIG_ONDEMAND_NO;
+                d->do_util = CONFIG_ONDEMAND_NO;
+                d->do_backlog = CONFIG_ONDEMAND_NO;
+                d->do_space = CONFIG_ONDEMAND_NO;
+                d->do_inodes = CONFIG_ONDEMAND_NO;
+            }
+            else {
+                // this disk is enabled
+                // check its direct settings
+
+                int def_performance = CONFIG_ONDEMAND_ONDEMAND;
+                int def_space = (d->mount_point)?CONFIG_ONDEMAND_ONDEMAND:CONFIG_ONDEMAND_NO;
+
+                // since this is 'on demand' we can figure the performance settings
+                // based on the type of disk
+
+                switch(d->type) {
+                    case DISK_TYPE_PHYSICAL:
+                        def_performance = global_enable_performance_for_physical_disks;
+                        break;
+
+                    case DISK_TYPE_PARTITION:
+                        def_performance = global_enable_performance_for_partitions;
+                        break;
+
+                    case DISK_TYPE_CONTAINER:
+                        def_performance = global_enable_performance_for_virtual_disks;
+
+                        if(d->mount_point)
+                            def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
+
+                        break;
+                }
+
+                if(d->mount_point)
+                    def_performance = select_positive_option(def_performance, global_enable_performance_for_mountpoints);
+
+                // ------------------------------------------------------------
+                // now we have def_performance and def_space
+                // to work further
+
+                // def_performance
+                // check the user configuration (this will also show our 'on demand' decision)
+                def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
+
+                int ddo_io = CONFIG_ONDEMAND_NO,
+                    ddo_ops = CONFIG_ONDEMAND_NO,
+                    ddo_mops = CONFIG_ONDEMAND_NO,
+                    ddo_iotime = CONFIG_ONDEMAND_NO,
+                    ddo_qops = CONFIG_ONDEMAND_NO,
+                    ddo_util = CONFIG_ONDEMAND_NO,
+                    ddo_backlog = CONFIG_ONDEMAND_NO;
+
+                // we enable individual performance charts only when def_performance is not disabled
+                if(def_performance != CONFIG_ONDEMAND_NO) {
+                    ddo_io = global_do_io,
+                    ddo_ops = global_do_ops,
+                    ddo_mops = global_do_mops,
+                    ddo_iotime = global_do_iotime,
+                    ddo_qops = global_do_qops,
+                    ddo_util = global_do_util,
+                    ddo_backlog = global_do_backlog;
+                }
+
+                d->do_io      = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
+                d->do_ops     = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
+                d->do_mops    = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
+                d->do_iotime  = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
+                d->do_qops    = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
+                d->do_util    = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
+                d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
+
+                // def_space
+                if(d->mount_point) {
+                    // check the user configuration (this will also show our 'on demand' decision)
+                    def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
+
+                    int ddo_space = def_space,
+                        ddo_inodes = def_space;
+
+                    d->do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
+                    d->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
+                }
+                else {
+                    // don't show settings for this disk
+                    d->do_space = CONFIG_ONDEMAND_NO;
+                    d->do_inodes = CONFIG_ONDEMAND_NO;
+                }
+            }
+
+            d->configured = 1;
+        }
+
+        RRDSET *st;
+
+        // --------------------------------------------------------------------------
+        // Do performance metrics
+
+        if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
+            d->do_io = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
+            if(!st) {
+                st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+
+                rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            last_readsectors  = rrddim_set(st, "reads", readsectors);
+            last_writesectors = rrddim_set(st, "writes", writesectors);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
+            d->do_ops = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_ops", disk);
+            if(!st) {
+                st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            last_reads  = rrddim_set(st, "reads", reads);
+            last_writes = rrddim_set(st, "writes", writes);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
+            d->do_qops = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_qops", disk);
+            if(!st) {
+                st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next_usec(st, dt);
+
+            rrddim_set(st, "operations", queued_ios);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
+            d->do_backlog = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_backlog", disk);
+            if(!st) {
+                st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
+                st->isdetail = 1;
+
+                rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            rrddim_set(st, "backlog", backlog_ms);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
+            d->do_util = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_util", disk);
+            if(!st) {
+                st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
+                st->isdetail = 1;
+
+                rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            last_busy_ms = rrddim_set(st, "utilization", busy_ms);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
+            d->do_mops = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_mops", disk);
+            if(!st) {
+                st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            rrddim_set(st, "reads", mreads);
+            rrddim_set(st, "writes", mwrites);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
+            d->do_iotime = CONFIG_ONDEMAND_YES;
+
+            st = rrdset_find_bytype("disk_iotime", disk);
+            if(!st) {
+                st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next_usec(st, dt);
+
+            last_readms  = rrddim_set(st, "reads", readms);
+            last_writems = rrddim_set(st, "writes", writems);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+        // calculate differential charts
+        // only if this is not the first time we run
+
+        if(dt) {
+            if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
+                (d->do_ops    == CONFIG_ONDEMAND_YES || (d->do_ops    == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                st = rrdset_find_bytype("disk_await", disk);
+                if(!st) {
+                    st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next_usec(st, dt);
+
+                rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
+                rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
+                rrdset_done(st);
+            }
+
+            if( (d->do_io  == CONFIG_ONDEMAND_YES || (d->do_io  == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
+                (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                st = rrdset_find_bytype("disk_avgsz", disk);
+                if(!st) {
+                    st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next_usec(st, dt);
+
+                rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
+                rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
+                rrdset_done(st);
+            }
+
+            if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
+                (d->do_ops  == CONFIG_ONDEMAND_YES || (d->do_ops  == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
+                st = rrdset_find_bytype("disk_svctm", disk);
+                if(!st) {
+                    st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next_usec(st, dt);
+
+                rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
+                rrdset_done(st);
+            }
+        }
+
+        // --------------------------------------------------------------------------
+        // space metrics
+
+        if(d->mount_point && (d->do_space || d->do_inodes) ) {
+            // collect space metrics using statvfs
+
+            if (statvfs(d->mount_point, &buff_statvfs) < 0)
+                error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
+            else {
+                space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
+                space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
+                space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
+
+                inodes_avail = buff_statvfs.f_favail;
+                inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
+                inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
+
+                // verify we collected the metrics for the right disk.
+                // if not the mountpoint has changed.
+
+                if(stat(d->mount_point, &buff_stat) == -1)
+                    error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
+                else {
+                    if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
+
+                        // --------------------------------------------------------------------------
+
+                        if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
+                            st = rrdset_find_bytype("disk_space", disk);
+                            if(!st) {
+                                st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
+                                st->isdetail = 1;
+
+                                rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
+                                rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
+                                rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
+                            }
+                            else rrdset_next_usec(st, dt);
+
+                            rrddim_set(st, "avail", space_avail);
+                            rrddim_set(st, "used", space_used);
+                            rrddim_set(st, "reserved_for_root", space_avail_root);
+                            rrdset_done(st);
+                        }
+
+                        // --------------------------------------------------------------------------
+
+                        if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
+                            st = rrdset_find_bytype("disk_inodes", disk);
+                            if(!st) {
+                                st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
+                                st->isdetail = 1;
+
+                                rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                                rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
+                                rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+                            }
+                            else rrdset_next_usec(st, dt);
+
+                            rrddim_set(st, "avail", inodes_avail);
+                            rrddim_set(st, "used", inodes_used);
+                            rrddim_set(st, "reserved_for_root", inodes_avail_root);
+                            rrdset_done(st);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return 0;
 }
index 6f703434878eb7201a1d72889e2038401127ba63..fe0e9b1a57635a43bc1cd139a74e59f0e10b9ebf 100644 (file)
@@ -3,11 +3,11 @@
 #define MAX_INTERRUPT_NAME 50
 
 struct interrupt {
-       int used;
-       char *id;
-       char name[MAX_INTERRUPT_NAME + 1];
-       unsigned long long total;
-       unsigned long long value[];
+    int used;
+    char *id;
+    char name[MAX_INTERRUPT_NAME + 1];
+    unsigned long long total;
+    unsigned long long value[];
 };
 
 // since each interrupt is variable in size
@@ -18,157 +18,157 @@ struct interrupt {
 #define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
 
 static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
-       static struct interrupt *irrs = NULL;
-       static int allocated = 0;
+    static struct interrupt *irrs = NULL;
+    static int allocated = 0;
 
-       if(lines < allocated) return irrs;
-       else {
-               irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
-               allocated = lines;
-       }
+    if(lines < allocated) return irrs;
+    else {
+        irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
+        allocated = lines;
+    }
 
-       return irrs;
+    return irrs;
 }
 
 int do_proc_interrupts(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int cpus = -1, do_per_core = -1;
-       struct interrupt *irrs = NULL;
-
-       if(dt) {};
-
-       if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
-               ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words = procfile_linewords(ff, 0), w;
-
-       if(!lines) {
-               error("Cannot read /proc/interrupts, zero lines reported.");
-               return 1;
-       }
-
-       // find how many CPUs are there
-       if(cpus == -1) {
-               cpus = 0;
-               for(w = 0; w < words ; w++) {
-                       if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
-                               cpus++;
-               }
-       }
-
-       if(!cpus) {
-               error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
-               return 1;
-       }
-
-       // allocate the size we need;
-       irrs = get_interrupts_array(lines, cpus);
-       irrs[0].used = 0;
-
-       // loop through all lines
-       for(l = 1; l < lines ;l++) {
-               struct interrupt *irr = irrindex(irrs, l, cpus);
-               irr->used = 0;
-               irr->total = 0;
-
-               words = procfile_linewords(ff, l);
-               if(!words) continue;
-
-               irr->id = procfile_lineword(ff, l, 0);
-               if(!irr->id || !irr->id[0]) continue;
-
-               int idlen = strlen(irr->id);
-               if(irr->id[idlen - 1] == ':')
-                       irr->id[idlen - 1] = '\0';
-
-               int c;
-               for(c = 0; c < cpus ;c++) {
-                       if((c + 1) < (int)words)
-                               irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
-                       else
-                               irr->value[c] = 0;
-
-                       irr->total += irr->value[c];
-               }
-
-               if(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words) {
-                       strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
-                       int nlen = strlen(irr->name);
-                       if(nlen < (MAX_INTERRUPT_NAME-1)) {
-                               irr->name[nlen] = '_';
-                               strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen);
-                       }
-               }
-               else {
-                       strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
-               }
-
-               irr->used = 1;
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       st = rrdset_find_bytype("system", "interrupts");
-       if(!st) {
-               st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
-
-               for(l = 0; l < lines ;l++) {
-                       struct interrupt *irr = irrindex(irrs, l, cpus);
-                       if(!irr->used) continue;
-                       rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
-               }
-       }
-       else rrdset_next(st);
-
-       for(l = 0; l < lines ;l++) {
-               struct interrupt *irr = irrindex(irrs, l, cpus);
-               if(!irr->used) continue;
-               rrddim_set(st, irr->id, irr->total);
-       }
-       rrdset_done(st);
-
-       if(do_per_core) {
-               int c;
-
-               for(c = 0; c < cpus ; c++) {
-                       char id[256+1];
-                       snprintfz(id, 256, "cpu%d_interrupts", c);
-
-                       st = rrdset_find_bytype("cpu", id);
-                       if(!st) {
-                               char name[256+1], title[256+1];
-                               snprintfz(name, 256, "cpu%d_interrupts", c);
-                               snprintfz(title, 256, "CPU%d Interrupts", c);
-                               st = rrdset_create("cpu", id, name, "interrupts", "cpu.interrupts", title, "interrupts/s", 2000 + c, update_every, RRDSET_TYPE_STACKED);
-
-                               for(l = 0; l < lines ;l++) {
-                                       struct interrupt *irr = irrindex(irrs, l, cpus);
-                                       if(!irr->used) continue;
-                                       rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                       }
-                       else rrdset_next(st);
-
-                       for(l = 0; l < lines ;l++) {
-                               struct interrupt *irr = irrindex(irrs, l, cpus);
-                               if(!irr->used) continue;
-                               rrddim_set(st, irr->id, irr->value[c]);
-                       }
-                       rrdset_done(st);
-               }
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static int cpus = -1, do_per_core = -1;
+    struct interrupt *irrs = NULL;
+
+    if(dt) {};
+
+    if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
+        ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words = procfile_linewords(ff, 0), w;
+
+    if(!lines) {
+        error("Cannot read /proc/interrupts, zero lines reported.");
+        return 1;
+    }
+
+    // find how many CPUs are there
+    if(cpus == -1) {
+        cpus = 0;
+        for(w = 0; w < words ; w++) {
+            if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
+                cpus++;
+        }
+    }
+
+    if(!cpus) {
+        error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
+        return 1;
+    }
+
+    // allocate the size we need;
+    irrs = get_interrupts_array(lines, cpus);
+    irrs[0].used = 0;
+
+    // loop through all lines
+    for(l = 1; l < lines ;l++) {
+        struct interrupt *irr = irrindex(irrs, l, cpus);
+        irr->used = 0;
+        irr->total = 0;
+
+        words = procfile_linewords(ff, l);
+        if(!words) continue;
+
+        irr->id = procfile_lineword(ff, l, 0);
+        if(!irr->id || !irr->id[0]) continue;
+
+        int idlen = strlen(irr->id);
+        if(irr->id[idlen - 1] == ':')
+            irr->id[idlen - 1] = '\0';
+
+        int c;
+        for(c = 0; c < cpus ;c++) {
+            if((c + 1) < (int)words)
+                irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
+            else
+                irr->value[c] = 0;
+
+            irr->total += irr->value[c];
+        }
+
+        if(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words) {
+            strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
+            int nlen = strlen(irr->name);
+            if(nlen < (MAX_INTERRUPT_NAME-1)) {
+                irr->name[nlen] = '_';
+                strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen);
+            }
+        }
+        else {
+            strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
+        }
+
+        irr->used = 1;
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    st = rrdset_find_bytype("system", "interrupts");
+    if(!st) {
+        st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
+
+        for(l = 0; l < lines ;l++) {
+            struct interrupt *irr = irrindex(irrs, l, cpus);
+            if(!irr->used) continue;
+            rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+        }
+    }
+    else rrdset_next(st);
+
+    for(l = 0; l < lines ;l++) {
+        struct interrupt *irr = irrindex(irrs, l, cpus);
+        if(!irr->used) continue;
+        rrddim_set(st, irr->id, irr->total);
+    }
+    rrdset_done(st);
+
+    if(do_per_core) {
+        int c;
+
+        for(c = 0; c < cpus ; c++) {
+            char id[256+1];
+            snprintfz(id, 256, "cpu%d_interrupts", c);
+
+            st = rrdset_find_bytype("cpu", id);
+            if(!st) {
+                char name[256+1], title[256+1];
+                snprintfz(name, 256, "cpu%d_interrupts", c);
+                snprintfz(title, 256, "CPU%d Interrupts", c);
+                st = rrdset_create("cpu", id, name, "interrupts", "cpu.interrupts", title, "interrupts/s", 2000 + c, update_every, RRDSET_TYPE_STACKED);
+
+                for(l = 0; l < lines ;l++) {
+                    struct interrupt *irr = irrindex(irrs, l, cpus);
+                    if(!irr->used) continue;
+                    rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+                }
+            }
+            else rrdset_next(st);
+
+            for(l = 0; l < lines ;l++) {
+                struct interrupt *irr = irrindex(irrs, l, cpus);
+                if(!irr->used) continue;
+                rrddim_set(st, irr->id, irr->value[c]);
+            }
+            rrdset_done(st);
+        }
+    }
+
+    return 0;
 }
index ec04ec250f5ccfa2798751ee0310617d60d97fa3..44ea70191ee43a2244d1155d3f5d44967637cc5e 100644 (file)
@@ -4,77 +4,77 @@
 #define MIN_LOADAVG_UPDATE_EVERY 5
 
 int do_proc_loadavg(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int do_loadavg = -1, do_all_processes = -1;
+    static procfile *ff = NULL;
+    static int do_loadavg = -1, do_all_processes = -1;
 
-       if(dt) {};
+    if(dt) {};
 
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
-               ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
+        ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
-       if(do_loadavg == -1)            do_loadavg                      = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
-       if(do_all_processes == -1)      do_all_processes        = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
+    if(do_loadavg == -1)        do_loadavg          = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
+    if(do_all_processes == -1)  do_all_processes    = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
 
-       if(procfile_lines(ff) < 1) {
-               error("/proc/loadavg has no lines.");
-               return 1;
-       }
-       if(procfile_linewords(ff, 0) < 6) {
-               error("/proc/loadavg has less than 6 words in it.");
-               return 1;
-       }
+    if(procfile_lines(ff) < 1) {
+        error("/proc/loadavg has no lines.");
+        return 1;
+    }
+    if(procfile_linewords(ff, 0) < 6) {
+        error("/proc/loadavg has less than 6 words in it.");
+        return 1;
+    }
 
-       double load1 = strtod(procfile_lineword(ff, 0, 0), NULL);
-       double load5 = strtod(procfile_lineword(ff, 0, 1), NULL);
-       double load15 = strtod(procfile_lineword(ff, 0, 2), NULL);
+    double load1 = strtod(procfile_lineword(ff, 0, 0), NULL);
+    double load5 = strtod(procfile_lineword(ff, 0, 1), NULL);
+    double load15 = strtod(procfile_lineword(ff, 0, 2), NULL);
 
-       //unsigned long long running_processes  = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
-       unsigned long long active_processes             = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
-       //unsigned long long next_pid                           = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
+    //unsigned long long running_processes  = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
+    unsigned long long active_processes     = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
+    //unsigned long long next_pid               = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
 
 
-       RRDSET *st;
+    RRDSET *st;
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_loadavg) {
-               st = rrdset_find_byname("system.load");
-               if(!st) {
-                       st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)?MIN_LOADAVG_UPDATE_EVERY:update_every, RRDSET_TYPE_LINE);
+    if(do_loadavg) {
+        st = rrdset_find_byname("system.load");
+        if(!st) {
+            st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)?MIN_LOADAVG_UPDATE_EVERY:update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "load1", load1 * 1000);
-               rrddim_set(st, "load5", load5 * 1000);
-               rrddim_set(st, "load15", load15 * 1000);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "load1", load1 * 1000);
+        rrddim_set(st, "load5", load5 * 1000);
+        rrddim_set(st, "load15", load15 * 1000);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_all_processes) {
-               st = rrdset_find_byname("system.active_processes");
-               if(!st) {
-                       st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
+    if(do_all_processes) {
+        st = rrdset_find_byname("system.active_processes");
+        if(!st) {
+            st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "active", active_processes);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "active", active_processes);
+        rrdset_done(st);
+    }
 
-       return 0;
+    return 0;
 }
index fc22ddf005a9aa95a9167317fae50212e708db2b..4295cd6daea3a085442c57f71362bb81de62a239 100644 (file)
 #define MAX_PROC_MEMINFO_NAME 1024
 
 int do_proc_meminfo(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-
-       static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1;
-
-       if(do_ram == -1)                do_ram                  = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
-       if(do_swap == -1)               do_swap                 = config_get_boolean("plugin:proc:/proc/meminfo", "system swap", 1);
-       if(do_hwcorrupt == -1)  do_hwcorrupt    = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_committed == -1)  do_committed    = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
-       if(do_writeback == -1)  do_writeback    = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
-       if(do_kernel == -1)             do_kernel               = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
-       if(do_slab == -1)               do_slab                 = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1);
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
-               ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       int hwcorrupted = 0;
-
-       unsigned long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapCached = 0,
-               Active = 0, Inactive = 0, ActiveAnon = 0, InactiveAnon = 0, ActiveFile = 0, InactiveFile = 0,
-               Unevictable = 0, Mlocked = 0, SwapTotal = 0, SwapFree = 0, Dirty = 0, Writeback = 0, AnonPages = 0,
-               Mapped = 0, Shmem = 0, Slab = 0, SReclaimable = 0, SUnreclaim = 0, KernelStack = 0, PageTables = 0,
-               NFS_Unstable = 0, Bounce = 0, WritebackTmp = 0, CommitLimit = 0, Committed_AS = 0,
-               VmallocTotal = 0, VmallocUsed = 0, VmallocChunk = 0,
-               AnonHugePages = 0, HugePages_Total = 0, HugePages_Free = 0, HugePages_Rsvd = 0, HugePages_Surp = 0, Hugepagesize = 0,
-               DirectMap4k = 0, DirectMap2M = 0, HardwareCorrupted = 0;
-
-       for(l = 0; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(words < 2) continue;
-
-               char *name = procfile_lineword(ff, l, 0);
-               unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-
-                    if(!MemTotal && strcmp(name, "MemTotal") == 0) MemTotal = value;
-               else if(!MemFree && strcmp(name, "MemFree") == 0) MemFree = value;
-               else if(!Buffers && strcmp(name, "Buffers") == 0) Buffers = value;
-               else if(!Cached && strcmp(name, "Cached") == 0) Cached = value;
-               else if(!SwapCached && strcmp(name, "SwapCached") == 0) SwapCached = value;
-               else if(!Active && strcmp(name, "Active") == 0) Active = value;
-               else if(!Inactive && strcmp(name, "Inactive") == 0) Inactive = value;
-               else if(!ActiveAnon && strcmp(name, "ActiveAnon") == 0) ActiveAnon = value;
-               else if(!InactiveAnon && strcmp(name, "InactiveAnon") == 0) InactiveAnon = value;
-               else if(!ActiveFile && strcmp(name, "ActiveFile") == 0) ActiveFile = value;
-               else if(!InactiveFile && strcmp(name, "InactiveFile") == 0) InactiveFile = value;
-               else if(!Unevictable && strcmp(name, "Unevictable") == 0) Unevictable = value;
-               else if(!Mlocked && strcmp(name, "Mlocked") == 0) Mlocked = value;
-               else if(!SwapTotal && strcmp(name, "SwapTotal") == 0) SwapTotal = value;
-               else if(!SwapFree && strcmp(name, "SwapFree") == 0) SwapFree = value;
-               else if(!Dirty && strcmp(name, "Dirty") == 0) Dirty = value;
-               else if(!Writeback && strcmp(name, "Writeback") == 0) Writeback = value;
-               else if(!AnonPages && strcmp(name, "AnonPages") == 0) AnonPages = value;
-               else if(!Mapped && strcmp(name, "Mapped") == 0) Mapped = value;
-               else if(!Shmem && strcmp(name, "Shmem") == 0) Shmem = value;
-               else if(!Slab && strcmp(name, "Slab") == 0) Slab = value;
-               else if(!SReclaimable && strcmp(name, "SReclaimable") == 0) SReclaimable = value;
-               else if(!SUnreclaim && strcmp(name, "SUnreclaim") == 0) SUnreclaim = value;
-               else if(!KernelStack && strcmp(name, "KernelStack") == 0) KernelStack = value;
-               else if(!PageTables && strcmp(name, "PageTables") == 0) PageTables = value;
-               else if(!NFS_Unstable && strcmp(name, "NFS_Unstable") == 0) NFS_Unstable = value;
-               else if(!Bounce && strcmp(name, "Bounce") == 0) Bounce = value;
-               else if(!WritebackTmp && strcmp(name, "WritebackTmp") == 0) WritebackTmp = value;
-               else if(!CommitLimit && strcmp(name, "CommitLimit") == 0) CommitLimit = value;
-               else if(!Committed_AS && strcmp(name, "Committed_AS") == 0) Committed_AS = value;
-               else if(!VmallocTotal && strcmp(name, "VmallocTotal") == 0) VmallocTotal = value;
-               else if(!VmallocUsed && strcmp(name, "VmallocUsed") == 0) VmallocUsed = value;
-               else if(!VmallocChunk && strcmp(name, "VmallocChunk") == 0) VmallocChunk = value;
-               else if(!HardwareCorrupted && strcmp(name, "HardwareCorrupted") == 0) { HardwareCorrupted = value; hwcorrupted = 1; }
-               else if(!AnonHugePages && strcmp(name, "AnonHugePages") == 0) AnonHugePages = value;
-               else if(!HugePages_Total && strcmp(name, "HugePages_Total") == 0) HugePages_Total = value;
-               else if(!HugePages_Free && strcmp(name, "HugePages_Free") == 0) HugePages_Free = value;
-               else if(!HugePages_Rsvd && strcmp(name, "HugePages_Rsvd") == 0) HugePages_Rsvd = value;
-               else if(!HugePages_Surp && strcmp(name, "HugePages_Surp") == 0) HugePages_Surp = value;
-               else if(!Hugepagesize && strcmp(name, "Hugepagesize") == 0) Hugepagesize = value;
-               else if(!DirectMap4k && strcmp(name, "DirectMap4k") == 0) DirectMap4k = value;
-               else if(!DirectMap2M && strcmp(name, "DirectMap2M") == 0) DirectMap2M = value;
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       // http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux
-       unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
-
-       if(do_ram) {
-               st = rrdset_find("system.ram");
-               if(!st) {
-                       st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
-
-                       rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "used",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "cached",  NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "free",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "used", MemUsed);
-               rrddim_set(st, "free", MemFree);
-               rrddim_set(st, "cached", Cached);
-               rrddim_set(st, "buffers", Buffers);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       unsigned long long SwapUsed = SwapTotal - SwapFree;
-
-       if(do_swap) {
-               st = rrdset_find("system.swap");
-               if(!st) {
-                       st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "free",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "used",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "used", SwapUsed);
-               rrddim_set(st, "free", SwapFree);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(hwcorrupted && do_hwcorrupt && HardwareCorrupted > 0) {
-               do_hwcorrupt = CONFIG_ONDEMAND_YES;
-
-               st = rrdset_find("mem.hwcorrupt");
-               if(!st) {
-                       st = rrdset_create("mem", "hwcorrupt", NULL, "errors", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "HardwareCorrupted", HardwareCorrupted);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_committed) {
-               st = rrdset_find("mem.committed");
-               if(!st) {
-                       st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "Committed_AS", Committed_AS);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_writeback) {
-               st = rrdset_find("mem.writeback");
-               if(!st) {
-                       st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "Dirty", Dirty);
-               rrddim_set(st, "Writeback", Writeback);
-               rrddim_set(st, "FuseWriteback", WritebackTmp);
-               rrddim_set(st, "NfsWriteback", NFS_Unstable);
-               rrddim_set(st, "Bounce", Bounce);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_kernel) {
-               st = rrdset_find("mem.kernel");
-               if(!st) {
-                       st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "KernelStack", KernelStack);
-               rrddim_set(st, "Slab", Slab);
-               rrddim_set(st, "PageTables", PageTables);
-               rrddim_set(st, "VmallocUsed", VmallocUsed);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_slab) {
-               st = rrdset_find("mem.slab");
-               if(!st) {
-                       st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "reclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "reclaimable", SReclaimable);
-               rrddim_set(st, "unreclaimable", SUnreclaim);
-               rrdset_done(st);
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+
+    static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1;
+
+    if(do_ram == -1)        do_ram          = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
+    if(do_swap == -1)       do_swap         = config_get_boolean("plugin:proc:/proc/meminfo", "system swap", 1);
+    if(do_hwcorrupt == -1)  do_hwcorrupt    = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_committed == -1)  do_committed    = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
+    if(do_writeback == -1)  do_writeback    = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
+    if(do_kernel == -1)     do_kernel       = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
+    if(do_slab == -1)       do_slab         = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1);
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
+        ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    int hwcorrupted = 0;
+
+    unsigned long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapCached = 0,
+        Active = 0, Inactive = 0, ActiveAnon = 0, InactiveAnon = 0, ActiveFile = 0, InactiveFile = 0,
+        Unevictable = 0, Mlocked = 0, SwapTotal = 0, SwapFree = 0, Dirty = 0, Writeback = 0, AnonPages = 0,
+        Mapped = 0, Shmem = 0, Slab = 0, SReclaimable = 0, SUnreclaim = 0, KernelStack = 0, PageTables = 0,
+        NFS_Unstable = 0, Bounce = 0, WritebackTmp = 0, CommitLimit = 0, Committed_AS = 0,
+        VmallocTotal = 0, VmallocUsed = 0, VmallocChunk = 0,
+        AnonHugePages = 0, HugePages_Total = 0, HugePages_Free = 0, HugePages_Rsvd = 0, HugePages_Surp = 0, Hugepagesize = 0,
+        DirectMap4k = 0, DirectMap2M = 0, HardwareCorrupted = 0;
+
+    for(l = 0; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(words < 2) continue;
+
+        char *name = procfile_lineword(ff, l, 0);
+        unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+
+             if(!MemTotal && strcmp(name, "MemTotal") == 0) MemTotal = value;
+        else if(!MemFree && strcmp(name, "MemFree") == 0) MemFree = value;
+        else if(!Buffers && strcmp(name, "Buffers") == 0) Buffers = value;
+        else if(!Cached && strcmp(name, "Cached") == 0) Cached = value;
+        else if(!SwapCached && strcmp(name, "SwapCached") == 0) SwapCached = value;
+        else if(!Active && strcmp(name, "Active") == 0) Active = value;
+        else if(!Inactive && strcmp(name, "Inactive") == 0) Inactive = value;
+        else if(!ActiveAnon && strcmp(name, "ActiveAnon") == 0) ActiveAnon = value;
+        else if(!InactiveAnon && strcmp(name, "InactiveAnon") == 0) InactiveAnon = value;
+        else if(!ActiveFile && strcmp(name, "ActiveFile") == 0) ActiveFile = value;
+        else if(!InactiveFile && strcmp(name, "InactiveFile") == 0) InactiveFile = value;
+        else if(!Unevictable && strcmp(name, "Unevictable") == 0) Unevictable = value;
+        else if(!Mlocked && strcmp(name, "Mlocked") == 0) Mlocked = value;
+        else if(!SwapTotal && strcmp(name, "SwapTotal") == 0) SwapTotal = value;
+        else if(!SwapFree && strcmp(name, "SwapFree") == 0) SwapFree = value;
+        else if(!Dirty && strcmp(name, "Dirty") == 0) Dirty = value;
+        else if(!Writeback && strcmp(name, "Writeback") == 0) Writeback = value;
+        else if(!AnonPages && strcmp(name, "AnonPages") == 0) AnonPages = value;
+        else if(!Mapped && strcmp(name, "Mapped") == 0) Mapped = value;
+        else if(!Shmem && strcmp(name, "Shmem") == 0) Shmem = value;
+        else if(!Slab && strcmp(name, "Slab") == 0) Slab = value;
+        else if(!SReclaimable && strcmp(name, "SReclaimable") == 0) SReclaimable = value;
+        else if(!SUnreclaim && strcmp(name, "SUnreclaim") == 0) SUnreclaim = value;
+        else if(!KernelStack && strcmp(name, "KernelStack") == 0) KernelStack = value;
+        else if(!PageTables && strcmp(name, "PageTables") == 0) PageTables = value;
+        else if(!NFS_Unstable && strcmp(name, "NFS_Unstable") == 0) NFS_Unstable = value;
+        else if(!Bounce && strcmp(name, "Bounce") == 0) Bounce = value;
+        else if(!WritebackTmp && strcmp(name, "WritebackTmp") == 0) WritebackTmp = value;
+        else if(!CommitLimit && strcmp(name, "CommitLimit") == 0) CommitLimit = value;
+        else if(!Committed_AS && strcmp(name, "Committed_AS") == 0) Committed_AS = value;
+        else if(!VmallocTotal && strcmp(name, "VmallocTotal") == 0) VmallocTotal = value;
+        else if(!VmallocUsed && strcmp(name, "VmallocUsed") == 0) VmallocUsed = value;
+        else if(!VmallocChunk && strcmp(name, "VmallocChunk") == 0) VmallocChunk = value;
+        else if(!HardwareCorrupted && strcmp(name, "HardwareCorrupted") == 0) { HardwareCorrupted = value; hwcorrupted = 1; }
+        else if(!AnonHugePages && strcmp(name, "AnonHugePages") == 0) AnonHugePages = value;
+        else if(!HugePages_Total && strcmp(name, "HugePages_Total") == 0) HugePages_Total = value;
+        else if(!HugePages_Free && strcmp(name, "HugePages_Free") == 0) HugePages_Free = value;
+        else if(!HugePages_Rsvd && strcmp(name, "HugePages_Rsvd") == 0) HugePages_Rsvd = value;
+        else if(!HugePages_Surp && strcmp(name, "HugePages_Surp") == 0) HugePages_Surp = value;
+        else if(!Hugepagesize && strcmp(name, "Hugepagesize") == 0) Hugepagesize = value;
+        else if(!DirectMap4k && strcmp(name, "DirectMap4k") == 0) DirectMap4k = value;
+        else if(!DirectMap2M && strcmp(name, "DirectMap2M") == 0) DirectMap2M = value;
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    // http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux
+    unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
+
+    if(do_ram) {
+        st = rrdset_find("system.ram");
+        if(!st) {
+            st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "used",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "cached",  NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "free",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "used", MemUsed);
+        rrddim_set(st, "free", MemFree);
+        rrddim_set(st, "cached", Cached);
+        rrddim_set(st, "buffers", Buffers);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    unsigned long long SwapUsed = SwapTotal - SwapFree;
+
+    if(do_swap) {
+        st = rrdset_find("system.swap");
+        if(!st) {
+            st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
+            st->isdetail = 1;
+
+            rrddim_add(st, "free",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "used",    NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "used", SwapUsed);
+        rrddim_set(st, "free", SwapFree);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(hwcorrupted && do_hwcorrupt && HardwareCorrupted > 0) {
+        do_hwcorrupt = CONFIG_ONDEMAND_YES;
+
+        st = rrdset_find("mem.hwcorrupt");
+        if(!st) {
+            st = rrdset_create("mem", "hwcorrupt", NULL, "errors", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "HardwareCorrupted", HardwareCorrupted);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_committed) {
+        st = rrdset_find("mem.committed");
+        if(!st) {
+            st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
+            st->isdetail = 1;
+
+            rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "Committed_AS", Committed_AS);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_writeback) {
+        st = rrdset_find("mem.writeback");
+        if(!st) {
+            st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "Dirty", Dirty);
+        rrddim_set(st, "Writeback", Writeback);
+        rrddim_set(st, "FuseWriteback", WritebackTmp);
+        rrddim_set(st, "NfsWriteback", NFS_Unstable);
+        rrddim_set(st, "Bounce", Bounce);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_kernel) {
+        st = rrdset_find("mem.kernel");
+        if(!st) {
+            st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
+            st->isdetail = 1;
+
+            rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "KernelStack", KernelStack);
+        rrddim_set(st, "Slab", Slab);
+        rrddim_set(st, "PageTables", PageTables);
+        rrddim_set(st, "VmallocUsed", VmallocUsed);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_slab) {
+        st = rrdset_find("mem.slab");
+        if(!st) {
+            st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
+            st->isdetail = 1;
+
+            rrddim_add(st, "reclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "reclaimable", SReclaimable);
+        rrddim_set(st, "unreclaimable", SUnreclaim);
+        rrdset_done(st);
+    }
+
+    return 0;
 }
 
index 2c02b0697d3f836a38b4bd3ac62c6a4bdde3d858..53981182a4b22ad5158534e4f0db9cf9596fe276 100644 (file)
 #include "common.h"
 
 int do_proc_net_dev(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int enable_new_interfaces = -1, enable_ifb_interfaces = -1;
-       static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
-       if(enable_ifb_interfaces == -1) enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
-
-       if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_packets == -1)    do_packets              = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_errors == -1)             do_errors               = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_drops == -1)              do_drops                = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_fifo == -1)               do_fifo                 = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_compressed == -1) do_compressed   = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_events == -1)             do_events               = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       char *iface;
-       unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
-       unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
-
-       for(l = 2; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(words < 17) continue;
-
-               iface           = procfile_lineword(ff, l, 0);
-
-               rbytes          = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-               rpackets        = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-               rerrors         = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-               rdrops          = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-               rfifo           = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-               rframe          = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-               rcompressed     = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-               rmulticast      = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-
-               tbytes          = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-               tpackets        = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-               terrors         = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-               tdrops          = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-               tfifo           = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-               tcollisions     = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-               tcarrier        = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
-               tcompressed     = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
-
-               int ddo_bandwidth = do_bandwidth, ddo_packets = do_packets, ddo_errors = do_errors, ddo_drops = do_drops, ddo_fifo = do_fifo, ddo_compressed = do_compressed, ddo_events = do_events;
-
-               int default_enable = enable_new_interfaces;
-
-               // prevent unused interfaces from creating charts
-               if(strcmp(iface, "lo") == 0)
-                       default_enable = 0;
-               else {
-                       int len = strlen(iface);
-                       if(len >= 4 && strcmp(&iface[len-4], "-ifb") == 0)
-                               default_enable = enable_ifb_interfaces;
-               }
-
-               // check if the user wants it
-               {
-                       char var_name[512 + 1];
-                       snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", iface);
-                       default_enable = config_get_boolean_ondemand(var_name, "enabled", default_enable);
-                       if(default_enable == CONFIG_ONDEMAND_NO) continue;
-                       if(default_enable == CONFIG_ONDEMAND_ONDEMAND && !rbytes && !tbytes) continue;
-
-                       ddo_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", ddo_bandwidth);
-                       ddo_packets = config_get_boolean_ondemand(var_name, "packets", ddo_packets);
-                       ddo_errors = config_get_boolean_ondemand(var_name, "errors", ddo_errors);
-                       ddo_drops = config_get_boolean_ondemand(var_name, "drops", ddo_drops);
-                       ddo_fifo = config_get_boolean_ondemand(var_name, "fifo", ddo_fifo);
-                       ddo_compressed = config_get_boolean_ondemand(var_name, "compressed", ddo_compressed);
-                       ddo_events = config_get_boolean_ondemand(var_name, "events", ddo_events);
-
-                       if(ddo_bandwidth == CONFIG_ONDEMAND_ONDEMAND && rbytes == 0 && tbytes == 0) ddo_bandwidth = 0;
-                       if(ddo_errors == CONFIG_ONDEMAND_ONDEMAND && rerrors == 0 && terrors == 0) ddo_errors = 0;
-                       if(ddo_drops == CONFIG_ONDEMAND_ONDEMAND && rdrops == 0 && tdrops == 0) ddo_drops = 0;
-                       if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND && rfifo == 0 && tfifo == 0) ddo_fifo = 0;
-                       if(ddo_compressed == CONFIG_ONDEMAND_ONDEMAND && rcompressed == 0 && tcompressed == 0) ddo_compressed = 0;
-                       if(ddo_events == CONFIG_ONDEMAND_ONDEMAND && rframe == 0 && tcollisions == 0 && tcarrier == 0) ddo_events = 0;
-
-                       // for absolute values, we need to switch the setting to 'yes'
-                       // to allow it refresh from now on
-                       // if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "fifo", "yes");
-               }
-
-               RRDSET *st;
-
-               // --------------------------------------------------------------------
-
-               if(ddo_bandwidth) {
-                       st = rrdset_find_bytype("net", iface);
-                       if(!st) {
-                               st = rrdset_create("net", iface, NULL, iface, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
-
-                               rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "received", rbytes);
-                       rrddim_set(st, "sent", tbytes);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_packets) {
-                       st = rrdset_find_bytype("net_packets", iface);
-                       if(!st) {
-                               st = rrdset_create("net_packets", iface, NULL, iface, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "received", rpackets);
-                       rrddim_set(st, "sent", tpackets);
-                       rrddim_set(st, "multicast", rmulticast);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_errors) {
-                       st = rrdset_find_bytype("net_errors", iface);
-                       if(!st) {
-                               st = rrdset_create("net_errors", iface, NULL, iface, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "inbound", rerrors);
-                       rrddim_set(st, "outbound", terrors);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_drops) {
-                       st = rrdset_find_bytype("net_drops", iface);
-                       if(!st) {
-                               st = rrdset_create("net_drops", iface, NULL, iface, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "inbound", rdrops);
-                       rrddim_set(st, "outbound", tdrops);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_fifo) {
-                       st = rrdset_find_bytype("net_fifo", iface);
-                       if(!st) {
-                               st = rrdset_create("net_fifo", iface, NULL, iface, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "receive", rfifo);
-                       rrddim_set(st, "transmit", tfifo);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_compressed) {
-                       st = rrdset_find_bytype("net_compressed", iface);
-                       if(!st) {
-                               st = rrdset_create("net_compressed", iface, NULL, iface, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "received", rcompressed);
-                       rrddim_set(st, "sent", tcompressed);
-                       rrdset_done(st);
-               }
-
-               // --------------------------------------------------------------------
-
-               if(ddo_events) {
-                       st = rrdset_find_bytype("net_events", iface);
-                       if(!st) {
-                               st = rrdset_create("net_events", iface, NULL, iface, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
-                               st->isdetail = 1;
-
-                               rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "frames", rframe);
-                       rrddim_set(st, "collisions", tcollisions);
-                       rrddim_set(st, "carrier", tcarrier);
-                       rrdset_done(st);
-               }
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static int enable_new_interfaces = -1, enable_ifb_interfaces = -1;
+    static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
+    if(enable_ifb_interfaces == -1) enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
+
+    if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_packets == -1)    do_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_errors == -1)     do_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_drops == -1)      do_drops        = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_fifo == -1)       do_fifo         = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_compressed == -1) do_compressed   = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_events == -1)     do_events       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    char *iface;
+    unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
+    unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
+
+    for(l = 2; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(words < 17) continue;
+
+        iface       = procfile_lineword(ff, l, 0);
+
+        rbytes      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        rpackets    = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+        rerrors     = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+        rdrops      = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+        rfifo       = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+        rframe      = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+        rcompressed = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+        rmulticast  = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+
+        tbytes      = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+        tpackets    = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+        terrors     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+        tdrops      = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+        tfifo       = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
+        tcollisions = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
+        tcarrier    = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
+        tcompressed = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
+
+        int ddo_bandwidth = do_bandwidth, ddo_packets = do_packets, ddo_errors = do_errors, ddo_drops = do_drops, ddo_fifo = do_fifo, ddo_compressed = do_compressed, ddo_events = do_events;
+
+        int default_enable = enable_new_interfaces;
+
+        // prevent unused interfaces from creating charts
+        if(strcmp(iface, "lo") == 0)
+            default_enable = 0;
+        else {
+            int len = strlen(iface);
+            if(len >= 4 && strcmp(&iface[len-4], "-ifb") == 0)
+                default_enable = enable_ifb_interfaces;
+        }
+
+        // check if the user wants it
+        {
+            char var_name[512 + 1];
+            snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", iface);
+            default_enable = config_get_boolean_ondemand(var_name, "enabled", default_enable);
+            if(default_enable == CONFIG_ONDEMAND_NO) continue;
+            if(default_enable == CONFIG_ONDEMAND_ONDEMAND && !rbytes && !tbytes) continue;
+
+            ddo_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", ddo_bandwidth);
+            ddo_packets = config_get_boolean_ondemand(var_name, "packets", ddo_packets);
+            ddo_errors = config_get_boolean_ondemand(var_name, "errors", ddo_errors);
+            ddo_drops = config_get_boolean_ondemand(var_name, "drops", ddo_drops);
+            ddo_fifo = config_get_boolean_ondemand(var_name, "fifo", ddo_fifo);
+            ddo_compressed = config_get_boolean_ondemand(var_name, "compressed", ddo_compressed);
+            ddo_events = config_get_boolean_ondemand(var_name, "events", ddo_events);
+
+            if(ddo_bandwidth == CONFIG_ONDEMAND_ONDEMAND && rbytes == 0 && tbytes == 0) ddo_bandwidth = 0;
+            if(ddo_errors == CONFIG_ONDEMAND_ONDEMAND && rerrors == 0 && terrors == 0) ddo_errors = 0;
+            if(ddo_drops == CONFIG_ONDEMAND_ONDEMAND && rdrops == 0 && tdrops == 0) ddo_drops = 0;
+            if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND && rfifo == 0 && tfifo == 0) ddo_fifo = 0;
+            if(ddo_compressed == CONFIG_ONDEMAND_ONDEMAND && rcompressed == 0 && tcompressed == 0) ddo_compressed = 0;
+            if(ddo_events == CONFIG_ONDEMAND_ONDEMAND && rframe == 0 && tcollisions == 0 && tcarrier == 0) ddo_events = 0;
+
+            // for absolute values, we need to switch the setting to 'yes'
+            // to allow it refresh from now on
+            // if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "fifo", "yes");
+        }
+
+        RRDSET *st;
+
+        // --------------------------------------------------------------------
+
+        if(ddo_bandwidth) {
+            st = rrdset_find_bytype("net", iface);
+            if(!st) {
+                st = rrdset_create("net", iface, NULL, iface, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+
+                rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "received", rbytes);
+            rrddim_set(st, "sent", tbytes);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_packets) {
+            st = rrdset_find_bytype("net_packets", iface);
+            if(!st) {
+                st = rrdset_create("net_packets", iface, NULL, iface, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "received", rpackets);
+            rrddim_set(st, "sent", tpackets);
+            rrddim_set(st, "multicast", rmulticast);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_errors) {
+            st = rrdset_find_bytype("net_errors", iface);
+            if(!st) {
+                st = rrdset_create("net_errors", iface, NULL, iface, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "inbound", rerrors);
+            rrddim_set(st, "outbound", terrors);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_drops) {
+            st = rrdset_find_bytype("net_drops", iface);
+            if(!st) {
+                st = rrdset_create("net_drops", iface, NULL, iface, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "inbound", rdrops);
+            rrddim_set(st, "outbound", tdrops);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_fifo) {
+            st = rrdset_find_bytype("net_fifo", iface);
+            if(!st) {
+                st = rrdset_create("net_fifo", iface, NULL, iface, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "receive", rfifo);
+            rrddim_set(st, "transmit", tfifo);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_compressed) {
+            st = rrdset_find_bytype("net_compressed", iface);
+            if(!st) {
+                st = rrdset_create("net_compressed", iface, NULL, iface, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "received", rcompressed);
+            rrddim_set(st, "sent", tcompressed);
+            rrdset_done(st);
+        }
+
+        // --------------------------------------------------------------------
+
+        if(ddo_events) {
+            st = rrdset_find_bytype("net_events", iface);
+            if(!st) {
+                st = rrdset_create("net_events", iface, NULL, iface, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "frames", rframe);
+            rrddim_set(st, "collisions", tcollisions);
+            rrddim_set(st, "carrier", tcarrier);
+            rrdset_done(st);
+        }
+    }
+
+    return 0;
 }
index ff038b9276a65cc78a93a4c7e08fecb9e8dab33d..96efd7925a6ebf5ecc1cd2725332c651e96bc686 100644 (file)
@@ -1,92 +1,92 @@
 #include "common.h"
 
-#define RRD_TYPE_NET_IPVS                      "ipvs"
-#define RRD_TYPE_NET_IPVS_LEN          strlen(RRD_TYPE_NET_IPVS)
+#define RRD_TYPE_NET_IPVS           "ipvs"
+#define RRD_TYPE_NET_IPVS_LEN       strlen(RRD_TYPE_NET_IPVS)
 
 int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt) {
-       static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
-       static procfile *ff = NULL;
+    static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
+    static procfile *ff = NULL;
 
-       if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
-       if(do_sockets == -1)    do_sockets              = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
-       if(do_packets == -1)    do_packets              = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
+    if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
+    if(do_sockets == -1)    do_sockets      = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
+    if(do_packets == -1)    do_packets      = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
 
-       if(dt) {};
+    if(dt) {};
 
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
-       // make sure we have 3 lines
-       if(procfile_lines(ff) < 3) return 1;
+    // make sure we have 3 lines
+    if(procfile_lines(ff) < 3) return 1;
 
-       // make sure we have 5 words on the 3rd line
-       if(procfile_linewords(ff, 2) < 5) return 1;
+    // make sure we have 5 words on the 3rd line
+    if(procfile_linewords(ff, 2) < 5) return 1;
 
-       unsigned long long entries, InPackets, OutPackets, InBytes, OutBytes;
+    unsigned long long entries, InPackets, OutPackets, InBytes, OutBytes;
 
-       entries         = strtoull(procfile_lineword(ff, 2, 0), NULL, 16);
-       InPackets       = strtoull(procfile_lineword(ff, 2, 1), NULL, 16);
-       OutPackets      = strtoull(procfile_lineword(ff, 2, 2), NULL, 16);
-       InBytes         = strtoull(procfile_lineword(ff, 2, 3), NULL, 16);
-       OutBytes        = strtoull(procfile_lineword(ff, 2, 4), NULL, 16);
+    entries     = strtoull(procfile_lineword(ff, 2, 0), NULL, 16);
+    InPackets   = strtoull(procfile_lineword(ff, 2, 1), NULL, 16);
+    OutPackets  = strtoull(procfile_lineword(ff, 2, 2), NULL, 16);
+    InBytes     = strtoull(procfile_lineword(ff, 2, 3), NULL, 16);
+    OutBytes    = strtoull(procfile_lineword(ff, 2, 4), NULL, 16);
 
-       RRDSET *st;
+    RRDSET *st;
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_sockets) {
-               st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
+    if(do_sockets) {
+        st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "connections", entries);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "connections", entries);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_packets) {
-               st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 1002, update_every, RRDSET_TYPE_LINE);
+    if(do_packets) {
+        st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 1002, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "received", InPackets);
-               rrddim_set(st, "sent", OutPackets);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "received", InPackets);
+        rrddim_set(st, "sent", OutPackets);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_bandwidth) {
-               st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 1000, update_every, RRDSET_TYPE_AREA);
+    if(do_bandwidth) {
+        st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 1000, update_every, RRDSET_TYPE_AREA);
 
-                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "received", InBytes);
-               rrddim_set(st, "sent", OutBytes);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "received", InBytes);
+        rrddim_set(st, "sent", OutBytes);
+        rrdset_done(st);
+    }
 
-       return 0;
+    return 0;
 }
index 1f3bff303c71906673e926c3ab4cdd86cd81e25b..fe1c4d9793aa4096297f9ba36e7a946d7519e779 100644 (file)
 #include "common.h"
 
 int do_proc_net_netstat(int update_every, unsigned long long dt) {
-       static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
-       static procfile *ff = NULL;
-
-       if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_inerrors == -1)   do_inerrors             = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_mcast == -1)              do_mcast                = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_bcast == -1)              do_bcast                = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_mcast_p == -1)    do_mcast_p              = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_bcast_p == -1)    do_bcast_p              = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       for(l = 0; l < lines ;l++) {
-               if(strcmp(procfile_lineword(ff, l, 0), "IpExt") == 0) {
-                       l++; // we need the next line
-
-                       if(strcmp(procfile_lineword(ff, l, 0), "IpExt") != 0) {
-                               error("Cannot read IpExt line from /proc/net/netstat.");
-                               break;
-                       }
-                       words = procfile_linewords(ff, l);
-                       if(words < 12) {
-                               error("Cannot read /proc/net/netstat IpExt line. Expected 12 params, read %u.", words);
-                               continue;
-                       }
-
-                       unsigned long long
-                               InNoRoutes = 0, InTruncatedPkts = 0,
-                               InOctets = 0,  InMcastPkts = 0,  InBcastPkts = 0,  InMcastOctets = 0,  InBcastOctets = 0,
-                               OutOctets = 0, OutMcastPkts = 0, OutBcastPkts = 0, OutMcastOctets = 0, OutBcastOctets = 0;
-
-                       InNoRoutes                      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       InTruncatedPkts         = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       InMcastPkts             = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       OutMcastPkts            = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       InBcastPkts             = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       OutBcastPkts            = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-                       InOctets                        = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-                       OutOctets                       = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-                       InMcastOctets           = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-                       OutMcastOctets          = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-                       InBcastOctets           = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-                       OutBcastOctets          = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-
-                       RRDSET *st;
-
-                       // --------------------------------------------------------------------
-
-                       if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (InOctets || OutOctets))) {
-                               do_bandwidth = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("system.ipv4");
-                               if(!st) {
-                                       st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
-                                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutOctets);
-                               rrddim_set(st, "received", InOctets);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (InNoRoutes || InTruncatedPkts))) {
-                               do_inerrors = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("ipv4.inerrors");
-                               if(!st) {
-                                       st = rrdset_create("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "noroutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "truncated", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "noroutes", InNoRoutes);
-                               rrddim_set(st, "truncated", InTruncatedPkts);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (InMcastOctets || OutMcastOctets))) {
-                               do_mcast = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("ipv4.mcast");
-                               if(!st) {
-                                       st = rrdset_create("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutMcastOctets);
-                               rrddim_set(st, "received", InMcastOctets);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (InBcastOctets || OutBcastOctets))) {
-                               do_bcast = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("ipv4.bcast");
-                               if(!st) {
-                                       st = rrdset_create("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutBcastOctets);
-                               rrddim_set(st, "received", InBcastOctets);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (InMcastPkts || OutMcastPkts))) {
-                               do_mcast_p = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("ipv4.mcastpkts");
-                               if(!st) {
-                                       st = rrdset_create("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutMcastPkts);
-                               rrddim_set(st, "received", InMcastPkts);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (InBcastPkts || OutBcastPkts))) {
-                               do_bcast_p = CONFIG_ONDEMAND_YES;
-                               st = rrdset_find("ipv4.bcastpkts");
-                               if(!st) {
-                                       st = rrdset_create("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutBcastPkts);
-                               rrddim_set(st, "received", InBcastPkts);
-                               rrdset_done(st);
-                       }
-               }
-       }
-
-       return 0;
+    static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
+    static procfile *ff = NULL;
+
+    if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_inerrors == -1)   do_inerrors     = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_mcast == -1)      do_mcast        = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_bcast == -1)      do_bcast        = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_mcast_p == -1)    do_mcast_p      = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_bcast_p == -1)    do_bcast_p      = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    for(l = 0; l < lines ;l++) {
+        if(strcmp(procfile_lineword(ff, l, 0), "IpExt") == 0) {
+            l++; // we need the next line
+
+            if(strcmp(procfile_lineword(ff, l, 0), "IpExt") != 0) {
+                error("Cannot read IpExt line from /proc/net/netstat.");
+                break;
+            }
+            words = procfile_linewords(ff, l);
+            if(words < 12) {
+                error("Cannot read /proc/net/netstat IpExt line. Expected 12 params, read %u.", words);
+                continue;
+            }
+
+            unsigned long long
+                InNoRoutes = 0, InTruncatedPkts = 0,
+                InOctets = 0,  InMcastPkts = 0,  InBcastPkts = 0,  InMcastOctets = 0,  InBcastOctets = 0,
+                OutOctets = 0, OutMcastPkts = 0, OutBcastPkts = 0, OutMcastOctets = 0, OutBcastOctets = 0;
+
+            InNoRoutes          = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            InTruncatedPkts     = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            InMcastPkts         = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            OutMcastPkts        = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            InBcastPkts         = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            OutBcastPkts        = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            InOctets            = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+            OutOctets           = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+            InMcastOctets       = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+            OutMcastOctets      = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+            InBcastOctets       = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+            OutBcastOctets      = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+
+            RRDSET *st;
+
+            // --------------------------------------------------------------------
+
+            if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (InOctets || OutOctets))) {
+                do_bandwidth = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("system.ipv4");
+                if(!st) {
+                    st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+
+                    rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutOctets);
+                rrddim_set(st, "received", InOctets);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (InNoRoutes || InTruncatedPkts))) {
+                do_inerrors = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.inerrors");
+                if(!st) {
+                    st = rrdset_create("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "noroutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "truncated", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "noroutes", InNoRoutes);
+                rrddim_set(st, "truncated", InTruncatedPkts);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (InMcastOctets || OutMcastOctets))) {
+                do_mcast = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.mcast");
+                if(!st) {
+                    st = rrdset_create("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutMcastOctets);
+                rrddim_set(st, "received", InMcastOctets);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (InBcastOctets || OutBcastOctets))) {
+                do_bcast = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.bcast");
+                if(!st) {
+                    st = rrdset_create("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutBcastOctets);
+                rrddim_set(st, "received", InBcastOctets);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (InMcastPkts || OutMcastPkts))) {
+                do_mcast_p = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.mcastpkts");
+                if(!st) {
+                    st = rrdset_create("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutMcastPkts);
+                rrddim_set(st, "received", InMcastPkts);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (InBcastPkts || OutBcastPkts))) {
+                do_bcast_p = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.bcastpkts");
+                if(!st) {
+                    st = rrdset_create("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutBcastPkts);
+                rrddim_set(st, "received", InBcastPkts);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    return 0;
 }
index 69a18773b31b41759f1a303f7d09af7e1d8ce4c3..0323b4dfb190002872084d8716d25225eaeb403d 100644 (file)
 #include "common.h"
 
 struct nfsd_procs {
-       char name[30];
-       unsigned long long proc2;
-       unsigned long long proc3;
-       unsigned long long proc4;
-       int present2;
-       int present3;
-       int present4;
+    char name[30];
+    unsigned long long proc2;
+    unsigned long long proc3;
+    unsigned long long proc4;
+    int present2;
+    int present3;
+    int present4;
 };
 
 struct nfsd_procs nfsd_proc_values[] = {
-       { "null", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "getattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "setattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "lookup", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "access", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "readlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "read", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "write", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "create", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "mkdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "symlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "mknod", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "remove", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "rmdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "rename", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "link", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "readdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "readdirplus", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "fsstat", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "fsinfo", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "pathconf", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "commit", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
-       { "", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "null", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "getattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "setattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "lookup", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "access", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "readlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "read", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "write", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "create", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "mkdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "symlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "mknod", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "remove", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "rmdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "rename", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "link", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "readdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "readdirplus", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "fsstat", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "fsinfo", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "pathconf", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "commit", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
+    { "", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
 };
 
 struct nfsd4_ops {
-       char name[30];
-       unsigned long long value;
-       int present;
+    char name[30];
+    unsigned long long value;
+    int present;
 };
 
 struct nfsd4_ops nfsd4_ops_values[] = {
-       { "access", 0ULL, 0},
-       { "close", 0ULL, 0},
-       { "commit", 0ULL, 0},
-       { "create", 0ULL, 0},
-       { "delegpurge", 0ULL, 0},
-       { "delegreturn", 0ULL, 0},
-       { "getattr", 0ULL, 0},
-       { "getfh", 0ULL, 0},
-       { "link", 0ULL, 0},
-       { "lock", 0ULL, 0},
-       { "lockt", 0ULL, 0},
-       { "locku", 0ULL, 0},
-       { "lookup", 0ULL, 0},
-       { "lookupp", 0ULL, 0},
-       { "nverify", 0ULL, 0},
-       { "open", 0ULL, 0},
-       { "openattr", 0ULL, 0},
-       { "open_confirm", 0ULL, 0},
-       { "open_downgrade", 0ULL, 0},
-       { "putfh", 0ULL, 0},
-       { "putpubfh", 0ULL, 0},
-       { "putrootfh", 0ULL, 0},
-       { "read", 0ULL, 0},
-       { "readdir", 0ULL, 0},
-       { "readlink", 0ULL, 0},
-       { "remove", 0ULL, 0},
-       { "rename", 0ULL, 0},
-       { "renew", 0ULL, 0},
-       { "restorefh", 0ULL, 0},
-       { "savefh", 0ULL, 0},
-       { "secinfo", 0ULL, 0},
-       { "setattr", 0ULL, 0},
-       { "setclientid", 0ULL, 0},
-       { "setclientid_confirm", 0ULL, 0},
-       { "verify", 0ULL, 0},
-       { "write", 0ULL, 0},
-       { "release_lockowner", 0ULL, 0},
-
-       /* nfs41 */
-       { "backchannel_ctl", 0ULL, 0},
-       { "bind_conn_to_session", 0ULL, 0},
-       { "exchange_id", 0ULL, 0},
-       { "create_session", 0ULL, 0},
-       { "destroy_session", 0ULL, 0},
-       { "free_stateid", 0ULL, 0},
-       { "get_dir_delegation", 0ULL, 0},
-       { "getdeviceinfo", 0ULL, 0},
-       { "getdevicelist", 0ULL, 0},
-       { "layoutcommit", 0ULL, 0},
-       { "layoutget", 0ULL, 0},
-       { "layoutreturn", 0ULL, 0},
-       { "secinfo_no_name", 0ULL, 0},
-       { "sequence", 0ULL, 0},
-       { "set_ssv", 0ULL, 0},
-       { "test_stateid", 0ULL, 0},
-       { "want_delegation", 0ULL, 0},
-       { "destroy_clientid", 0ULL, 0},
-       { "reclaim_complete", 0ULL, 0},
-
-       /* nfs42 */
-       { "allocate", 0ULL, 0},
-       { "copy", 0ULL, 0},
-       { "copy_notify", 0ULL, 0},
-       { "deallocate", 0ULL, 0},
-       { "io_advise", 0ULL, 0},
-       { "layouterror", 0ULL, 0},
-       { "layoutstats", 0ULL, 0},
-       { "offload_cancel", 0ULL, 0},
-       { "offload_status", 0ULL, 0},
-       { "read_plus", 0ULL, 0},
-       { "seek", 0ULL, 0},
-       { "write_same", 0ULL, 0},
-
-       /* termination */
-       { "", 0ULL, 0 }
+    { "access", 0ULL, 0},
+    { "close", 0ULL, 0},
+    { "commit", 0ULL, 0},
+    { "create", 0ULL, 0},
+    { "delegpurge", 0ULL, 0},
+    { "delegreturn", 0ULL, 0},
+    { "getattr", 0ULL, 0},
+    { "getfh", 0ULL, 0},
+    { "link", 0ULL, 0},
+    { "lock", 0ULL, 0},
+    { "lockt", 0ULL, 0},
+    { "locku", 0ULL, 0},
+    { "lookup", 0ULL, 0},
+    { "lookupp", 0ULL, 0},
+    { "nverify", 0ULL, 0},
+    { "open", 0ULL, 0},
+    { "openattr", 0ULL, 0},
+    { "open_confirm", 0ULL, 0},
+    { "open_downgrade", 0ULL, 0},
+    { "putfh", 0ULL, 0},
+    { "putpubfh", 0ULL, 0},
+    { "putrootfh", 0ULL, 0},
+    { "read", 0ULL, 0},
+    { "readdir", 0ULL, 0},
+    { "readlink", 0ULL, 0},
+    { "remove", 0ULL, 0},
+    { "rename", 0ULL, 0},
+    { "renew", 0ULL, 0},
+    { "restorefh", 0ULL, 0},
+    { "savefh", 0ULL, 0},
+    { "secinfo", 0ULL, 0},
+    { "setattr", 0ULL, 0},
+    { "setclientid", 0ULL, 0},
+    { "setclientid_confirm", 0ULL, 0},
+    { "verify", 0ULL, 0},
+    { "write", 0ULL, 0},
+    { "release_lockowner", 0ULL, 0},
+
+    /* nfs41 */
+    { "backchannel_ctl", 0ULL, 0},
+    { "bind_conn_to_session", 0ULL, 0},
+    { "exchange_id", 0ULL, 0},
+    { "create_session", 0ULL, 0},
+    { "destroy_session", 0ULL, 0},
+    { "free_stateid", 0ULL, 0},
+    { "get_dir_delegation", 0ULL, 0},
+    { "getdeviceinfo", 0ULL, 0},
+    { "getdevicelist", 0ULL, 0},
+    { "layoutcommit", 0ULL, 0},
+    { "layoutget", 0ULL, 0},
+    { "layoutreturn", 0ULL, 0},
+    { "secinfo_no_name", 0ULL, 0},
+    { "sequence", 0ULL, 0},
+    { "set_ssv", 0ULL, 0},
+    { "test_stateid", 0ULL, 0},
+    { "want_delegation", 0ULL, 0},
+    { "destroy_clientid", 0ULL, 0},
+    { "reclaim_complete", 0ULL, 0},
+
+    /* nfs42 */
+    { "allocate", 0ULL, 0},
+    { "copy", 0ULL, 0},
+    { "copy_notify", 0ULL, 0},
+    { "deallocate", 0ULL, 0},
+    { "io_advise", 0ULL, 0},
+    { "layouterror", 0ULL, 0},
+    { "layoutstats", 0ULL, 0},
+    { "offload_cancel", 0ULL, 0},
+    { "offload_status", 0ULL, 0},
+    { "read_plus", 0ULL, 0},
+    { "seek", 0ULL, 0},
+    { "write_same", 0ULL, 0},
+
+    /* termination */
+    { "", 0ULL, 0 }
 };
 
 
 int do_proc_net_rpc_nfsd(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
-       static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       if(do_rc == -1) do_rc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read cache", 1);
-       if(do_fh == -1) do_fh = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "file handles", 1);
-       if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "I/O", 1);
-       if(do_th == -1) do_th = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "threads", 1);
-       if(do_ra == -1) do_ra = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read ahead", 1);
-       if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "network", 1);
-       if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "rpc", 1);
-       if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v2 procedures", 1);
-       if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v3 procedures", 1);
-       if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 procedures", 1);
-       if(do_proc4ops == -1) do_proc4ops = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 operations", 1);
-
-       // if they are enabled, reset them to 1
-       // later we do them =2 to avoid doing strcmp for all lines
-       if(do_rc) do_rc = 1;
-       if(do_fh) do_fh = 1;
-       if(do_io) do_io = 1;
-       if(do_th) do_th = 1;
-       if(do_ra) do_ra = 1;
-       if(do_net) do_net = 1;
-       if(do_rpc) do_rpc = 1;
-       if(do_proc2) do_proc2 = 1;
-       if(do_proc3) do_proc3 = 1;
-       if(do_proc4) do_proc4 = 1;
-       if(do_proc4ops) do_proc4ops = 1;
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       char *type;
-       unsigned long long rc_hits = 0, rc_misses = 0, rc_nocache = 0;
-       unsigned long long fh_stale = 0, fh_total_lookups = 0, fh_anonymous_lookups = 0, fh_dir_not_in_dcache = 0, fh_non_dir_not_in_dcache = 0;
-       unsigned long long io_read = 0, io_write = 0;
-       unsigned long long th_threads = 0, th_fullcnt = 0, th_hist10 = 0, th_hist20 = 0, th_hist30 = 0, th_hist40 = 0, th_hist50 = 0, th_hist60 = 0, th_hist70 = 0, th_hist80 = 0, th_hist90 = 0, th_hist100 = 0;
-       unsigned long long ra_size = 0, ra_hist10 = 0, ra_hist20 = 0, ra_hist30 = 0, ra_hist40 = 0, ra_hist50 = 0, ra_hist60 = 0, ra_hist70 = 0, ra_hist80 = 0, ra_hist90 = 0, ra_hist100 = 0, ra_none = 0;
-       unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0;
-       unsigned long long rpc_count = 0, rpc_bad_format = 0, rpc_bad_auth = 0, rpc_bad_client = 0;
-
-       for(l = 0; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(!words) continue;
-
-               type            = procfile_lineword(ff, l, 0);
-
-               if(do_rc == 1 && strcmp(type, "rc") == 0) {
-                       if(words < 4) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 4);
-                               continue;
-                       }
-
-                       rc_hits = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       rc_misses = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       rc_nocache = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-
-                       unsigned long long sum = rc_hits + rc_misses + rc_nocache;
-                       if(sum == 0ULL) do_rc = -1;
-                       else do_rc = 2;
-               }
-               else if(do_fh == 1 && strcmp(type, "fh") == 0) {
-                       if(words < 6) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
-                               continue;
-                       }
-
-                       fh_stale = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       fh_total_lookups = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       fh_anonymous_lookups = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       fh_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       fh_non_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-
-                       unsigned long long sum = fh_stale + fh_total_lookups + fh_anonymous_lookups + fh_dir_not_in_dcache + fh_non_dir_not_in_dcache;
-                       if(sum == 0ULL) do_fh = -1;
-                       else do_fh = 2;
-               }
-               else if(do_io == 1 && strcmp(type, "io") == 0) {
-                       if(words < 3) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 3);
-                               continue;
-                       }
-
-                       io_read = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       io_write = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-
-                       unsigned long long sum = io_read + io_write;
-                       if(sum == 0ULL) do_io = -1;
-                       else do_io = 2;
-               }
-               else if(do_th == 1 && strcmp(type, "th") == 0) {
-                       if(words < 13) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
-                               continue;
-                       }
-
-                       th_threads = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       th_fullcnt = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       th_hist10 = (unsigned long long)(atof(procfile_lineword(ff, l, 3)) * 1000.0);
-                       th_hist20 = (unsigned long long)(atof(procfile_lineword(ff, l, 4)) * 1000.0);
-                       th_hist30 = (unsigned long long)(atof(procfile_lineword(ff, l, 5)) * 1000.0);
-                       th_hist40 = (unsigned long long)(atof(procfile_lineword(ff, l, 6)) * 1000.0);
-                       th_hist50 = (unsigned long long)(atof(procfile_lineword(ff, l, 7)) * 1000.0);
-                       th_hist60 = (unsigned long long)(atof(procfile_lineword(ff, l, 8)) * 1000.0);
-                       th_hist70 = (unsigned long long)(atof(procfile_lineword(ff, l, 9)) * 1000.0);
-                       th_hist80 = (unsigned long long)(atof(procfile_lineword(ff, l, 10)) * 1000.0);
-                       th_hist90 = (unsigned long long)(atof(procfile_lineword(ff, l, 11)) * 1000.0);
-                       th_hist100 = (unsigned long long)(atof(procfile_lineword(ff, l, 12)) * 1000.0);
-
-                       // threads histogram has been disabled on recent kernels
-                       // http://permalink.gmane.org/gmane.linux.nfs/24528
-                       unsigned long long sum = th_hist10 + th_hist20 + th_hist30 + th_hist40 + th_hist50 + th_hist60 + th_hist70 + th_hist80 + th_hist90 + th_hist100;
-                       if(sum == 0ULL) {
-                               if(!th_warning) {
-                                       info("Disabling /proc/net/rpc/nfsd threads histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       th_warning = 1;
-                               }
-                               do_th = -1;
-                       }
-                       else do_th = 2;
-               }
-               else if(do_ra == 1 && strcmp(type, "ra") == 0) {
-                       if(words < 13) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
-                               continue;
-                       }
-
-                       ra_size = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       ra_hist10 = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       ra_hist20 = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       ra_hist30 = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       ra_hist40 = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       ra_hist50 = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-                       ra_hist60 = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-                       ra_hist70 = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-                       ra_hist80 = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-                       ra_hist90 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-                       ra_hist100 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-                       ra_none = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-
-                       unsigned long long sum = ra_hist10 + ra_hist20 + ra_hist30 + ra_hist40 + ra_hist50 + ra_hist60 + ra_hist70 + ra_hist80 + ra_hist90 + ra_hist100 + ra_none;
-                       if(sum == 0ULL) {
-                               if(!ra_warning) {
-                                       info("Disabling /proc/net/rpc/nfsd read ahead histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       ra_warning = 1;
-                               }
-                               do_ra = -1;
-                       }
-                       else do_ra = 2;
-               }
-               else if(do_net == 1 && strcmp(type, "net") == 0) {
-                       if(words < 5) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 5);
-                               continue;
-                       }
-
-                       net_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       net_udp_count = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       net_tcp_count = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       net_tcp_connections = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-
-                       unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
-                       if(sum == 0ULL) do_net = -1;
-                       else do_net = 2;
-               }
-               else if(do_rpc == 1 && strcmp(type, "rpc") == 0) {
-                       if(words < 6) {
-                               error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
-                               continue;
-                       }
-
-                       rpc_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       rpc_bad_format = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       rpc_bad_auth = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       rpc_bad_client = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-
-                       unsigned long long sum = rpc_count + rpc_bad_format + rpc_bad_auth + rpc_bad_client;
-                       if(sum == 0ULL) do_rpc = -1;
-                       else do_rpc = 2;
-               }
-               else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) {
-                       // the first number is the count of numbers present
-                       // so we start for word 2
-
-                       unsigned long long sum = 0;
-                       unsigned int i, j;
-                       for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
-                               nfsd_proc_values[i].proc2 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
-                               nfsd_proc_values[i].present2 = 1;
-                               sum += nfsd_proc_values[i].proc2;
-                       }
-
-                       if(sum == 0ULL) {
-                               if(!proc2_warning) {
-                                       error("Disabling /proc/net/rpc/nfsd v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       proc2_warning = 1;
-                               }
-                               do_proc2 = 0;
-                       }
-                       else do_proc2 = 2;
-               }
-               else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) {
-                       // the first number is the count of numbers present
-                       // so we start for word 2
-
-                       unsigned long long sum = 0;
-                       unsigned int i, j;
-                       for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
-                               nfsd_proc_values[i].proc3 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
-                               nfsd_proc_values[i].present3 = 1;
-                               sum += nfsd_proc_values[i].proc3;
-                       }
-
-                       if(sum == 0ULL) {
-                               if(!proc3_warning) {
-                                       info("Disabling /proc/net/rpc/nfsd v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       proc3_warning = 1;
-                               }
-                               do_proc3 = 0;
-                       }
-                       else do_proc3 = 2;
-               }
-               else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) {
-                       // the first number is the count of numbers present
-                       // so we start for word 2
-
-                       unsigned long long sum = 0;
-                       unsigned int i, j;
-                       for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
-                               nfsd_proc_values[i].proc4 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
-                               nfsd_proc_values[i].present4 = 1;
-                               sum += nfsd_proc_values[i].proc4;
-                       }
-
-                       if(sum == 0ULL) {
-                               if(!proc4_warning) {
-                                       info("Disabling /proc/net/rpc/nfsd v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       proc4_warning = 1;
-                               }
-                               do_proc4 = 0;
-                       }
-                       else do_proc4 = 2;
-               }
-               else if(do_proc4ops == 1 && strcmp(type, "proc4ops") == 0) {
-                       // the first number is the count of numbers present
-                       // so we start for word 2
-
-                       unsigned long long sum = 0;
-                       unsigned int i, j;
-                       for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) {
-                               nfsd4_ops_values[i].value = strtoull(procfile_lineword(ff, l, j), NULL, 10);
-                               nfsd4_ops_values[i].present = 1;
-                               sum += nfsd4_ops_values[i].value;
-                       }
-
-                       if(sum == 0ULL) {
-                               if(!proc4ops_warning) {
-                                       info("Disabling /proc/net/rpc/nfsd v4 operations chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
-                                       proc4ops_warning = 1;
-                               }
-                               do_proc4ops = 0;
-                       }
-                       else do_proc4ops = 2;
-               }
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       if(do_rc == 2) {
-               st = rrdset_find_bytype("nfsd", "readcache");
-               if(!st) {
-                       st = rrdset_create("nfsd", "readcache", NULL, "nfsd", NULL, "Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
-
-                       rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "hits", rc_hits);
-               rrddim_set(st, "misses", rc_misses);
-               rrddim_set(st, "nocache", rc_nocache);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_fh == 2) {
-               st = rrdset_find_bytype("nfsd", "filehandles");
-               if(!st) {
-                       st = rrdset_create("nfsd", "filehandles", NULL, "nfsd", NULL, "File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "stale", fh_stale);
-               rrddim_set(st, "total_lookups", fh_total_lookups);
-               rrddim_set(st, "anonymous_lookups", fh_anonymous_lookups);
-               rrddim_set(st, "dir_not_in_dcache", fh_dir_not_in_dcache);
-               rrddim_set(st, "non_dir_not_in_dcache", fh_non_dir_not_in_dcache);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_io == 2) {
-               st = rrdset_find_bytype("nfsd", "io");
-               if(!st) {
-                       st = rrdset_create("nfsd", "io", NULL, "nfsd", NULL, "I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
-
-                       rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "read", io_read);
-               rrddim_set(st, "write", io_write);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_th == 2) {
-               st = rrdset_find_bytype("nfsd", "threads");
-               if(!st) {
-                       st = rrdset_create("nfsd", "threads", NULL, "nfsd", NULL, "Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "threads", th_threads);
-               rrdset_done(st);
-
-               st = rrdset_find_bytype("nfsd", "threads_fullcnt");
-               if(!st) {
-                       st = rrdset_create("nfsd", "threads_fullcnt", NULL, "nfsd", NULL, "Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "full_count", th_fullcnt);
-               rrdset_done(st);
-
-               st = rrdset_find_bytype("nfsd", "threads_histogram");
-               if(!st) {
-                       st = rrdset_create("nfsd", "threads_histogram", NULL, "nfsd", NULL, "Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "0%-10%", th_hist10);
-               rrddim_set(st, "10%-20%", th_hist20);
-               rrddim_set(st, "20%-30%", th_hist30);
-               rrddim_set(st, "30%-40%", th_hist40);
-               rrddim_set(st, "40%-50%", th_hist50);
-               rrddim_set(st, "50%-60%", th_hist60);
-               rrddim_set(st, "60%-70%", th_hist70);
-               rrddim_set(st, "70%-80%", th_hist80);
-               rrddim_set(st, "80%-90%", th_hist90);
-               rrddim_set(st, "90%-100%", th_hist100);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ra == 2) {
-               st = rrdset_find_bytype("nfsd", "readahead");
-               if(!st) {
-                       st = rrdset_create("nfsd", "readahead", NULL, "nfsd", NULL, "Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
-
-                       rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                       rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-               }
-               else rrdset_next(st);
-
-               // ignore ra_size
-               if(ra_size) {};
-
-               rrddim_set(st, "10%", ra_hist10);
-               rrddim_set(st, "20%", ra_hist20);
-               rrddim_set(st, "30%", ra_hist30);
-               rrddim_set(st, "40%", ra_hist40);
-               rrddim_set(st, "50%", ra_hist50);
-               rrddim_set(st, "60%", ra_hist60);
-               rrddim_set(st, "70%", ra_hist70);
-               rrddim_set(st, "80%", ra_hist80);
-               rrddim_set(st, "90%", ra_hist90);
-               rrddim_set(st, "100%", ra_hist100);
-               rrddim_set(st, "misses", ra_none);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_net == 2) {
-               st = rrdset_find_bytype("nfsd", "net");
-               if(!st) {
-                       st = rrdset_create("nfsd", "net", NULL, "nfsd", NULL, "Network Reads", "reads/s", 5007, update_every, RRDSET_TYPE_STACKED);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               // ignore net_count, net_tcp_connections
-               if(net_count) {};
-               if(net_tcp_connections) {};
-
-               rrddim_set(st, "udp", net_udp_count);
-               rrddim_set(st, "tcp", net_tcp_count);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_rpc == 2) {
-               st = rrdset_find_bytype("nfsd", "rpc");
-               if(!st) {
-                       st = rrdset_create("nfsd", "rpc", NULL, "nfsd", NULL, "Remote Procedure Calls", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               // ignore rpc_bad_client
-               if(rpc_bad_client) {};
-
-               rrddim_set(st, "all", rpc_count);
-               rrddim_set(st, "bad_format", rpc_bad_format);
-               rrddim_set(st, "bad_auth", rpc_bad_auth);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_proc2 == 2) {
-               unsigned int i;
-               st = rrdset_find_bytype("nfsd", "proc2");
-               if(!st) {
-                       st = rrdset_create("nfsd", "proc2", NULL, "nfsd", NULL, "NFS v2 Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
-
-                       for(i = 0; nfsd_proc_values[i].present2 ; i++)
-                               rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               for(i = 0; nfsd_proc_values[i].present2 ; i++)
-                       rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc2);
-
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_proc3 == 2) {
-               unsigned int i;
-               st = rrdset_find_bytype("nfsd", "proc3");
-               if(!st) {
-                       st = rrdset_create("nfsd", "proc3", NULL, "nfsd", NULL, "NFS v3 Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
-
-                       for(i = 0; nfsd_proc_values[i].present3 ; i++)
-                               rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               for(i = 0; nfsd_proc_values[i].present3 ; i++)
-                       rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc3);
-
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_proc4 == 2) {
-               unsigned int i;
-               st = rrdset_find_bytype("nfsd", "proc4");
-               if(!st) {
-                       st = rrdset_create("nfsd", "proc4", NULL, "nfsd", NULL, "NFS v4 Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
-
-                       for(i = 0; nfsd_proc_values[i].present4 ; i++)
-                               rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+    static procfile *ff = NULL;
+    static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
+    static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    if(do_rc == -1) do_rc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read cache", 1);
+    if(do_fh == -1) do_fh = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "file handles", 1);
+    if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "I/O", 1);
+    if(do_th == -1) do_th = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "threads", 1);
+    if(do_ra == -1) do_ra = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read ahead", 1);
+    if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "network", 1);
+    if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "rpc", 1);
+    if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v2 procedures", 1);
+    if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v3 procedures", 1);
+    if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 procedures", 1);
+    if(do_proc4ops == -1) do_proc4ops = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 operations", 1);
+
+    // if they are enabled, reset them to 1
+    // later we do them =2 to avoid doing strcmp for all lines
+    if(do_rc) do_rc = 1;
+    if(do_fh) do_fh = 1;
+    if(do_io) do_io = 1;
+    if(do_th) do_th = 1;
+    if(do_ra) do_ra = 1;
+    if(do_net) do_net = 1;
+    if(do_rpc) do_rpc = 1;
+    if(do_proc2) do_proc2 = 1;
+    if(do_proc3) do_proc3 = 1;
+    if(do_proc4) do_proc4 = 1;
+    if(do_proc4ops) do_proc4ops = 1;
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    char *type;
+    unsigned long long rc_hits = 0, rc_misses = 0, rc_nocache = 0;
+    unsigned long long fh_stale = 0, fh_total_lookups = 0, fh_anonymous_lookups = 0, fh_dir_not_in_dcache = 0, fh_non_dir_not_in_dcache = 0;
+    unsigned long long io_read = 0, io_write = 0;
+    unsigned long long th_threads = 0, th_fullcnt = 0, th_hist10 = 0, th_hist20 = 0, th_hist30 = 0, th_hist40 = 0, th_hist50 = 0, th_hist60 = 0, th_hist70 = 0, th_hist80 = 0, th_hist90 = 0, th_hist100 = 0;
+    unsigned long long ra_size = 0, ra_hist10 = 0, ra_hist20 = 0, ra_hist30 = 0, ra_hist40 = 0, ra_hist50 = 0, ra_hist60 = 0, ra_hist70 = 0, ra_hist80 = 0, ra_hist90 = 0, ra_hist100 = 0, ra_none = 0;
+    unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0;
+    unsigned long long rpc_count = 0, rpc_bad_format = 0, rpc_bad_auth = 0, rpc_bad_client = 0;
+
+    for(l = 0; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(!words) continue;
+
+        type        = procfile_lineword(ff, l, 0);
+
+        if(do_rc == 1 && strcmp(type, "rc") == 0) {
+            if(words < 4) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 4);
+                continue;
+            }
+
+            rc_hits = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            rc_misses = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            rc_nocache = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+
+            unsigned long long sum = rc_hits + rc_misses + rc_nocache;
+            if(sum == 0ULL) do_rc = -1;
+            else do_rc = 2;
+        }
+        else if(do_fh == 1 && strcmp(type, "fh") == 0) {
+            if(words < 6) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
+                continue;
+            }
+
+            fh_stale = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            fh_total_lookups = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            fh_anonymous_lookups = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            fh_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            fh_non_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+
+            unsigned long long sum = fh_stale + fh_total_lookups + fh_anonymous_lookups + fh_dir_not_in_dcache + fh_non_dir_not_in_dcache;
+            if(sum == 0ULL) do_fh = -1;
+            else do_fh = 2;
+        }
+        else if(do_io == 1 && strcmp(type, "io") == 0) {
+            if(words < 3) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 3);
+                continue;
+            }
+
+            io_read = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            io_write = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+
+            unsigned long long sum = io_read + io_write;
+            if(sum == 0ULL) do_io = -1;
+            else do_io = 2;
+        }
+        else if(do_th == 1 && strcmp(type, "th") == 0) {
+            if(words < 13) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
+                continue;
+            }
+
+            th_threads = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            th_fullcnt = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            th_hist10 = (unsigned long long)(atof(procfile_lineword(ff, l, 3)) * 1000.0);
+            th_hist20 = (unsigned long long)(atof(procfile_lineword(ff, l, 4)) * 1000.0);
+            th_hist30 = (unsigned long long)(atof(procfile_lineword(ff, l, 5)) * 1000.0);
+            th_hist40 = (unsigned long long)(atof(procfile_lineword(ff, l, 6)) * 1000.0);
+            th_hist50 = (unsigned long long)(atof(procfile_lineword(ff, l, 7)) * 1000.0);
+            th_hist60 = (unsigned long long)(atof(procfile_lineword(ff, l, 8)) * 1000.0);
+            th_hist70 = (unsigned long long)(atof(procfile_lineword(ff, l, 9)) * 1000.0);
+            th_hist80 = (unsigned long long)(atof(procfile_lineword(ff, l, 10)) * 1000.0);
+            th_hist90 = (unsigned long long)(atof(procfile_lineword(ff, l, 11)) * 1000.0);
+            th_hist100 = (unsigned long long)(atof(procfile_lineword(ff, l, 12)) * 1000.0);
+
+            // threads histogram has been disabled on recent kernels
+            // http://permalink.gmane.org/gmane.linux.nfs/24528
+            unsigned long long sum = th_hist10 + th_hist20 + th_hist30 + th_hist40 + th_hist50 + th_hist60 + th_hist70 + th_hist80 + th_hist90 + th_hist100;
+            if(sum == 0ULL) {
+                if(!th_warning) {
+                    info("Disabling /proc/net/rpc/nfsd threads histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    th_warning = 1;
+                }
+                do_th = -1;
+            }
+            else do_th = 2;
+        }
+        else if(do_ra == 1 && strcmp(type, "ra") == 0) {
+            if(words < 13) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
+                continue;
+            }
+
+            ra_size = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            ra_hist10 = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            ra_hist20 = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            ra_hist30 = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            ra_hist40 = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            ra_hist50 = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            ra_hist60 = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+            ra_hist70 = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+            ra_hist80 = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+            ra_hist90 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+            ra_hist100 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+            ra_none = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+
+            unsigned long long sum = ra_hist10 + ra_hist20 + ra_hist30 + ra_hist40 + ra_hist50 + ra_hist60 + ra_hist70 + ra_hist80 + ra_hist90 + ra_hist100 + ra_none;
+            if(sum == 0ULL) {
+                if(!ra_warning) {
+                    info("Disabling /proc/net/rpc/nfsd read ahead histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    ra_warning = 1;
+                }
+                do_ra = -1;
+            }
+            else do_ra = 2;
+        }
+        else if(do_net == 1 && strcmp(type, "net") == 0) {
+            if(words < 5) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 5);
+                continue;
+            }
+
+            net_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            net_udp_count = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            net_tcp_count = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            net_tcp_connections = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+
+            unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
+            if(sum == 0ULL) do_net = -1;
+            else do_net = 2;
+        }
+        else if(do_rpc == 1 && strcmp(type, "rpc") == 0) {
+            if(words < 6) {
+                error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
+                continue;
+            }
+
+            rpc_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            rpc_bad_format = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            rpc_bad_auth = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            rpc_bad_client = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+
+            unsigned long long sum = rpc_count + rpc_bad_format + rpc_bad_auth + rpc_bad_client;
+            if(sum == 0ULL) do_rpc = -1;
+            else do_rpc = 2;
+        }
+        else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) {
+            // the first number is the count of numbers present
+            // so we start for word 2
+
+            unsigned long long sum = 0;
+            unsigned int i, j;
+            for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
+                nfsd_proc_values[i].proc2 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
+                nfsd_proc_values[i].present2 = 1;
+                sum += nfsd_proc_values[i].proc2;
+            }
+
+            if(sum == 0ULL) {
+                if(!proc2_warning) {
+                    error("Disabling /proc/net/rpc/nfsd v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    proc2_warning = 1;
+                }
+                do_proc2 = 0;
+            }
+            else do_proc2 = 2;
+        }
+        else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) {
+            // the first number is the count of numbers present
+            // so we start for word 2
+
+            unsigned long long sum = 0;
+            unsigned int i, j;
+            for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
+                nfsd_proc_values[i].proc3 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
+                nfsd_proc_values[i].present3 = 1;
+                sum += nfsd_proc_values[i].proc3;
+            }
+
+            if(sum == 0ULL) {
+                if(!proc3_warning) {
+                    info("Disabling /proc/net/rpc/nfsd v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    proc3_warning = 1;
+                }
+                do_proc3 = 0;
+            }
+            else do_proc3 = 2;
+        }
+        else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) {
+            // the first number is the count of numbers present
+            // so we start for word 2
+
+            unsigned long long sum = 0;
+            unsigned int i, j;
+            for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
+                nfsd_proc_values[i].proc4 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
+                nfsd_proc_values[i].present4 = 1;
+                sum += nfsd_proc_values[i].proc4;
+            }
+
+            if(sum == 0ULL) {
+                if(!proc4_warning) {
+                    info("Disabling /proc/net/rpc/nfsd v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    proc4_warning = 1;
+                }
+                do_proc4 = 0;
+            }
+            else do_proc4 = 2;
+        }
+        else if(do_proc4ops == 1 && strcmp(type, "proc4ops") == 0) {
+            // the first number is the count of numbers present
+            // so we start for word 2
+
+            unsigned long long sum = 0;
+            unsigned int i, j;
+            for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) {
+                nfsd4_ops_values[i].value = strtoull(procfile_lineword(ff, l, j), NULL, 10);
+                nfsd4_ops_values[i].present = 1;
+                sum += nfsd4_ops_values[i].value;
+            }
+
+            if(sum == 0ULL) {
+                if(!proc4ops_warning) {
+                    info("Disabling /proc/net/rpc/nfsd v4 operations chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
+                    proc4ops_warning = 1;
+                }
+                do_proc4ops = 0;
+            }
+            else do_proc4ops = 2;
+        }
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    if(do_rc == 2) {
+        st = rrdset_find_bytype("nfsd", "readcache");
+        if(!st) {
+            st = rrdset_create("nfsd", "readcache", NULL, "nfsd", NULL, "Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "hits", rc_hits);
+        rrddim_set(st, "misses", rc_misses);
+        rrddim_set(st, "nocache", rc_nocache);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_fh == 2) {
+        st = rrdset_find_bytype("nfsd", "filehandles");
+        if(!st) {
+            st = rrdset_create("nfsd", "filehandles", NULL, "nfsd", NULL, "File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "stale", fh_stale);
+        rrddim_set(st, "total_lookups", fh_total_lookups);
+        rrddim_set(st, "anonymous_lookups", fh_anonymous_lookups);
+        rrddim_set(st, "dir_not_in_dcache", fh_dir_not_in_dcache);
+        rrddim_set(st, "non_dir_not_in_dcache", fh_non_dir_not_in_dcache);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_io == 2) {
+        st = rrdset_find_bytype("nfsd", "io");
+        if(!st) {
+            st = rrdset_create("nfsd", "io", NULL, "nfsd", NULL, "I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
+
+            rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "read", io_read);
+        rrddim_set(st, "write", io_write);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_th == 2) {
+        st = rrdset_find_bytype("nfsd", "threads");
+        if(!st) {
+            st = rrdset_create("nfsd", "threads", NULL, "nfsd", NULL, "Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "threads", th_threads);
+        rrdset_done(st);
+
+        st = rrdset_find_bytype("nfsd", "threads_fullcnt");
+        if(!st) {
+            st = rrdset_create("nfsd", "threads_fullcnt", NULL, "nfsd", NULL, "Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "full_count", th_fullcnt);
+        rrdset_done(st);
+
+        st = rrdset_find_bytype("nfsd", "threads_histogram");
+        if(!st) {
+            st = rrdset_create("nfsd", "threads_histogram", NULL, "nfsd", NULL, "Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "0%-10%", th_hist10);
+        rrddim_set(st, "10%-20%", th_hist20);
+        rrddim_set(st, "20%-30%", th_hist30);
+        rrddim_set(st, "30%-40%", th_hist40);
+        rrddim_set(st, "40%-50%", th_hist50);
+        rrddim_set(st, "50%-60%", th_hist60);
+        rrddim_set(st, "60%-70%", th_hist70);
+        rrddim_set(st, "70%-80%", th_hist80);
+        rrddim_set(st, "80%-90%", th_hist90);
+        rrddim_set(st, "90%-100%", th_hist100);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ra == 2) {
+        st = rrdset_find_bytype("nfsd", "readahead");
+        if(!st) {
+            st = rrdset_create("nfsd", "readahead", NULL, "nfsd", NULL, "Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+        }
+        else rrdset_next(st);
+
+        // ignore ra_size
+        if(ra_size) {};
+
+        rrddim_set(st, "10%", ra_hist10);
+        rrddim_set(st, "20%", ra_hist20);
+        rrddim_set(st, "30%", ra_hist30);
+        rrddim_set(st, "40%", ra_hist40);
+        rrddim_set(st, "50%", ra_hist50);
+        rrddim_set(st, "60%", ra_hist60);
+        rrddim_set(st, "70%", ra_hist70);
+        rrddim_set(st, "80%", ra_hist80);
+        rrddim_set(st, "90%", ra_hist90);
+        rrddim_set(st, "100%", ra_hist100);
+        rrddim_set(st, "misses", ra_none);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_net == 2) {
+        st = rrdset_find_bytype("nfsd", "net");
+        if(!st) {
+            st = rrdset_create("nfsd", "net", NULL, "nfsd", NULL, "Network Reads", "reads/s", 5007, update_every, RRDSET_TYPE_STACKED);
+            st->isdetail = 1;
+
+            rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        // ignore net_count, net_tcp_connections
+        if(net_count) {};
+        if(net_tcp_connections) {};
+
+        rrddim_set(st, "udp", net_udp_count);
+        rrddim_set(st, "tcp", net_tcp_count);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_rpc == 2) {
+        st = rrdset_find_bytype("nfsd", "rpc");
+        if(!st) {
+            st = rrdset_create("nfsd", "rpc", NULL, "nfsd", NULL, "Remote Procedure Calls", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        // ignore rpc_bad_client
+        if(rpc_bad_client) {};
+
+        rrddim_set(st, "all", rpc_count);
+        rrddim_set(st, "bad_format", rpc_bad_format);
+        rrddim_set(st, "bad_auth", rpc_bad_auth);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_proc2 == 2) {
+        unsigned int i;
+        st = rrdset_find_bytype("nfsd", "proc2");
+        if(!st) {
+            st = rrdset_create("nfsd", "proc2", NULL, "nfsd", NULL, "NFS v2 Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
+
+            for(i = 0; nfsd_proc_values[i].present2 ; i++)
+                rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        for(i = 0; nfsd_proc_values[i].present2 ; i++)
+            rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc2);
+
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_proc3 == 2) {
+        unsigned int i;
+        st = rrdset_find_bytype("nfsd", "proc3");
+        if(!st) {
+            st = rrdset_create("nfsd", "proc3", NULL, "nfsd", NULL, "NFS v3 Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
+
+            for(i = 0; nfsd_proc_values[i].present3 ; i++)
+                rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        for(i = 0; nfsd_proc_values[i].present3 ; i++)
+            rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc3);
+
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_proc4 == 2) {
+        unsigned int i;
+        st = rrdset_find_bytype("nfsd", "proc4");
+        if(!st) {
+            st = rrdset_create("nfsd", "proc4", NULL, "nfsd", NULL, "NFS v4 Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
+
+            for(i = 0; nfsd_proc_values[i].present4 ; i++)
+                rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               for(i = 0; nfsd_proc_values[i].present4 ; i++)
-                       rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc4);
+        for(i = 0; nfsd_proc_values[i].present4 ; i++)
+            rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc4);
 
-               rrdset_done(st);
-       }
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_proc4ops == 2) {
-               unsigned int i;
-               st = rrdset_find_bytype("nfsd", "proc4ops");
-               if(!st) {
-                       st = rrdset_create("nfsd", "proc4ops", NULL, "nfsd", NULL, "NFS v4 Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
+    if(do_proc4ops == 2) {
+        unsigned int i;
+        st = rrdset_find_bytype("nfsd", "proc4ops");
+        if(!st) {
+            st = rrdset_create("nfsd", "proc4ops", NULL, "nfsd", NULL, "NFS v4 Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
 
-                       for(i = 0; nfsd4_ops_values[i].present ; i++)
-                               rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            for(i = 0; nfsd4_ops_values[i].present ; i++)
+                rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               for(i = 0; nfsd4_ops_values[i].present ; i++)
-                       rrddim_set(st, nfsd4_ops_values[i].name, nfsd4_ops_values[i].value);
+        for(i = 0; nfsd4_ops_values[i].present ; i++)
+            rrddim_set(st, nfsd4_ops_values[i].name, nfsd4_ops_values[i].value);
 
-               rrdset_done(st);
-       }
+        rrdset_done(st);
+    }
 
-       return 0;
+    return 0;
 }
index 815eeac7df0deebdfb97a6a6ca773add7aa938d5..a773f55f603c1a18db44a030246650546f4f2e41 100644 (file)
 #include "common.h"
 
-#define RRD_TYPE_NET_SNMP                      "ipv4"
-#define RRD_TYPE_NET_SNMP_LEN          strlen(RRD_TYPE_NET_SNMP)
+#define RRD_TYPE_NET_SNMP           "ipv4"
+#define RRD_TYPE_NET_SNMP_LEN       strlen(RRD_TYPE_NET_SNMP)
 
 int do_proc_net_snmp(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
-               do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
-               do_udp_packets = -1, do_udp_errors = -1;
-
-       if(do_ip_packets == -1)         do_ip_packets           = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
-       if(do_ip_fragsout == -1)        do_ip_fragsout          = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
-       if(do_ip_fragsin == -1)         do_ip_fragsin           = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
-       if(do_ip_errors == -1)          do_ip_errors            = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
-       if(do_tcp_sockets == -1)        do_tcp_sockets          = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
-       if(do_tcp_packets == -1)        do_tcp_packets          = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
-       if(do_tcp_errors == -1)         do_tcp_errors           = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
-       if(do_tcp_handshake == -1)      do_tcp_handshake        = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
-       if(do_udp_packets == -1)        do_udp_packets          = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
-       if(do_udp_errors == -1)         do_udp_errors           = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       RRDSET *st;
-
-       for(l = 0; l < lines ;l++) {
-               if(strcmp(procfile_lineword(ff, l, 0), "Ip") == 0) {
-                       l++;
-
-                       if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
-                               error("Cannot read Ip line from /proc/net/snmp.");
-                               break;
-                       }
-
-                       words = procfile_linewords(ff, l);
-                       if(words < 20) {
-                               error("Cannot read /proc/net/snmp Ip line. Expected 20 params, read %u.", words);
-                               continue;
-                       }
-
-                       // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
-                       unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
-                               OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
-
-                       Forwarding              = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       DefaultTTL              = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       InReceives              = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       InHdrErrors             = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       InAddrErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       ForwDatagrams   = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-                       InUnknownProtos = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-                       InDiscards              = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-                       InDelivers              = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-                       OutRequests             = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-                       OutDiscards             = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-                       OutNoRoutes             = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-                       ReasmTimeout    = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-                       ReasmReqds              = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-                       ReasmOKs                = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
-                       ReasmFails              = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
-                       FragOKs                 = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
-                       FragFails               = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
-                       FragCreates             = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
-
-                       // these are not counters
-                       if(Forwarding) {};              // is forwarding enabled?
-                       if(DefaultTTL) {};              // the default ttl on packets
-                       if(ReasmTimeout) {};    // Reassembly timeout
-
-                       // this counter is not used
-                       if(InDelivers) {};              // total number of packets delivered to IP user-protocols
-
-                       // --------------------------------------------------------------------
-
-                       if(do_ip_packets) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "sent", OutRequests);
-                               rrddim_set(st, "received", InReceives);
-                               rrddim_set(st, "forwarded", ForwDatagrams);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_ip_fragsout) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "ok", FragOKs);
-                               rrddim_set(st, "failed", FragFails);
-                               rrddim_set(st, "all", FragCreates);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_ip_fragsin) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "ok", ReasmOKs);
-                               rrddim_set(st, "failed", ReasmFails);
-                               rrddim_set(st, "all", ReasmReqds);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_ip_errors) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                                       rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
-
-                                       rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "InDiscards", InDiscards);
-                               rrddim_set(st, "OutDiscards", OutDiscards);
-                               rrddim_set(st, "InHdrErrors", InHdrErrors);
-                               rrddim_set(st, "InAddrErrors", InAddrErrors);
-                               rrddim_set(st, "InUnknownProtos", InUnknownProtos);
-                               rrddim_set(st, "OutNoRoutes", OutNoRoutes);
-                               rrdset_done(st);
-                       }
-               }
-               else if(strcmp(procfile_lineword(ff, l, 0), "Tcp") == 0) {
-                       l++;
-
-                       if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
-                               error("Cannot read Tcp line from /proc/net/snmp.");
-                               break;
-                       }
-
-                       words = procfile_linewords(ff, l);
-                       if(words < 15) {
-                               error("Cannot read /proc/net/snmp Tcp line. Expected 15 params, read %u.", words);
-                               continue;
-                       }
-
-                       unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets,
-                               CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
-
-                       RtoAlgorithm    = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       RtoMin                  = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       RtoMax                  = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       MaxConn                 = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       ActiveOpens             = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       PassiveOpens    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-                       AttemptFails    = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-                       EstabResets             = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-                       CurrEstab               = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-                       InSegs                  = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-                       OutSegs                 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-                       RetransSegs             = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-                       InErrs                  = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-                       OutRsts                 = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-
-                       // these are not counters
-                       if(RtoAlgorithm) {};
-                       if(RtoMin) {};
-                       if(RtoMax) {};
-                       if(MaxConn) {};
-
-                       // --------------------------------------------------------------------
-
-                       // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
-                       if(do_tcp_sockets) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "connections", CurrEstab);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_tcp_packets) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "received", InSegs);
-                               rrddim_set(st, "sent", OutSegs);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_tcp_errors) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "InErrs", InErrs);
-                               rrddim_set(st, "RetransSegs", RetransSegs);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_tcp_handshake) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "EstabResets", EstabResets);
-                               rrddim_set(st, "OutRsts", OutRsts);
-                               rrddim_set(st, "ActiveOpens", ActiveOpens);
-                               rrddim_set(st, "PassiveOpens", PassiveOpens);
-                               rrddim_set(st, "AttemptFails", AttemptFails);
-                               rrdset_done(st);
-                       }
-               }
-               else if(strcmp(procfile_lineword(ff, l, 0), "Udp") == 0) {
-                       l++;
-
-                       if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
-                               error("Cannot read Udp line from /proc/net/snmp.");
-                               break;
-                       }
-
-                       words = procfile_linewords(ff, l);
-                       if(words < 7) {
-                               error("Cannot read /proc/net/snmp Udp line. Expected 7 params, read %u.", words);
-                               continue;
-                       }
-
-                       unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
-
-                       InDatagrams             = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       NoPorts                 = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       InErrors                = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       OutDatagrams    = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       RcvbufErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       SndbufErrors    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-
-                       // --------------------------------------------------------------------
-
-                       // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
-                       if(do_udp_packets) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "received", InDatagrams);
-                               rrddim_set(st, "sent", OutDatagrams);
-                               rrdset_done(st);
-                       }
-
-                       // --------------------------------------------------------------------
-
-                       if(do_udp_errors) {
-                               st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
-                               if(!st) {
-                                       st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "InErrors", InErrors);
-                               rrddim_set(st, "NoPorts", NoPorts);
-                               rrddim_set(st, "RcvbufErrors", RcvbufErrors);
-                               rrddim_set(st, "SndbufErrors", SndbufErrors);
-                               rrdset_done(st);
-                       }
-               }
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
+        do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
+        do_udp_packets = -1, do_udp_errors = -1;
+
+    if(do_ip_packets == -1)     do_ip_packets       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
+    if(do_ip_fragsout == -1)    do_ip_fragsout      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
+    if(do_ip_fragsin == -1)     do_ip_fragsin       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
+    if(do_ip_errors == -1)      do_ip_errors        = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
+    if(do_tcp_sockets == -1)    do_tcp_sockets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
+    if(do_tcp_packets == -1)    do_tcp_packets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
+    if(do_tcp_errors == -1)     do_tcp_errors       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
+    if(do_tcp_handshake == -1)  do_tcp_handshake    = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
+    if(do_udp_packets == -1)    do_udp_packets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
+    if(do_udp_errors == -1)     do_udp_errors       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    RRDSET *st;
+
+    for(l = 0; l < lines ;l++) {
+        if(strcmp(procfile_lineword(ff, l, 0), "Ip") == 0) {
+            l++;
+
+            if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
+                error("Cannot read Ip line from /proc/net/snmp.");
+                break;
+            }
+
+            words = procfile_linewords(ff, l);
+            if(words < 20) {
+                error("Cannot read /proc/net/snmp Ip line. Expected 20 params, read %u.", words);
+                continue;
+            }
+
+            // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
+            unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
+                OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
+
+            Forwarding      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            DefaultTTL      = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            InReceives      = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            InHdrErrors     = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            InAddrErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            ForwDatagrams   = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            InUnknownProtos = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+            InDiscards      = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+            InDelivers      = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+            OutRequests     = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+            OutDiscards     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+            OutNoRoutes     = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+            ReasmTimeout    = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
+            ReasmReqds      = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
+            ReasmOKs        = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
+            ReasmFails      = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
+            FragOKs         = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
+            FragFails       = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
+            FragCreates     = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
+
+            // these are not counters
+            if(Forwarding) {};      // is forwarding enabled?
+            if(DefaultTTL) {};      // the default ttl on packets
+            if(ReasmTimeout) {};    // Reassembly timeout
+
+            // this counter is not used
+            if(InDelivers) {};      // total number of packets delivered to IP user-protocols
+
+            // --------------------------------------------------------------------
+
+            if(do_ip_packets) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "sent", OutRequests);
+                rrddim_set(st, "received", InReceives);
+                rrddim_set(st, "forwarded", ForwDatagrams);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_ip_fragsout) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "ok", FragOKs);
+                rrddim_set(st, "failed", FragFails);
+                rrddim_set(st, "all", FragCreates);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_ip_fragsin) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "ok", ReasmOKs);
+                rrddim_set(st, "failed", ReasmFails);
+                rrddim_set(st, "all", ReasmReqds);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_ip_errors) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "InDiscards", InDiscards);
+                rrddim_set(st, "OutDiscards", OutDiscards);
+                rrddim_set(st, "InHdrErrors", InHdrErrors);
+                rrddim_set(st, "InAddrErrors", InAddrErrors);
+                rrddim_set(st, "InUnknownProtos", InUnknownProtos);
+                rrddim_set(st, "OutNoRoutes", OutNoRoutes);
+                rrdset_done(st);
+            }
+        }
+        else if(strcmp(procfile_lineword(ff, l, 0), "Tcp") == 0) {
+            l++;
+
+            if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
+                error("Cannot read Tcp line from /proc/net/snmp.");
+                break;
+            }
+
+            words = procfile_linewords(ff, l);
+            if(words < 15) {
+                error("Cannot read /proc/net/snmp Tcp line. Expected 15 params, read %u.", words);
+                continue;
+            }
+
+            unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets,
+                CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
+
+            RtoAlgorithm    = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            RtoMin          = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            RtoMax          = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            MaxConn         = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            ActiveOpens     = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            PassiveOpens    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            AttemptFails    = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+            EstabResets     = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+            CurrEstab       = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+            InSegs          = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+            OutSegs         = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+            RetransSegs     = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+            InErrs          = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
+            OutRsts         = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
+
+            // these are not counters
+            if(RtoAlgorithm) {};
+            if(RtoMin) {};
+            if(RtoMax) {};
+            if(MaxConn) {};
+
+            // --------------------------------------------------------------------
+
+            // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
+            if(do_tcp_sockets) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "connections", CurrEstab);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_tcp_packets) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "received", InSegs);
+                rrddim_set(st, "sent", OutSegs);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_tcp_errors) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "InErrs", InErrs);
+                rrddim_set(st, "RetransSegs", RetransSegs);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_tcp_handshake) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "EstabResets", EstabResets);
+                rrddim_set(st, "OutRsts", OutRsts);
+                rrddim_set(st, "ActiveOpens", ActiveOpens);
+                rrddim_set(st, "PassiveOpens", PassiveOpens);
+                rrddim_set(st, "AttemptFails", AttemptFails);
+                rrdset_done(st);
+            }
+        }
+        else if(strcmp(procfile_lineword(ff, l, 0), "Udp") == 0) {
+            l++;
+
+            if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
+                error("Cannot read Udp line from /proc/net/snmp.");
+                break;
+            }
+
+            words = procfile_linewords(ff, l);
+            if(words < 7) {
+                error("Cannot read /proc/net/snmp Udp line. Expected 7 params, read %u.", words);
+                continue;
+            }
+
+            unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
+
+            InDatagrams     = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            NoPorts         = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            InErrors        = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            OutDatagrams    = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            RcvbufErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            SndbufErrors    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+
+            // --------------------------------------------------------------------
+
+            // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
+            if(do_udp_packets) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "received", InDatagrams);
+                rrddim_set(st, "sent", OutDatagrams);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if(do_udp_errors) {
+                st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
+                if(!st) {
+                    st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "InErrors", InErrors);
+                rrddim_set(st, "NoPorts", NoPorts);
+                rrddim_set(st, "RcvbufErrors", RcvbufErrors);
+                rrddim_set(st, "SndbufErrors", SndbufErrors);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    return 0;
 }
 
index 0d770ddd49e978b79690e480fad9acbe178ee422..97dc20edd27ad7f23c4350d60092085cf158a6a4 100644 (file)
 #include "common.h"
 
-#define RRD_TYPE_NET_SNMP6                     "ipv6"
-#define RRD_TYPE_NET_SNMP6_LEN         strlen(RRD_TYPE_NET_SNMP6)
+#define RRD_TYPE_NET_SNMP6          "ipv6"
+#define RRD_TYPE_NET_SNMP6_LEN      strlen(RRD_TYPE_NET_SNMP6)
 
 int do_proc_net_snmp6(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int gen_hashes = -1;
-
-       static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
-               do_udplite_packets = -1, do_udplite_errors = -1,
-               do_udp_packets = -1, do_udp_errors = -1,
-               do_bandwidth = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1,
-               do_icmp = -1, do_icmp_redir = -1, do_icmp_errors = -1, do_icmp_echos = -1, do_icmp_groupmemb = -1,
-               do_icmp_router = -1, do_icmp_neighbor = -1, do_icmp_mldv2 = -1, do_icmp_types = -1, do_ect = -1;
-
-       static uint32_t hash_Ip6InReceives = -1;
-
-       static uint32_t hash_Ip6InHdrErrors = -1;
-       static uint32_t hash_Ip6InTooBigErrors = -1;
-       static uint32_t hash_Ip6InNoRoutes = -1;
-       static uint32_t hash_Ip6InAddrErrors = -1;
-       static uint32_t hash_Ip6InUnknownProtos = -1;
-       static uint32_t hash_Ip6InTruncatedPkts = -1;
-       static uint32_t hash_Ip6InDiscards = -1;
-       static uint32_t hash_Ip6InDelivers = -1;
-
-       static uint32_t hash_Ip6OutForwDatagrams = -1;
-       static uint32_t hash_Ip6OutRequests = -1;
-       static uint32_t hash_Ip6OutDiscards = -1;
-       static uint32_t hash_Ip6OutNoRoutes = -1;
-
-       static uint32_t hash_Ip6ReasmTimeout = -1;
-       static uint32_t hash_Ip6ReasmReqds = -1;
-       static uint32_t hash_Ip6ReasmOKs = -1;
-       static uint32_t hash_Ip6ReasmFails = -1;
-
-       static uint32_t hash_Ip6FragOKs = -1;
-       static uint32_t hash_Ip6FragFails = -1;
-       static uint32_t hash_Ip6FragCreates = -1;
-
-       static uint32_t hash_Ip6InMcastPkts = -1;
-       static uint32_t hash_Ip6OutMcastPkts = -1;
-
-       static uint32_t hash_Ip6InOctets = -1;
-       static uint32_t hash_Ip6OutOctets = -1;
-
-       static uint32_t hash_Ip6InMcastOctets = -1;
-       static uint32_t hash_Ip6OutMcastOctets = -1;
-       static uint32_t hash_Ip6InBcastOctets = -1;
-       static uint32_t hash_Ip6OutBcastOctets = -1;
-
-       static uint32_t hash_Ip6InNoECTPkts = -1;
-       static uint32_t hash_Ip6InECT1Pkts = -1;
-       static uint32_t hash_Ip6InECT0Pkts = -1;
-       static uint32_t hash_Ip6InCEPkts = -1;
-
-       static uint32_t hash_Icmp6InMsgs = -1;
-       static uint32_t hash_Icmp6InErrors = -1;
-       static uint32_t hash_Icmp6OutMsgs = -1;
-       static uint32_t hash_Icmp6OutErrors = -1;
-       static uint32_t hash_Icmp6InCsumErrors = -1;
-       static uint32_t hash_Icmp6InDestUnreachs = -1;
-       static uint32_t hash_Icmp6InPktTooBigs = -1;
-       static uint32_t hash_Icmp6InTimeExcds = -1;
-       static uint32_t hash_Icmp6InParmProblems = -1;
-       static uint32_t hash_Icmp6InEchos = -1;
-       static uint32_t hash_Icmp6InEchoReplies = -1;
-       static uint32_t hash_Icmp6InGroupMembQueries = -1;
-       static uint32_t hash_Icmp6InGroupMembResponses = -1;
-       static uint32_t hash_Icmp6InGroupMembReductions = -1;
-       static uint32_t hash_Icmp6InRouterSolicits = -1;
-       static uint32_t hash_Icmp6InRouterAdvertisements = -1;
-       static uint32_t hash_Icmp6InNeighborSolicits = -1;
-       static uint32_t hash_Icmp6InNeighborAdvertisements = -1;
-       static uint32_t hash_Icmp6InRedirects = -1;
-       static uint32_t hash_Icmp6InMLDv2Reports = -1;
-       static uint32_t hash_Icmp6OutDestUnreachs = -1;
-       static uint32_t hash_Icmp6OutPktTooBigs = -1;
-       static uint32_t hash_Icmp6OutTimeExcds = -1;
-       static uint32_t hash_Icmp6OutParmProblems = -1;
-       static uint32_t hash_Icmp6OutEchos = -1;
-       static uint32_t hash_Icmp6OutEchoReplies = -1;
-       static uint32_t hash_Icmp6OutGroupMembQueries = -1;
-       static uint32_t hash_Icmp6OutGroupMembResponses = -1;
-       static uint32_t hash_Icmp6OutGroupMembReductions = -1;
-       static uint32_t hash_Icmp6OutRouterSolicits = -1;
-       static uint32_t hash_Icmp6OutRouterAdvertisements = -1;
-       static uint32_t hash_Icmp6OutNeighborSolicits = -1;
-       static uint32_t hash_Icmp6OutNeighborAdvertisements = -1;
-       static uint32_t hash_Icmp6OutRedirects = -1;
-       static uint32_t hash_Icmp6OutMLDv2Reports = -1;
-       static uint32_t hash_Icmp6InType1 = -1;
-       static uint32_t hash_Icmp6InType128 = -1;
-       static uint32_t hash_Icmp6InType129 = -1;
-       static uint32_t hash_Icmp6InType136 = -1;
-       static uint32_t hash_Icmp6OutType1 = -1;
-       static uint32_t hash_Icmp6OutType128 = -1;
-       static uint32_t hash_Icmp6OutType129 = -1;
-       static uint32_t hash_Icmp6OutType133 = -1;
-       static uint32_t hash_Icmp6OutType135 = -1;
-       static uint32_t hash_Icmp6OutType143 = -1;
-
-       static uint32_t hash_Udp6InDatagrams = -1;
-       static uint32_t hash_Udp6NoPorts = -1;
-       static uint32_t hash_Udp6InErrors = -1;
-       static uint32_t hash_Udp6OutDatagrams = -1;
-       static uint32_t hash_Udp6RcvbufErrors = -1;
-       static uint32_t hash_Udp6SndbufErrors = -1;
-       static uint32_t hash_Udp6InCsumErrors = -1;
-       static uint32_t hash_Udp6IgnoredMulti = -1;
-
-       static uint32_t hash_UdpLite6InDatagrams = -1;
-       static uint32_t hash_UdpLite6NoPorts = -1;
-       static uint32_t hash_UdpLite6InErrors = -1;
-       static uint32_t hash_UdpLite6OutDatagrams = -1;
-       static uint32_t hash_UdpLite6RcvbufErrors = -1;
-       static uint32_t hash_UdpLite6SndbufErrors = -1;
-       static uint32_t hash_UdpLite6InCsumErrors = -1;
-
-       if(gen_hashes != 1) {
-               gen_hashes = 1;
-               hash_Ip6InReceives = simple_hash("Ip6InReceives");
-               hash_Ip6InHdrErrors = simple_hash("Ip6InHdrErrors");
-               hash_Ip6InTooBigErrors = simple_hash("Ip6InTooBigErrors");
-               hash_Ip6InNoRoutes = simple_hash("Ip6InNoRoutes");
-               hash_Ip6InAddrErrors = simple_hash("Ip6InAddrErrors");
-               hash_Ip6InUnknownProtos = simple_hash("Ip6InUnknownProtos");
-               hash_Ip6InTruncatedPkts = simple_hash("Ip6InTruncatedPkts");
-               hash_Ip6InDiscards = simple_hash("Ip6InDiscards");
-               hash_Ip6InDelivers = simple_hash("Ip6InDelivers");
-               hash_Ip6OutForwDatagrams = simple_hash("Ip6OutForwDatagrams");
-               hash_Ip6OutRequests = simple_hash("Ip6OutRequests");
-               hash_Ip6OutDiscards = simple_hash("Ip6OutDiscards");
-               hash_Ip6OutNoRoutes = simple_hash("Ip6OutNoRoutes");
-               hash_Ip6ReasmTimeout = simple_hash("Ip6ReasmTimeout");
-               hash_Ip6ReasmReqds = simple_hash("Ip6ReasmReqds");
-               hash_Ip6ReasmOKs = simple_hash("Ip6ReasmOKs");
-               hash_Ip6ReasmFails = simple_hash("Ip6ReasmFails");
-               hash_Ip6FragOKs = simple_hash("Ip6FragOKs");
-               hash_Ip6FragFails = simple_hash("Ip6FragFails");
-               hash_Ip6FragCreates = simple_hash("Ip6FragCreates");
-               hash_Ip6InMcastPkts = simple_hash("Ip6InMcastPkts");
-               hash_Ip6OutMcastPkts = simple_hash("Ip6OutMcastPkts");
-               hash_Ip6InOctets = simple_hash("Ip6InOctets");
-               hash_Ip6OutOctets = simple_hash("Ip6OutOctets");
-               hash_Ip6InMcastOctets = simple_hash("Ip6InMcastOctets");
-               hash_Ip6OutMcastOctets = simple_hash("Ip6OutMcastOctets");
-               hash_Ip6InBcastOctets = simple_hash("Ip6InBcastOctets");
-               hash_Ip6OutBcastOctets = simple_hash("Ip6OutBcastOctets");
-               hash_Ip6InNoECTPkts = simple_hash("Ip6InNoECTPkts");
-               hash_Ip6InECT1Pkts = simple_hash("Ip6InECT1Pkts");
-               hash_Ip6InECT0Pkts = simple_hash("Ip6InECT0Pkts");
-               hash_Ip6InCEPkts = simple_hash("Ip6InCEPkts");
-               hash_Icmp6InMsgs = simple_hash("Icmp6InMsgs");
-               hash_Icmp6InErrors = simple_hash("Icmp6InErrors");
-               hash_Icmp6OutMsgs = simple_hash("Icmp6OutMsgs");
-               hash_Icmp6OutErrors = simple_hash("Icmp6OutErrors");
-               hash_Icmp6InCsumErrors = simple_hash("Icmp6InCsumErrors");
-               hash_Icmp6InDestUnreachs = simple_hash("Icmp6InDestUnreachs");
-               hash_Icmp6InPktTooBigs = simple_hash("Icmp6InPktTooBigs");
-               hash_Icmp6InTimeExcds = simple_hash("Icmp6InTimeExcds");
-               hash_Icmp6InParmProblems = simple_hash("Icmp6InParmProblems");
-               hash_Icmp6InEchos = simple_hash("Icmp6InEchos");
-               hash_Icmp6InEchoReplies = simple_hash("Icmp6InEchoReplies");
-               hash_Icmp6InGroupMembQueries = simple_hash("Icmp6InGroupMembQueries");
-               hash_Icmp6InGroupMembResponses = simple_hash("Icmp6InGroupMembResponses");
-               hash_Icmp6InGroupMembReductions = simple_hash("Icmp6InGroupMembReductions");
-               hash_Icmp6InRouterSolicits = simple_hash("Icmp6InRouterSolicits");
-               hash_Icmp6InRouterAdvertisements = simple_hash("Icmp6InRouterAdvertisements");
-               hash_Icmp6InNeighborSolicits = simple_hash("Icmp6InNeighborSolicits");
-               hash_Icmp6InNeighborAdvertisements = simple_hash("Icmp6InNeighborAdvertisements");
-               hash_Icmp6InRedirects = simple_hash("Icmp6InRedirects");
-               hash_Icmp6InMLDv2Reports = simple_hash("Icmp6InMLDv2Reports");
-               hash_Icmp6OutDestUnreachs = simple_hash("Icmp6OutDestUnreachs");
-               hash_Icmp6OutPktTooBigs = simple_hash("Icmp6OutPktTooBigs");
-               hash_Icmp6OutTimeExcds = simple_hash("Icmp6OutTimeExcds");
-               hash_Icmp6OutParmProblems = simple_hash("Icmp6OutParmProblems");
-               hash_Icmp6OutEchos = simple_hash("Icmp6OutEchos");
-               hash_Icmp6OutEchoReplies = simple_hash("Icmp6OutEchoReplies");
-               hash_Icmp6OutGroupMembQueries = simple_hash("Icmp6OutGroupMembQueries");
-               hash_Icmp6OutGroupMembResponses = simple_hash("Icmp6OutGroupMembResponses");
-               hash_Icmp6OutGroupMembReductions = simple_hash("Icmp6OutGroupMembReductions");
-               hash_Icmp6OutRouterSolicits = simple_hash("Icmp6OutRouterSolicits");
-               hash_Icmp6OutRouterAdvertisements = simple_hash("Icmp6OutRouterAdvertisements");
-               hash_Icmp6OutNeighborSolicits = simple_hash("Icmp6OutNeighborSolicits");
-               hash_Icmp6OutNeighborAdvertisements = simple_hash("Icmp6OutNeighborAdvertisements");
-               hash_Icmp6OutRedirects = simple_hash("Icmp6OutRedirects");
-               hash_Icmp6OutMLDv2Reports = simple_hash("Icmp6OutMLDv2Reports");
-               hash_Icmp6InType1 = simple_hash("Icmp6InType1");
-               hash_Icmp6InType128 = simple_hash("Icmp6InType128");
-               hash_Icmp6InType129 = simple_hash("Icmp6InType129");
-               hash_Icmp6InType136 = simple_hash("Icmp6InType136");
-               hash_Icmp6OutType1 = simple_hash("Icmp6OutType1");
-               hash_Icmp6OutType128 = simple_hash("Icmp6OutType128");
-               hash_Icmp6OutType129 = simple_hash("Icmp6OutType129");
-               hash_Icmp6OutType133 = simple_hash("Icmp6OutType133");
-               hash_Icmp6OutType135 = simple_hash("Icmp6OutType135");
-               hash_Icmp6OutType143 = simple_hash("Icmp6OutType143");
-               hash_Udp6InDatagrams = simple_hash("Udp6InDatagrams");
-               hash_Udp6NoPorts = simple_hash("Udp6NoPorts");
-               hash_Udp6InErrors = simple_hash("Udp6InErrors");
-               hash_Udp6OutDatagrams = simple_hash("Udp6OutDatagrams");
-               hash_Udp6RcvbufErrors = simple_hash("Udp6RcvbufErrors");
-               hash_Udp6SndbufErrors = simple_hash("Udp6SndbufErrors");
-               hash_Udp6InCsumErrors = simple_hash("Udp6InCsumErrors");
-               hash_Udp6IgnoredMulti = simple_hash("Udp6IgnoredMulti");
-               hash_UdpLite6InDatagrams = simple_hash("UdpLite6InDatagrams");
-               hash_UdpLite6NoPorts = simple_hash("UdpLite6NoPorts");
-               hash_UdpLite6InErrors = simple_hash("UdpLite6InErrors");
-               hash_UdpLite6OutDatagrams = simple_hash("UdpLite6OutDatagrams");
-               hash_UdpLite6RcvbufErrors = simple_hash("UdpLite6RcvbufErrors");
-               hash_UdpLite6SndbufErrors = simple_hash("UdpLite6SndbufErrors");
-               hash_UdpLite6InCsumErrors = simple_hash("UdpLite6InCsumErrors");
-       }
-
-       if(do_ip_packets == -1)                 do_ip_packets           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_ip_fragsout == -1)                do_ip_fragsout          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_ip_fragsin == -1)                 do_ip_fragsin           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_ip_errors == -1)                  do_ip_errors            = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_udp_packets == -1)                do_udp_packets          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_udp_errors == -1)                 do_udp_errors           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_udplite_packets == -1)    do_udplite_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_udplite_errors == -1)             do_udplite_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_bandwidth == -1)                  do_bandwidth            = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_mcast == -1)                              do_mcast                        = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_bcast == -1)                              do_bcast                        = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_mcast_p == -1)                    do_mcast_p                      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp == -1)                               do_icmp                         = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_redir == -1)                 do_icmp_redir           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_errors == -1)                do_icmp_errors          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_echos == -1)                 do_icmp_echos           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_groupmemb == -1)             do_icmp_groupmemb       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_router == -1)                do_icmp_router          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_neighbor == -1)              do_icmp_neighbor        = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_mldv2 == -1)                 do_icmp_mldv2           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_icmp_types == -1)                 do_icmp_types           = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_ect == -1)                                do_ect                          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       unsigned long long Ip6InReceives = 0ULL;
-       unsigned long long Ip6InHdrErrors = 0ULL;
-       unsigned long long Ip6InTooBigErrors = 0ULL;
-       unsigned long long Ip6InNoRoutes = 0ULL;
-       unsigned long long Ip6InAddrErrors = 0ULL;
-       unsigned long long Ip6InUnknownProtos = 0ULL;
-       unsigned long long Ip6InTruncatedPkts = 0ULL;
-       unsigned long long Ip6InDiscards = 0ULL;
-       unsigned long long Ip6InDelivers = 0ULL;
-       unsigned long long Ip6OutForwDatagrams = 0ULL;
-       unsigned long long Ip6OutRequests = 0ULL;
-       unsigned long long Ip6OutDiscards = 0ULL;
-       unsigned long long Ip6OutNoRoutes = 0ULL;
-       unsigned long long Ip6ReasmTimeout = 0ULL;
-       unsigned long long Ip6ReasmReqds = 0ULL;
-       unsigned long long Ip6ReasmOKs = 0ULL;
-       unsigned long long Ip6ReasmFails = 0ULL;
-       unsigned long long Ip6FragOKs = 0ULL;
-       unsigned long long Ip6FragFails = 0ULL;
-       unsigned long long Ip6FragCreates = 0ULL;
-       unsigned long long Ip6InMcastPkts = 0ULL;
-       unsigned long long Ip6OutMcastPkts = 0ULL;
-       unsigned long long Ip6InOctets = 0ULL;
-       unsigned long long Ip6OutOctets = 0ULL;
-       unsigned long long Ip6InMcastOctets = 0ULL;
-       unsigned long long Ip6OutMcastOctets = 0ULL;
-       unsigned long long Ip6InBcastOctets = 0ULL;
-       unsigned long long Ip6OutBcastOctets = 0ULL;
-       unsigned long long Ip6InNoECTPkts = 0ULL;
-       unsigned long long Ip6InECT1Pkts = 0ULL;
-       unsigned long long Ip6InECT0Pkts = 0ULL;
-       unsigned long long Ip6InCEPkts = 0ULL;
-       unsigned long long Icmp6InMsgs = 0ULL;
-       unsigned long long Icmp6InErrors = 0ULL;
-       unsigned long long Icmp6OutMsgs = 0ULL;
-       unsigned long long Icmp6OutErrors = 0ULL;
-       unsigned long long Icmp6InCsumErrors = 0ULL;
-       unsigned long long Icmp6InDestUnreachs = 0ULL;
-       unsigned long long Icmp6InPktTooBigs = 0ULL;
-       unsigned long long Icmp6InTimeExcds = 0ULL;
-       unsigned long long Icmp6InParmProblems = 0ULL;
-       unsigned long long Icmp6InEchos = 0ULL;
-       unsigned long long Icmp6InEchoReplies = 0ULL;
-       unsigned long long Icmp6InGroupMembQueries = 0ULL;
-       unsigned long long Icmp6InGroupMembResponses = 0ULL;
-       unsigned long long Icmp6InGroupMembReductions = 0ULL;
-       unsigned long long Icmp6InRouterSolicits = 0ULL;
-       unsigned long long Icmp6InRouterAdvertisements = 0ULL;
-       unsigned long long Icmp6InNeighborSolicits = 0ULL;
-       unsigned long long Icmp6InNeighborAdvertisements = 0ULL;
-       unsigned long long Icmp6InRedirects = 0ULL;
-       unsigned long long Icmp6InMLDv2Reports = 0ULL;
-       unsigned long long Icmp6OutDestUnreachs = 0ULL;
-       unsigned long long Icmp6OutPktTooBigs = 0ULL;
-       unsigned long long Icmp6OutTimeExcds = 0ULL;
-       unsigned long long Icmp6OutParmProblems = 0ULL;
-       unsigned long long Icmp6OutEchos = 0ULL;
-       unsigned long long Icmp6OutEchoReplies = 0ULL;
-       unsigned long long Icmp6OutGroupMembQueries = 0ULL;
-       unsigned long long Icmp6OutGroupMembResponses = 0ULL;
-       unsigned long long Icmp6OutGroupMembReductions = 0ULL;
-       unsigned long long Icmp6OutRouterSolicits = 0ULL;
-       unsigned long long Icmp6OutRouterAdvertisements = 0ULL;
-       unsigned long long Icmp6OutNeighborSolicits = 0ULL;
-       unsigned long long Icmp6OutNeighborAdvertisements = 0ULL;
-       unsigned long long Icmp6OutRedirects = 0ULL;
-       unsigned long long Icmp6OutMLDv2Reports = 0ULL;
-       unsigned long long Icmp6InType1 = 0ULL;
-       unsigned long long Icmp6InType128 = 0ULL;
-       unsigned long long Icmp6InType129 = 0ULL;
-       unsigned long long Icmp6InType136 = 0ULL;
-       unsigned long long Icmp6OutType1 = 0ULL;
-       unsigned long long Icmp6OutType128 = 0ULL;
-       unsigned long long Icmp6OutType129 = 0ULL;
-       unsigned long long Icmp6OutType133 = 0ULL;
-       unsigned long long Icmp6OutType135 = 0ULL;
-       unsigned long long Icmp6OutType143 = 0ULL;
-       unsigned long long Udp6InDatagrams = 0ULL;
-       unsigned long long Udp6NoPorts = 0ULL;
-       unsigned long long Udp6InErrors = 0ULL;
-       unsigned long long Udp6OutDatagrams = 0ULL;
-       unsigned long long Udp6RcvbufErrors = 0ULL;
-       unsigned long long Udp6SndbufErrors = 0ULL;
-       unsigned long long Udp6InCsumErrors = 0ULL;
-       unsigned long long Udp6IgnoredMulti = 0ULL;
-       unsigned long long UdpLite6InDatagrams = 0ULL;
-       unsigned long long UdpLite6NoPorts = 0ULL;
-       unsigned long long UdpLite6InErrors = 0ULL;
-       unsigned long long UdpLite6OutDatagrams = 0ULL;
-       unsigned long long UdpLite6RcvbufErrors = 0ULL;
-       unsigned long long UdpLite6SndbufErrors = 0ULL;
-       unsigned long long UdpLite6InCsumErrors = 0ULL;
-
-       for(l = 0; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(words < 2) {
-                       if(words) error("Cannot read /proc/net/snmp6 line %u. Expected 2 params, read %u.", l, words);
-                       continue;
-               }
-
-               char *name = procfile_lineword(ff, l, 0);
-               char * value = procfile_lineword(ff, l, 1);
-               if(!name || !*name || !value || !*value) continue;
-
-               uint32_t hash = simple_hash(name);
-
-               if(0) ;
-               else if(hash == hash_Ip6InReceives && strcmp(name, "Ip6InReceives") == 0) Ip6InReceives = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InHdrErrors && strcmp(name, "Ip6InHdrErrors") == 0) Ip6InHdrErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InTooBigErrors && strcmp(name, "Ip6InTooBigErrors") == 0) Ip6InTooBigErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InNoRoutes && strcmp(name, "Ip6InNoRoutes") == 0) Ip6InNoRoutes = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InAddrErrors && strcmp(name, "Ip6InAddrErrors") == 0) Ip6InAddrErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InUnknownProtos && strcmp(name, "Ip6InUnknownProtos") == 0) Ip6InUnknownProtos = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InTruncatedPkts && strcmp(name, "Ip6InTruncatedPkts") == 0) Ip6InTruncatedPkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InDiscards && strcmp(name, "Ip6InDiscards") == 0) Ip6InDiscards = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InDelivers && strcmp(name, "Ip6InDelivers") == 0) Ip6InDelivers = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutForwDatagrams && strcmp(name, "Ip6OutForwDatagrams") == 0) Ip6OutForwDatagrams = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutRequests && strcmp(name, "Ip6OutRequests") == 0) Ip6OutRequests = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutDiscards && strcmp(name, "Ip6OutDiscards") == 0) Ip6OutDiscards = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutNoRoutes && strcmp(name, "Ip6OutNoRoutes") == 0) Ip6OutNoRoutes = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6ReasmTimeout && strcmp(name, "Ip6ReasmTimeout") == 0) Ip6ReasmTimeout = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6ReasmReqds && strcmp(name, "Ip6ReasmReqds") == 0) Ip6ReasmReqds = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6ReasmOKs && strcmp(name, "Ip6ReasmOKs") == 0) Ip6ReasmOKs = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6ReasmFails && strcmp(name, "Ip6ReasmFails") == 0) Ip6ReasmFails = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6FragOKs && strcmp(name, "Ip6FragOKs") == 0) Ip6FragOKs = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6FragFails && strcmp(name, "Ip6FragFails") == 0) Ip6FragFails = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6FragCreates && strcmp(name, "Ip6FragCreates") == 0) Ip6FragCreates = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InMcastPkts && strcmp(name, "Ip6InMcastPkts") == 0) Ip6InMcastPkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutMcastPkts && strcmp(name, "Ip6OutMcastPkts") == 0) Ip6OutMcastPkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InOctets && strcmp(name, "Ip6InOctets") == 0) Ip6InOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutOctets && strcmp(name, "Ip6OutOctets") == 0) Ip6OutOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InMcastOctets && strcmp(name, "Ip6InMcastOctets") == 0) Ip6InMcastOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutMcastOctets && strcmp(name, "Ip6OutMcastOctets") == 0) Ip6OutMcastOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InBcastOctets && strcmp(name, "Ip6InBcastOctets") == 0) Ip6InBcastOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6OutBcastOctets && strcmp(name, "Ip6OutBcastOctets") == 0) Ip6OutBcastOctets = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InNoECTPkts && strcmp(name, "Ip6InNoECTPkts") == 0) Ip6InNoECTPkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InECT1Pkts && strcmp(name, "Ip6InECT1Pkts") == 0) Ip6InECT1Pkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InECT0Pkts && strcmp(name, "Ip6InECT0Pkts") == 0) Ip6InECT0Pkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Ip6InCEPkts && strcmp(name, "Ip6InCEPkts") == 0) Ip6InCEPkts = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InMsgs && strcmp(name, "Icmp6InMsgs") == 0) Icmp6InMsgs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InErrors && strcmp(name, "Icmp6InErrors") == 0) Icmp6InErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutMsgs && strcmp(name, "Icmp6OutMsgs") == 0) Icmp6OutMsgs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutErrors && strcmp(name, "Icmp6OutErrors") == 0) Icmp6OutErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InCsumErrors && strcmp(name, "Icmp6InCsumErrors") == 0) Icmp6InCsumErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InDestUnreachs && strcmp(name, "Icmp6InDestUnreachs") == 0) Icmp6InDestUnreachs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InPktTooBigs && strcmp(name, "Icmp6InPktTooBigs") == 0) Icmp6InPktTooBigs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InTimeExcds && strcmp(name, "Icmp6InTimeExcds") == 0) Icmp6InTimeExcds = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InParmProblems && strcmp(name, "Icmp6InParmProblems") == 0) Icmp6InParmProblems = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InEchos && strcmp(name, "Icmp6InEchos") == 0) Icmp6InEchos = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InEchoReplies && strcmp(name, "Icmp6InEchoReplies") == 0) Icmp6InEchoReplies = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InGroupMembQueries && strcmp(name, "Icmp6InGroupMembQueries") == 0) Icmp6InGroupMembQueries = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InGroupMembResponses && strcmp(name, "Icmp6InGroupMembResponses") == 0) Icmp6InGroupMembResponses = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InGroupMembReductions && strcmp(name, "Icmp6InGroupMembReductions") == 0) Icmp6InGroupMembReductions = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InRouterSolicits && strcmp(name, "Icmp6InRouterSolicits") == 0) Icmp6InRouterSolicits = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InRouterAdvertisements && strcmp(name, "Icmp6InRouterAdvertisements") == 0) Icmp6InRouterAdvertisements = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InNeighborSolicits && strcmp(name, "Icmp6InNeighborSolicits") == 0) Icmp6InNeighborSolicits = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InNeighborAdvertisements && strcmp(name, "Icmp6InNeighborAdvertisements") == 0) Icmp6InNeighborAdvertisements = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InRedirects && strcmp(name, "Icmp6InRedirects") == 0) Icmp6InRedirects = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InMLDv2Reports && strcmp(name, "Icmp6InMLDv2Reports") == 0) Icmp6InMLDv2Reports = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutDestUnreachs && strcmp(name, "Icmp6OutDestUnreachs") == 0) Icmp6OutDestUnreachs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutPktTooBigs && strcmp(name, "Icmp6OutPktTooBigs") == 0) Icmp6OutPktTooBigs = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutTimeExcds && strcmp(name, "Icmp6OutTimeExcds") == 0) Icmp6OutTimeExcds = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutParmProblems && strcmp(name, "Icmp6OutParmProblems") == 0) Icmp6OutParmProblems = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutEchos && strcmp(name, "Icmp6OutEchos") == 0) Icmp6OutEchos = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutEchoReplies && strcmp(name, "Icmp6OutEchoReplies") == 0) Icmp6OutEchoReplies = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutGroupMembQueries && strcmp(name, "Icmp6OutGroupMembQueries") == 0) Icmp6OutGroupMembQueries = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutGroupMembResponses && strcmp(name, "Icmp6OutGroupMembResponses") == 0) Icmp6OutGroupMembResponses = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutGroupMembReductions && strcmp(name, "Icmp6OutGroupMembReductions") == 0) Icmp6OutGroupMembReductions = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutRouterSolicits && strcmp(name, "Icmp6OutRouterSolicits") == 0) Icmp6OutRouterSolicits = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutRouterAdvertisements && strcmp(name, "Icmp6OutRouterAdvertisements") == 0) Icmp6OutRouterAdvertisements = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutNeighborSolicits && strcmp(name, "Icmp6OutNeighborSolicits") == 0) Icmp6OutNeighborSolicits = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutNeighborAdvertisements && strcmp(name, "Icmp6OutNeighborAdvertisements") == 0) Icmp6OutNeighborAdvertisements = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutRedirects && strcmp(name, "Icmp6OutRedirects") == 0) Icmp6OutRedirects = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutMLDv2Reports && strcmp(name, "Icmp6OutMLDv2Reports") == 0) Icmp6OutMLDv2Reports = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InType1 && strcmp(name, "Icmp6InType1") == 0) Icmp6InType1 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InType128 && strcmp(name, "Icmp6InType128") == 0) Icmp6InType128 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InType129 && strcmp(name, "Icmp6InType129") == 0) Icmp6InType129 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6InType136 && strcmp(name, "Icmp6InType136") == 0) Icmp6InType136 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType1 && strcmp(name, "Icmp6OutType1") == 0) Icmp6OutType1 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType128 && strcmp(name, "Icmp6OutType128") == 0) Icmp6OutType128 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType129 && strcmp(name, "Icmp6OutType129") == 0) Icmp6OutType129 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType133 && strcmp(name, "Icmp6OutType133") == 0) Icmp6OutType133 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType135 && strcmp(name, "Icmp6OutType135") == 0) Icmp6OutType135 = strtoull(value, NULL, 10);
-               else if(hash == hash_Icmp6OutType143 && strcmp(name, "Icmp6OutType143") == 0) Icmp6OutType143 = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6InDatagrams && strcmp(name, "Udp6InDatagrams") == 0) Udp6InDatagrams = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6NoPorts && strcmp(name, "Udp6NoPorts") == 0) Udp6NoPorts = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6InErrors && strcmp(name, "Udp6InErrors") == 0) Udp6InErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6OutDatagrams && strcmp(name, "Udp6OutDatagrams") == 0) Udp6OutDatagrams = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6RcvbufErrors && strcmp(name, "Udp6RcvbufErrors") == 0) Udp6RcvbufErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6SndbufErrors && strcmp(name, "Udp6SndbufErrors") == 0) Udp6SndbufErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6InCsumErrors && strcmp(name, "Udp6InCsumErrors") == 0) Udp6InCsumErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_Udp6IgnoredMulti && strcmp(name, "Udp6IgnoredMulti") == 0) Udp6IgnoredMulti = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6InDatagrams && strcmp(name, "UdpLite6InDatagrams") == 0) UdpLite6InDatagrams = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6NoPorts && strcmp(name, "UdpLite6NoPorts") == 0) UdpLite6NoPorts = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6InErrors && strcmp(name, "UdpLite6InErrors") == 0) UdpLite6InErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6OutDatagrams && strcmp(name, "UdpLite6OutDatagrams") == 0) UdpLite6OutDatagrams = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6RcvbufErrors && strcmp(name, "UdpLite6RcvbufErrors") == 0) UdpLite6RcvbufErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6SndbufErrors && strcmp(name, "UdpLite6SndbufErrors") == 0) UdpLite6SndbufErrors = strtoull(value, NULL, 10);
-               else if(hash == hash_UdpLite6InCsumErrors && strcmp(name, "UdpLite6InCsumErrors") == 0) UdpLite6InCsumErrors = strtoull(value, NULL, 10);
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
-               do_bandwidth = CONFIG_ONDEMAND_YES;
-               st = rrdset_find("system.ipv6");
-               if(!st) {
-                       st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
-
-                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Ip6OutOctets);
-               rrddim_set(st, "received", Ip6InOctets);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
-               do_ip_packets = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Ip6OutRequests);
-               rrddim_set(st, "received", Ip6InReceives);
-               rrddim_set(st, "forwarded", Ip6InDelivers);
-               rrddim_set(st, "delivers", Ip6OutForwDatagrams);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
-               do_ip_fragsout = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "ok", Ip6FragOKs);
-               rrddim_set(st, "failed", Ip6FragFails);
-               rrddim_set(st, "all", Ip6FragCreates);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Ip6ReasmOKs
-                       || Ip6ReasmFails
-                       || Ip6ReasmTimeout
-                       || Ip6ReasmReqds
-                       ))) {
-               do_ip_fragsin = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "ok", Ip6ReasmOKs);
-               rrddim_set(st, "failed", Ip6ReasmFails);
-               rrddim_set(st, "timeout", Ip6ReasmTimeout);
-               rrddim_set(st, "all", Ip6ReasmReqds);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Ip6InDiscards
-                       || Ip6OutDiscards
-                       || Ip6InHdrErrors
-                       || Ip6InAddrErrors
-                       || Ip6InUnknownProtos
-                       || Ip6InTooBigErrors
-                       || Ip6InTruncatedPkts
-                       || Ip6InNoRoutes
-               ))) {
-               do_ip_errors = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                       rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
-
-                       rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InDiscards", Ip6InDiscards);
-               rrddim_set(st, "OutDiscards", Ip6OutDiscards);
-
-               rrddim_set(st, "InHdrErrors", Ip6InHdrErrors);
-               rrddim_set(st, "InAddrErrors", Ip6InAddrErrors);
-               rrddim_set(st, "InUnknownProtos", Ip6InUnknownProtos);
-               rrddim_set(st, "InTooBigErrors", Ip6InTooBigErrors);
-               rrddim_set(st, "InTruncatedPkts", Ip6InTruncatedPkts);
-               rrddim_set(st, "InNoRoutes", Ip6InNoRoutes);
-
-               rrddim_set(st, "OutNoRoutes", Ip6OutNoRoutes);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
-               do_udp_packets = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "received", Udp6InDatagrams);
-               rrddim_set(st, "sent", Udp6OutDatagrams);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Udp6InErrors
-                       || Udp6NoPorts
-                       || Udp6RcvbufErrors
-                       || Udp6SndbufErrors
-                       || Udp6InCsumErrors
-                       || Udp6IgnoredMulti
-               ))) {
-               do_udp_errors = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InErrors", Udp6InErrors);
-               rrddim_set(st, "NoPorts", Udp6NoPorts);
-               rrddim_set(st, "RcvbufErrors", Udp6RcvbufErrors);
-               rrddim_set(st, "SndbufErrors", Udp6SndbufErrors);
-               rrddim_set(st, "InCsumErrors", Udp6InCsumErrors);
-               rrddim_set(st, "IgnoredMulti", Udp6IgnoredMulti);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
-               do_udplite_packets = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "received", UdpLite6InDatagrams);
-               rrddim_set(st, "sent", UdpLite6OutDatagrams);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       UdpLite6InErrors
-                       || UdpLite6NoPorts
-                       || UdpLite6RcvbufErrors
-                       || UdpLite6SndbufErrors
-                       || Udp6InCsumErrors
-                       || UdpLite6InCsumErrors
-               ))) {
-               do_udplite_errors = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InErrors", UdpLite6InErrors);
-               rrddim_set(st, "NoPorts", UdpLite6NoPorts);
-               rrddim_set(st, "RcvbufErrors", UdpLite6RcvbufErrors);
-               rrddim_set(st, "SndbufErrors", UdpLite6SndbufErrors);
-               rrddim_set(st, "InCsumErrors", UdpLite6InCsumErrors);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
-               do_mcast = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Ip6OutMcastOctets);
-               rrddim_set(st, "received", Ip6InMcastOctets);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
-               do_bcast = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Ip6OutBcastOctets);
-               rrddim_set(st, "received", Ip6InBcastOctets);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
-               do_mcast_p = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Ip6OutMcastPkts);
-               rrddim_set(st, "received", Ip6InMcastPkts);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
-               do_icmp = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Icmp6InMsgs);
-               rrddim_set(st, "received", Icmp6OutMsgs);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
-               do_icmp_redir = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Icmp6InRedirects);
-               rrddim_set(st, "received", Icmp6OutRedirects);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InErrors
-                       || Icmp6OutErrors
-                       || Icmp6InCsumErrors
-                       || Icmp6InDestUnreachs
-                       || Icmp6InPktTooBigs
-                       || Icmp6InTimeExcds
-                       || Icmp6InParmProblems
-                       || Icmp6OutDestUnreachs
-                       || Icmp6OutPktTooBigs
-                       || Icmp6OutTimeExcds
-                       || Icmp6OutParmProblems
-               ))) {
-               do_icmp_errors = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                       rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InErrors", Icmp6InErrors);
-               rrddim_set(st, "OutErrors", Icmp6OutErrors);
-               rrddim_set(st, "InCsumErrors", Icmp6InCsumErrors);
-               rrddim_set(st, "InDestUnreachs", Icmp6InDestUnreachs);
-               rrddim_set(st, "InPktTooBigs", Icmp6InPktTooBigs);
-               rrddim_set(st, "InTimeExcds", Icmp6InTimeExcds);
-               rrddim_set(st, "InParmProblems", Icmp6InParmProblems);
-               rrddim_set(st, "OutDestUnreachs", Icmp6OutDestUnreachs);
-               rrddim_set(st, "OutPktTooBigs", Icmp6OutPktTooBigs);
-               rrddim_set(st, "OutTimeExcds", Icmp6OutTimeExcds);
-               rrddim_set(st, "OutParmProblems", Icmp6OutParmProblems);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InEchos
-                       || Icmp6OutEchos
-                       || Icmp6InEchoReplies
-                       || Icmp6OutEchoReplies
-               ))) {
-               do_icmp_echos = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InEchos", Icmp6InEchos);
-               rrddim_set(st, "OutEchos", Icmp6OutEchos);
-               rrddim_set(st, "InEchoReplies", Icmp6InEchoReplies);
-               rrddim_set(st, "OutEchoReplies", Icmp6OutEchoReplies);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InGroupMembQueries
-                       || Icmp6OutGroupMembQueries
-                       || Icmp6InGroupMembResponses
-                       || Icmp6OutGroupMembResponses
-                       || Icmp6InGroupMembReductions
-                       || Icmp6OutGroupMembReductions
-               ))) {
-               do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InQueries", Icmp6InGroupMembQueries);
-               rrddim_set(st, "OutQueries", Icmp6OutGroupMembQueries);
-               rrddim_set(st, "InResponses", Icmp6InGroupMembResponses);
-               rrddim_set(st, "OutResponses", Icmp6OutGroupMembResponses);
-               rrddim_set(st, "InReductions", Icmp6InGroupMembReductions);
-               rrddim_set(st, "OutReductions", Icmp6OutGroupMembReductions);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InRouterSolicits
-                       || Icmp6OutRouterSolicits
-                       || Icmp6InRouterAdvertisements
-                       || Icmp6OutRouterAdvertisements
-               ))) {
-               do_icmp_router = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InSolicits", Icmp6InRouterSolicits);
-               rrddim_set(st, "OutSolicits", Icmp6OutRouterSolicits);
-               rrddim_set(st, "InAdvertisements", Icmp6InRouterAdvertisements);
-               rrddim_set(st, "OutAdvertisements", Icmp6OutRouterAdvertisements);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InNeighborSolicits
-                       || Icmp6OutNeighborSolicits
-                       || Icmp6InNeighborAdvertisements
-                       || Icmp6OutNeighborAdvertisements
-               ))) {
-               do_icmp_neighbor = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InSolicits", Icmp6InNeighborSolicits);
-               rrddim_set(st, "OutSolicits", Icmp6OutNeighborSolicits);
-               rrddim_set(st, "InAdvertisements", Icmp6InNeighborAdvertisements);
-               rrddim_set(st, "OutAdvertisements", Icmp6OutNeighborAdvertisements);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
-               do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "sent", Icmp6InMLDv2Reports);
-               rrddim_set(st, "received", Icmp6OutMLDv2Reports);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Icmp6InType1
-                       || Icmp6InType128
-                       || Icmp6InType129
-                       || Icmp6InType136
-                       || Icmp6OutType1
-                       || Icmp6OutType128
-                       || Icmp6OutType129
-                       || Icmp6OutType133
-                       || Icmp6OutType135
-                       || Icmp6OutType143
-               ))) {
-               do_icmp_types = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InType1", Icmp6InType1);
-               rrddim_set(st, "InType128", Icmp6InType128);
-               rrddim_set(st, "InType129", Icmp6InType129);
-               rrddim_set(st, "InType136", Icmp6InType136);
-               rrddim_set(st, "OutType1", Icmp6OutType1);
-               rrddim_set(st, "OutType128", Icmp6OutType128);
-               rrddim_set(st, "OutType129", Icmp6OutType129);
-               rrddim_set(st, "OutType133", Icmp6OutType133);
-               rrddim_set(st, "OutType135", Icmp6OutType135);
-               rrddim_set(st, "OutType143", Icmp6OutType143);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
-               && (
-                       Ip6InNoECTPkts
-                       || Ip6InECT1Pkts
-                       || Ip6InECT0Pkts
-                       || Ip6InCEPkts
-               ))) {
-               do_ect = CONFIG_ONDEMAND_YES;
-               st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "InNoECTPkts", Ip6InNoECTPkts);
-               rrddim_set(st, "InECT1Pkts", Ip6InECT1Pkts);
-               rrddim_set(st, "InECT0Pkts", Ip6InECT0Pkts);
-               rrddim_set(st, "InCEPkts", Ip6InCEPkts);
-               rrdset_done(st);
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static int gen_hashes = -1;
+
+    static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
+        do_udplite_packets = -1, do_udplite_errors = -1,
+        do_udp_packets = -1, do_udp_errors = -1,
+        do_bandwidth = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1,
+        do_icmp = -1, do_icmp_redir = -1, do_icmp_errors = -1, do_icmp_echos = -1, do_icmp_groupmemb = -1,
+        do_icmp_router = -1, do_icmp_neighbor = -1, do_icmp_mldv2 = -1, do_icmp_types = -1, do_ect = -1;
+
+    static uint32_t hash_Ip6InReceives = -1;
+
+    static uint32_t hash_Ip6InHdrErrors = -1;
+    static uint32_t hash_Ip6InTooBigErrors = -1;
+    static uint32_t hash_Ip6InNoRoutes = -1;
+    static uint32_t hash_Ip6InAddrErrors = -1;
+    static uint32_t hash_Ip6InUnknownProtos = -1;
+    static uint32_t hash_Ip6InTruncatedPkts = -1;
+    static uint32_t hash_Ip6InDiscards = -1;
+    static uint32_t hash_Ip6InDelivers = -1;
+
+    static uint32_t hash_Ip6OutForwDatagrams = -1;
+    static uint32_t hash_Ip6OutRequests = -1;
+    static uint32_t hash_Ip6OutDiscards = -1;
+    static uint32_t hash_Ip6OutNoRoutes = -1;
+
+    static uint32_t hash_Ip6ReasmTimeout = -1;
+    static uint32_t hash_Ip6ReasmReqds = -1;
+    static uint32_t hash_Ip6ReasmOKs = -1;
+    static uint32_t hash_Ip6ReasmFails = -1;
+
+    static uint32_t hash_Ip6FragOKs = -1;
+    static uint32_t hash_Ip6FragFails = -1;
+    static uint32_t hash_Ip6FragCreates = -1;
+
+    static uint32_t hash_Ip6InMcastPkts = -1;
+    static uint32_t hash_Ip6OutMcastPkts = -1;
+
+    static uint32_t hash_Ip6InOctets = -1;
+    static uint32_t hash_Ip6OutOctets = -1;
+
+    static uint32_t hash_Ip6InMcastOctets = -1;
+    static uint32_t hash_Ip6OutMcastOctets = -1;
+    static uint32_t hash_Ip6InBcastOctets = -1;
+    static uint32_t hash_Ip6OutBcastOctets = -1;
+
+    static uint32_t hash_Ip6InNoECTPkts = -1;
+    static uint32_t hash_Ip6InECT1Pkts = -1;
+    static uint32_t hash_Ip6InECT0Pkts = -1;
+    static uint32_t hash_Ip6InCEPkts = -1;
+
+    static uint32_t hash_Icmp6InMsgs = -1;
+    static uint32_t hash_Icmp6InErrors = -1;
+    static uint32_t hash_Icmp6OutMsgs = -1;
+    static uint32_t hash_Icmp6OutErrors = -1;
+    static uint32_t hash_Icmp6InCsumErrors = -1;
+    static uint32_t hash_Icmp6InDestUnreachs = -1;
+    static uint32_t hash_Icmp6InPktTooBigs = -1;
+    static uint32_t hash_Icmp6InTimeExcds = -1;
+    static uint32_t hash_Icmp6InParmProblems = -1;
+    static uint32_t hash_Icmp6InEchos = -1;
+    static uint32_t hash_Icmp6InEchoReplies = -1;
+    static uint32_t hash_Icmp6InGroupMembQueries = -1;
+    static uint32_t hash_Icmp6InGroupMembResponses = -1;
+    static uint32_t hash_Icmp6InGroupMembReductions = -1;
+    static uint32_t hash_Icmp6InRouterSolicits = -1;
+    static uint32_t hash_Icmp6InRouterAdvertisements = -1;
+    static uint32_t hash_Icmp6InNeighborSolicits = -1;
+    static uint32_t hash_Icmp6InNeighborAdvertisements = -1;
+    static uint32_t hash_Icmp6InRedirects = -1;
+    static uint32_t hash_Icmp6InMLDv2Reports = -1;
+    static uint32_t hash_Icmp6OutDestUnreachs = -1;
+    static uint32_t hash_Icmp6OutPktTooBigs = -1;
+    static uint32_t hash_Icmp6OutTimeExcds = -1;
+    static uint32_t hash_Icmp6OutParmProblems = -1;
+    static uint32_t hash_Icmp6OutEchos = -1;
+    static uint32_t hash_Icmp6OutEchoReplies = -1;
+    static uint32_t hash_Icmp6OutGroupMembQueries = -1;
+    static uint32_t hash_Icmp6OutGroupMembResponses = -1;
+    static uint32_t hash_Icmp6OutGroupMembReductions = -1;
+    static uint32_t hash_Icmp6OutRouterSolicits = -1;
+    static uint32_t hash_Icmp6OutRouterAdvertisements = -1;
+    static uint32_t hash_Icmp6OutNeighborSolicits = -1;
+    static uint32_t hash_Icmp6OutNeighborAdvertisements = -1;
+    static uint32_t hash_Icmp6OutRedirects = -1;
+    static uint32_t hash_Icmp6OutMLDv2Reports = -1;
+    static uint32_t hash_Icmp6InType1 = -1;
+    static uint32_t hash_Icmp6InType128 = -1;
+    static uint32_t hash_Icmp6InType129 = -1;
+    static uint32_t hash_Icmp6InType136 = -1;
+    static uint32_t hash_Icmp6OutType1 = -1;
+    static uint32_t hash_Icmp6OutType128 = -1;
+    static uint32_t hash_Icmp6OutType129 = -1;
+    static uint32_t hash_Icmp6OutType133 = -1;
+    static uint32_t hash_Icmp6OutType135 = -1;
+    static uint32_t hash_Icmp6OutType143 = -1;
+
+    static uint32_t hash_Udp6InDatagrams = -1;
+    static uint32_t hash_Udp6NoPorts = -1;
+    static uint32_t hash_Udp6InErrors = -1;
+    static uint32_t hash_Udp6OutDatagrams = -1;
+    static uint32_t hash_Udp6RcvbufErrors = -1;
+    static uint32_t hash_Udp6SndbufErrors = -1;
+    static uint32_t hash_Udp6InCsumErrors = -1;
+    static uint32_t hash_Udp6IgnoredMulti = -1;
+
+    static uint32_t hash_UdpLite6InDatagrams = -1;
+    static uint32_t hash_UdpLite6NoPorts = -1;
+    static uint32_t hash_UdpLite6InErrors = -1;
+    static uint32_t hash_UdpLite6OutDatagrams = -1;
+    static uint32_t hash_UdpLite6RcvbufErrors = -1;
+    static uint32_t hash_UdpLite6SndbufErrors = -1;
+    static uint32_t hash_UdpLite6InCsumErrors = -1;
+
+    if(gen_hashes != 1) {
+        gen_hashes = 1;
+        hash_Ip6InReceives = simple_hash("Ip6InReceives");
+        hash_Ip6InHdrErrors = simple_hash("Ip6InHdrErrors");
+        hash_Ip6InTooBigErrors = simple_hash("Ip6InTooBigErrors");
+        hash_Ip6InNoRoutes = simple_hash("Ip6InNoRoutes");
+        hash_Ip6InAddrErrors = simple_hash("Ip6InAddrErrors");
+        hash_Ip6InUnknownProtos = simple_hash("Ip6InUnknownProtos");
+        hash_Ip6InTruncatedPkts = simple_hash("Ip6InTruncatedPkts");
+        hash_Ip6InDiscards = simple_hash("Ip6InDiscards");
+        hash_Ip6InDelivers = simple_hash("Ip6InDelivers");
+        hash_Ip6OutForwDatagrams = simple_hash("Ip6OutForwDatagrams");
+        hash_Ip6OutRequests = simple_hash("Ip6OutRequests");
+        hash_Ip6OutDiscards = simple_hash("Ip6OutDiscards");
+        hash_Ip6OutNoRoutes = simple_hash("Ip6OutNoRoutes");
+        hash_Ip6ReasmTimeout = simple_hash("Ip6ReasmTimeout");
+        hash_Ip6ReasmReqds = simple_hash("Ip6ReasmReqds");
+        hash_Ip6ReasmOKs = simple_hash("Ip6ReasmOKs");
+        hash_Ip6ReasmFails = simple_hash("Ip6ReasmFails");
+        hash_Ip6FragOKs = simple_hash("Ip6FragOKs");
+        hash_Ip6FragFails = simple_hash("Ip6FragFails");
+        hash_Ip6FragCreates = simple_hash("Ip6FragCreates");
+        hash_Ip6InMcastPkts = simple_hash("Ip6InMcastPkts");
+        hash_Ip6OutMcastPkts = simple_hash("Ip6OutMcastPkts");
+        hash_Ip6InOctets = simple_hash("Ip6InOctets");
+        hash_Ip6OutOctets = simple_hash("Ip6OutOctets");
+        hash_Ip6InMcastOctets = simple_hash("Ip6InMcastOctets");
+        hash_Ip6OutMcastOctets = simple_hash("Ip6OutMcastOctets");
+        hash_Ip6InBcastOctets = simple_hash("Ip6InBcastOctets");
+        hash_Ip6OutBcastOctets = simple_hash("Ip6OutBcastOctets");
+        hash_Ip6InNoECTPkts = simple_hash("Ip6InNoECTPkts");
+        hash_Ip6InECT1Pkts = simple_hash("Ip6InECT1Pkts");
+        hash_Ip6InECT0Pkts = simple_hash("Ip6InECT0Pkts");
+        hash_Ip6InCEPkts = simple_hash("Ip6InCEPkts");
+        hash_Icmp6InMsgs = simple_hash("Icmp6InMsgs");
+        hash_Icmp6InErrors = simple_hash("Icmp6InErrors");
+        hash_Icmp6OutMsgs = simple_hash("Icmp6OutMsgs");
+        hash_Icmp6OutErrors = simple_hash("Icmp6OutErrors");
+        hash_Icmp6InCsumErrors = simple_hash("Icmp6InCsumErrors");
+        hash_Icmp6InDestUnreachs = simple_hash("Icmp6InDestUnreachs");
+        hash_Icmp6InPktTooBigs = simple_hash("Icmp6InPktTooBigs");
+        hash_Icmp6InTimeExcds = simple_hash("Icmp6InTimeExcds");
+        hash_Icmp6InParmProblems = simple_hash("Icmp6InParmProblems");
+        hash_Icmp6InEchos = simple_hash("Icmp6InEchos");
+        hash_Icmp6InEchoReplies = simple_hash("Icmp6InEchoReplies");
+        hash_Icmp6InGroupMembQueries = simple_hash("Icmp6InGroupMembQueries");
+        hash_Icmp6InGroupMembResponses = simple_hash("Icmp6InGroupMembResponses");
+        hash_Icmp6InGroupMembReductions = simple_hash("Icmp6InGroupMembReductions");
+        hash_Icmp6InRouterSolicits = simple_hash("Icmp6InRouterSolicits");
+        hash_Icmp6InRouterAdvertisements = simple_hash("Icmp6InRouterAdvertisements");
+        hash_Icmp6InNeighborSolicits = simple_hash("Icmp6InNeighborSolicits");
+        hash_Icmp6InNeighborAdvertisements = simple_hash("Icmp6InNeighborAdvertisements");
+        hash_Icmp6InRedirects = simple_hash("Icmp6InRedirects");
+        hash_Icmp6InMLDv2Reports = simple_hash("Icmp6InMLDv2Reports");
+        hash_Icmp6OutDestUnreachs = simple_hash("Icmp6OutDestUnreachs");
+        hash_Icmp6OutPktTooBigs = simple_hash("Icmp6OutPktTooBigs");
+        hash_Icmp6OutTimeExcds = simple_hash("Icmp6OutTimeExcds");
+        hash_Icmp6OutParmProblems = simple_hash("Icmp6OutParmProblems");
+        hash_Icmp6OutEchos = simple_hash("Icmp6OutEchos");
+        hash_Icmp6OutEchoReplies = simple_hash("Icmp6OutEchoReplies");
+        hash_Icmp6OutGroupMembQueries = simple_hash("Icmp6OutGroupMembQueries");
+        hash_Icmp6OutGroupMembResponses = simple_hash("Icmp6OutGroupMembResponses");
+        hash_Icmp6OutGroupMembReductions = simple_hash("Icmp6OutGroupMembReductions");
+        hash_Icmp6OutRouterSolicits = simple_hash("Icmp6OutRouterSolicits");
+        hash_Icmp6OutRouterAdvertisements = simple_hash("Icmp6OutRouterAdvertisements");
+        hash_Icmp6OutNeighborSolicits = simple_hash("Icmp6OutNeighborSolicits");
+        hash_Icmp6OutNeighborAdvertisements = simple_hash("Icmp6OutNeighborAdvertisements");
+        hash_Icmp6OutRedirects = simple_hash("Icmp6OutRedirects");
+        hash_Icmp6OutMLDv2Reports = simple_hash("Icmp6OutMLDv2Reports");
+        hash_Icmp6InType1 = simple_hash("Icmp6InType1");
+        hash_Icmp6InType128 = simple_hash("Icmp6InType128");
+        hash_Icmp6InType129 = simple_hash("Icmp6InType129");
+        hash_Icmp6InType136 = simple_hash("Icmp6InType136");
+        hash_Icmp6OutType1 = simple_hash("Icmp6OutType1");
+        hash_Icmp6OutType128 = simple_hash("Icmp6OutType128");
+        hash_Icmp6OutType129 = simple_hash("Icmp6OutType129");
+        hash_Icmp6OutType133 = simple_hash("Icmp6OutType133");
+        hash_Icmp6OutType135 = simple_hash("Icmp6OutType135");
+        hash_Icmp6OutType143 = simple_hash("Icmp6OutType143");
+        hash_Udp6InDatagrams = simple_hash("Udp6InDatagrams");
+        hash_Udp6NoPorts = simple_hash("Udp6NoPorts");
+        hash_Udp6InErrors = simple_hash("Udp6InErrors");
+        hash_Udp6OutDatagrams = simple_hash("Udp6OutDatagrams");
+        hash_Udp6RcvbufErrors = simple_hash("Udp6RcvbufErrors");
+        hash_Udp6SndbufErrors = simple_hash("Udp6SndbufErrors");
+        hash_Udp6InCsumErrors = simple_hash("Udp6InCsumErrors");
+        hash_Udp6IgnoredMulti = simple_hash("Udp6IgnoredMulti");
+        hash_UdpLite6InDatagrams = simple_hash("UdpLite6InDatagrams");
+        hash_UdpLite6NoPorts = simple_hash("UdpLite6NoPorts");
+        hash_UdpLite6InErrors = simple_hash("UdpLite6InErrors");
+        hash_UdpLite6OutDatagrams = simple_hash("UdpLite6OutDatagrams");
+        hash_UdpLite6RcvbufErrors = simple_hash("UdpLite6RcvbufErrors");
+        hash_UdpLite6SndbufErrors = simple_hash("UdpLite6SndbufErrors");
+        hash_UdpLite6InCsumErrors = simple_hash("UdpLite6InCsumErrors");
+    }
+
+    if(do_ip_packets == -1)         do_ip_packets       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_ip_fragsout == -1)        do_ip_fragsout      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_ip_fragsin == -1)         do_ip_fragsin       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_ip_errors == -1)          do_ip_errors        = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_udp_packets == -1)        do_udp_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_udp_errors == -1)         do_udp_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_udplite_packets == -1)    do_udplite_packets  = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_udplite_errors == -1)     do_udplite_errors   = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_bandwidth == -1)          do_bandwidth        = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_mcast == -1)              do_mcast            = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_bcast == -1)              do_bcast            = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_mcast_p == -1)            do_mcast_p          = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp == -1)               do_icmp             = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_redir == -1)         do_icmp_redir       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_errors == -1)        do_icmp_errors      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_echos == -1)         do_icmp_echos       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_groupmemb == -1)     do_icmp_groupmemb   = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_router == -1)        do_icmp_router      = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_neighbor == -1)      do_icmp_neighbor    = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_mldv2 == -1)         do_icmp_mldv2       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_icmp_types == -1)         do_icmp_types       = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_ect == -1)                do_ect              = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    unsigned long long Ip6InReceives = 0ULL;
+    unsigned long long Ip6InHdrErrors = 0ULL;
+    unsigned long long Ip6InTooBigErrors = 0ULL;
+    unsigned long long Ip6InNoRoutes = 0ULL;
+    unsigned long long Ip6InAddrErrors = 0ULL;
+    unsigned long long Ip6InUnknownProtos = 0ULL;
+    unsigned long long Ip6InTruncatedPkts = 0ULL;
+    unsigned long long Ip6InDiscards = 0ULL;
+    unsigned long long Ip6InDelivers = 0ULL;
+    unsigned long long Ip6OutForwDatagrams = 0ULL;
+    unsigned long long Ip6OutRequests = 0ULL;
+    unsigned long long Ip6OutDiscards = 0ULL;
+    unsigned long long Ip6OutNoRoutes = 0ULL;
+    unsigned long long Ip6ReasmTimeout = 0ULL;
+    unsigned long long Ip6ReasmReqds = 0ULL;
+    unsigned long long Ip6ReasmOKs = 0ULL;
+    unsigned long long Ip6ReasmFails = 0ULL;
+    unsigned long long Ip6FragOKs = 0ULL;
+    unsigned long long Ip6FragFails = 0ULL;
+    unsigned long long Ip6FragCreates = 0ULL;
+    unsigned long long Ip6InMcastPkts = 0ULL;
+    unsigned long long Ip6OutMcastPkts = 0ULL;
+    unsigned long long Ip6InOctets = 0ULL;
+    unsigned long long Ip6OutOctets = 0ULL;
+    unsigned long long Ip6InMcastOctets = 0ULL;
+    unsigned long long Ip6OutMcastOctets = 0ULL;
+    unsigned long long Ip6InBcastOctets = 0ULL;
+    unsigned long long Ip6OutBcastOctets = 0ULL;
+    unsigned long long Ip6InNoECTPkts = 0ULL;
+    unsigned long long Ip6InECT1Pkts = 0ULL;
+    unsigned long long Ip6InECT0Pkts = 0ULL;
+    unsigned long long Ip6InCEPkts = 0ULL;
+    unsigned long long Icmp6InMsgs = 0ULL;
+    unsigned long long Icmp6InErrors = 0ULL;
+    unsigned long long Icmp6OutMsgs = 0ULL;
+    unsigned long long Icmp6OutErrors = 0ULL;
+    unsigned long long Icmp6InCsumErrors = 0ULL;
+    unsigned long long Icmp6InDestUnreachs = 0ULL;
+    unsigned long long Icmp6InPktTooBigs = 0ULL;
+    unsigned long long Icmp6InTimeExcds = 0ULL;
+    unsigned long long Icmp6InParmProblems = 0ULL;
+    unsigned long long Icmp6InEchos = 0ULL;
+    unsigned long long Icmp6InEchoReplies = 0ULL;
+    unsigned long long Icmp6InGroupMembQueries = 0ULL;
+    unsigned long long Icmp6InGroupMembResponses = 0ULL;
+    unsigned long long Icmp6InGroupMembReductions = 0ULL;
+    unsigned long long Icmp6InRouterSolicits = 0ULL;
+    unsigned long long Icmp6InRouterAdvertisements = 0ULL;
+    unsigned long long Icmp6InNeighborSolicits = 0ULL;
+    unsigned long long Icmp6InNeighborAdvertisements = 0ULL;
+    unsigned long long Icmp6InRedirects = 0ULL;
+    unsigned long long Icmp6InMLDv2Reports = 0ULL;
+    unsigned long long Icmp6OutDestUnreachs = 0ULL;
+    unsigned long long Icmp6OutPktTooBigs = 0ULL;
+    unsigned long long Icmp6OutTimeExcds = 0ULL;
+    unsigned long long Icmp6OutParmProblems = 0ULL;
+    unsigned long long Icmp6OutEchos = 0ULL;
+    unsigned long long Icmp6OutEchoReplies = 0ULL;
+    unsigned long long Icmp6OutGroupMembQueries = 0ULL;
+    unsigned long long Icmp6OutGroupMembResponses = 0ULL;
+    unsigned long long Icmp6OutGroupMembReductions = 0ULL;
+    unsigned long long Icmp6OutRouterSolicits = 0ULL;
+    unsigned long long Icmp6OutRouterAdvertisements = 0ULL;
+    unsigned long long Icmp6OutNeighborSolicits = 0ULL;
+    unsigned long long Icmp6OutNeighborAdvertisements = 0ULL;
+    unsigned long long Icmp6OutRedirects = 0ULL;
+    unsigned long long Icmp6OutMLDv2Reports = 0ULL;
+    unsigned long long Icmp6InType1 = 0ULL;
+    unsigned long long Icmp6InType128 = 0ULL;
+    unsigned long long Icmp6InType129 = 0ULL;
+    unsigned long long Icmp6InType136 = 0ULL;
+    unsigned long long Icmp6OutType1 = 0ULL;
+    unsigned long long Icmp6OutType128 = 0ULL;
+    unsigned long long Icmp6OutType129 = 0ULL;
+    unsigned long long Icmp6OutType133 = 0ULL;
+    unsigned long long Icmp6OutType135 = 0ULL;
+    unsigned long long Icmp6OutType143 = 0ULL;
+    unsigned long long Udp6InDatagrams = 0ULL;
+    unsigned long long Udp6NoPorts = 0ULL;
+    unsigned long long Udp6InErrors = 0ULL;
+    unsigned long long Udp6OutDatagrams = 0ULL;
+    unsigned long long Udp6RcvbufErrors = 0ULL;
+    unsigned long long Udp6SndbufErrors = 0ULL;
+    unsigned long long Udp6InCsumErrors = 0ULL;
+    unsigned long long Udp6IgnoredMulti = 0ULL;
+    unsigned long long UdpLite6InDatagrams = 0ULL;
+    unsigned long long UdpLite6NoPorts = 0ULL;
+    unsigned long long UdpLite6InErrors = 0ULL;
+    unsigned long long UdpLite6OutDatagrams = 0ULL;
+    unsigned long long UdpLite6RcvbufErrors = 0ULL;
+    unsigned long long UdpLite6SndbufErrors = 0ULL;
+    unsigned long long UdpLite6InCsumErrors = 0ULL;
+
+    for(l = 0; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(words < 2) {
+            if(words) error("Cannot read /proc/net/snmp6 line %u. Expected 2 params, read %u.", l, words);
+            continue;
+        }
+
+        char *name = procfile_lineword(ff, l, 0);
+        char * value = procfile_lineword(ff, l, 1);
+        if(!name || !*name || !value || !*value) continue;
+
+        uint32_t hash = simple_hash(name);
+
+        if(0) ;
+        else if(hash == hash_Ip6InReceives && strcmp(name, "Ip6InReceives") == 0) Ip6InReceives = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InHdrErrors && strcmp(name, "Ip6InHdrErrors") == 0) Ip6InHdrErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InTooBigErrors && strcmp(name, "Ip6InTooBigErrors") == 0) Ip6InTooBigErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InNoRoutes && strcmp(name, "Ip6InNoRoutes") == 0) Ip6InNoRoutes = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InAddrErrors && strcmp(name, "Ip6InAddrErrors") == 0) Ip6InAddrErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InUnknownProtos && strcmp(name, "Ip6InUnknownProtos") == 0) Ip6InUnknownProtos = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InTruncatedPkts && strcmp(name, "Ip6InTruncatedPkts") == 0) Ip6InTruncatedPkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InDiscards && strcmp(name, "Ip6InDiscards") == 0) Ip6InDiscards = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InDelivers && strcmp(name, "Ip6InDelivers") == 0) Ip6InDelivers = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutForwDatagrams && strcmp(name, "Ip6OutForwDatagrams") == 0) Ip6OutForwDatagrams = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutRequests && strcmp(name, "Ip6OutRequests") == 0) Ip6OutRequests = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutDiscards && strcmp(name, "Ip6OutDiscards") == 0) Ip6OutDiscards = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutNoRoutes && strcmp(name, "Ip6OutNoRoutes") == 0) Ip6OutNoRoutes = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6ReasmTimeout && strcmp(name, "Ip6ReasmTimeout") == 0) Ip6ReasmTimeout = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6ReasmReqds && strcmp(name, "Ip6ReasmReqds") == 0) Ip6ReasmReqds = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6ReasmOKs && strcmp(name, "Ip6ReasmOKs") == 0) Ip6ReasmOKs = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6ReasmFails && strcmp(name, "Ip6ReasmFails") == 0) Ip6ReasmFails = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6FragOKs && strcmp(name, "Ip6FragOKs") == 0) Ip6FragOKs = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6FragFails && strcmp(name, "Ip6FragFails") == 0) Ip6FragFails = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6FragCreates && strcmp(name, "Ip6FragCreates") == 0) Ip6FragCreates = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InMcastPkts && strcmp(name, "Ip6InMcastPkts") == 0) Ip6InMcastPkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutMcastPkts && strcmp(name, "Ip6OutMcastPkts") == 0) Ip6OutMcastPkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InOctets && strcmp(name, "Ip6InOctets") == 0) Ip6InOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutOctets && strcmp(name, "Ip6OutOctets") == 0) Ip6OutOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InMcastOctets && strcmp(name, "Ip6InMcastOctets") == 0) Ip6InMcastOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutMcastOctets && strcmp(name, "Ip6OutMcastOctets") == 0) Ip6OutMcastOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InBcastOctets && strcmp(name, "Ip6InBcastOctets") == 0) Ip6InBcastOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6OutBcastOctets && strcmp(name, "Ip6OutBcastOctets") == 0) Ip6OutBcastOctets = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InNoECTPkts && strcmp(name, "Ip6InNoECTPkts") == 0) Ip6InNoECTPkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InECT1Pkts && strcmp(name, "Ip6InECT1Pkts") == 0) Ip6InECT1Pkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InECT0Pkts && strcmp(name, "Ip6InECT0Pkts") == 0) Ip6InECT0Pkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Ip6InCEPkts && strcmp(name, "Ip6InCEPkts") == 0) Ip6InCEPkts = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InMsgs && strcmp(name, "Icmp6InMsgs") == 0) Icmp6InMsgs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InErrors && strcmp(name, "Icmp6InErrors") == 0) Icmp6InErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutMsgs && strcmp(name, "Icmp6OutMsgs") == 0) Icmp6OutMsgs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutErrors && strcmp(name, "Icmp6OutErrors") == 0) Icmp6OutErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InCsumErrors && strcmp(name, "Icmp6InCsumErrors") == 0) Icmp6InCsumErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InDestUnreachs && strcmp(name, "Icmp6InDestUnreachs") == 0) Icmp6InDestUnreachs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InPktTooBigs && strcmp(name, "Icmp6InPktTooBigs") == 0) Icmp6InPktTooBigs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InTimeExcds && strcmp(name, "Icmp6InTimeExcds") == 0) Icmp6InTimeExcds = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InParmProblems && strcmp(name, "Icmp6InParmProblems") == 0) Icmp6InParmProblems = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InEchos && strcmp(name, "Icmp6InEchos") == 0) Icmp6InEchos = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InEchoReplies && strcmp(name, "Icmp6InEchoReplies") == 0) Icmp6InEchoReplies = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InGroupMembQueries && strcmp(name, "Icmp6InGroupMembQueries") == 0) Icmp6InGroupMembQueries = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InGroupMembResponses && strcmp(name, "Icmp6InGroupMembResponses") == 0) Icmp6InGroupMembResponses = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InGroupMembReductions && strcmp(name, "Icmp6InGroupMembReductions") == 0) Icmp6InGroupMembReductions = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InRouterSolicits && strcmp(name, "Icmp6InRouterSolicits") == 0) Icmp6InRouterSolicits = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InRouterAdvertisements && strcmp(name, "Icmp6InRouterAdvertisements") == 0) Icmp6InRouterAdvertisements = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InNeighborSolicits && strcmp(name, "Icmp6InNeighborSolicits") == 0) Icmp6InNeighborSolicits = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InNeighborAdvertisements && strcmp(name, "Icmp6InNeighborAdvertisements") == 0) Icmp6InNeighborAdvertisements = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InRedirects && strcmp(name, "Icmp6InRedirects") == 0) Icmp6InRedirects = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InMLDv2Reports && strcmp(name, "Icmp6InMLDv2Reports") == 0) Icmp6InMLDv2Reports = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutDestUnreachs && strcmp(name, "Icmp6OutDestUnreachs") == 0) Icmp6OutDestUnreachs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutPktTooBigs && strcmp(name, "Icmp6OutPktTooBigs") == 0) Icmp6OutPktTooBigs = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutTimeExcds && strcmp(name, "Icmp6OutTimeExcds") == 0) Icmp6OutTimeExcds = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutParmProblems && strcmp(name, "Icmp6OutParmProblems") == 0) Icmp6OutParmProblems = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutEchos && strcmp(name, "Icmp6OutEchos") == 0) Icmp6OutEchos = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutEchoReplies && strcmp(name, "Icmp6OutEchoReplies") == 0) Icmp6OutEchoReplies = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutGroupMembQueries && strcmp(name, "Icmp6OutGroupMembQueries") == 0) Icmp6OutGroupMembQueries = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutGroupMembResponses && strcmp(name, "Icmp6OutGroupMembResponses") == 0) Icmp6OutGroupMembResponses = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutGroupMembReductions && strcmp(name, "Icmp6OutGroupMembReductions") == 0) Icmp6OutGroupMembReductions = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutRouterSolicits && strcmp(name, "Icmp6OutRouterSolicits") == 0) Icmp6OutRouterSolicits = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutRouterAdvertisements && strcmp(name, "Icmp6OutRouterAdvertisements") == 0) Icmp6OutRouterAdvertisements = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutNeighborSolicits && strcmp(name, "Icmp6OutNeighborSolicits") == 0) Icmp6OutNeighborSolicits = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutNeighborAdvertisements && strcmp(name, "Icmp6OutNeighborAdvertisements") == 0) Icmp6OutNeighborAdvertisements = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutRedirects && strcmp(name, "Icmp6OutRedirects") == 0) Icmp6OutRedirects = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutMLDv2Reports && strcmp(name, "Icmp6OutMLDv2Reports") == 0) Icmp6OutMLDv2Reports = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InType1 && strcmp(name, "Icmp6InType1") == 0) Icmp6InType1 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InType128 && strcmp(name, "Icmp6InType128") == 0) Icmp6InType128 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InType129 && strcmp(name, "Icmp6InType129") == 0) Icmp6InType129 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6InType136 && strcmp(name, "Icmp6InType136") == 0) Icmp6InType136 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType1 && strcmp(name, "Icmp6OutType1") == 0) Icmp6OutType1 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType128 && strcmp(name, "Icmp6OutType128") == 0) Icmp6OutType128 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType129 && strcmp(name, "Icmp6OutType129") == 0) Icmp6OutType129 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType133 && strcmp(name, "Icmp6OutType133") == 0) Icmp6OutType133 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType135 && strcmp(name, "Icmp6OutType135") == 0) Icmp6OutType135 = strtoull(value, NULL, 10);
+        else if(hash == hash_Icmp6OutType143 && strcmp(name, "Icmp6OutType143") == 0) Icmp6OutType143 = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6InDatagrams && strcmp(name, "Udp6InDatagrams") == 0) Udp6InDatagrams = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6NoPorts && strcmp(name, "Udp6NoPorts") == 0) Udp6NoPorts = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6InErrors && strcmp(name, "Udp6InErrors") == 0) Udp6InErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6OutDatagrams && strcmp(name, "Udp6OutDatagrams") == 0) Udp6OutDatagrams = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6RcvbufErrors && strcmp(name, "Udp6RcvbufErrors") == 0) Udp6RcvbufErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6SndbufErrors && strcmp(name, "Udp6SndbufErrors") == 0) Udp6SndbufErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6InCsumErrors && strcmp(name, "Udp6InCsumErrors") == 0) Udp6InCsumErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_Udp6IgnoredMulti && strcmp(name, "Udp6IgnoredMulti") == 0) Udp6IgnoredMulti = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6InDatagrams && strcmp(name, "UdpLite6InDatagrams") == 0) UdpLite6InDatagrams = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6NoPorts && strcmp(name, "UdpLite6NoPorts") == 0) UdpLite6NoPorts = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6InErrors && strcmp(name, "UdpLite6InErrors") == 0) UdpLite6InErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6OutDatagrams && strcmp(name, "UdpLite6OutDatagrams") == 0) UdpLite6OutDatagrams = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6RcvbufErrors && strcmp(name, "UdpLite6RcvbufErrors") == 0) UdpLite6RcvbufErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6SndbufErrors && strcmp(name, "UdpLite6SndbufErrors") == 0) UdpLite6SndbufErrors = strtoull(value, NULL, 10);
+        else if(hash == hash_UdpLite6InCsumErrors && strcmp(name, "UdpLite6InCsumErrors") == 0) UdpLite6InCsumErrors = strtoull(value, NULL, 10);
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
+        do_bandwidth = CONFIG_ONDEMAND_YES;
+        st = rrdset_find("system.ipv6");
+        if(!st) {
+            st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+
+            rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Ip6OutOctets);
+        rrddim_set(st, "received", Ip6InOctets);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
+        do_ip_packets = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Ip6OutRequests);
+        rrddim_set(st, "received", Ip6InReceives);
+        rrddim_set(st, "forwarded", Ip6InDelivers);
+        rrddim_set(st, "delivers", Ip6OutForwDatagrams);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
+        do_ip_fragsout = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "ok", Ip6FragOKs);
+        rrddim_set(st, "failed", Ip6FragFails);
+        rrddim_set(st, "all", Ip6FragCreates);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Ip6ReasmOKs
+            || Ip6ReasmFails
+            || Ip6ReasmTimeout
+            || Ip6ReasmReqds
+            ))) {
+        do_ip_fragsin = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "ok", Ip6ReasmOKs);
+        rrddim_set(st, "failed", Ip6ReasmFails);
+        rrddim_set(st, "timeout", Ip6ReasmTimeout);
+        rrddim_set(st, "all", Ip6ReasmReqds);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Ip6InDiscards
+            || Ip6OutDiscards
+            || Ip6InHdrErrors
+            || Ip6InAddrErrors
+            || Ip6InUnknownProtos
+            || Ip6InTooBigErrors
+            || Ip6InTruncatedPkts
+            || Ip6InNoRoutes
+        ))) {
+        do_ip_errors = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+            rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+
+            rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InDiscards", Ip6InDiscards);
+        rrddim_set(st, "OutDiscards", Ip6OutDiscards);
+
+        rrddim_set(st, "InHdrErrors", Ip6InHdrErrors);
+        rrddim_set(st, "InAddrErrors", Ip6InAddrErrors);
+        rrddim_set(st, "InUnknownProtos", Ip6InUnknownProtos);
+        rrddim_set(st, "InTooBigErrors", Ip6InTooBigErrors);
+        rrddim_set(st, "InTruncatedPkts", Ip6InTruncatedPkts);
+        rrddim_set(st, "InNoRoutes", Ip6InNoRoutes);
+
+        rrddim_set(st, "OutNoRoutes", Ip6OutNoRoutes);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
+        do_udp_packets = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "received", Udp6InDatagrams);
+        rrddim_set(st, "sent", Udp6OutDatagrams);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Udp6InErrors
+            || Udp6NoPorts
+            || Udp6RcvbufErrors
+            || Udp6SndbufErrors
+            || Udp6InCsumErrors
+            || Udp6IgnoredMulti
+        ))) {
+        do_udp_errors = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InErrors", Udp6InErrors);
+        rrddim_set(st, "NoPorts", Udp6NoPorts);
+        rrddim_set(st, "RcvbufErrors", Udp6RcvbufErrors);
+        rrddim_set(st, "SndbufErrors", Udp6SndbufErrors);
+        rrddim_set(st, "InCsumErrors", Udp6InCsumErrors);
+        rrddim_set(st, "IgnoredMulti", Udp6IgnoredMulti);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
+        do_udplite_packets = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "received", UdpLite6InDatagrams);
+        rrddim_set(st, "sent", UdpLite6OutDatagrams);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            UdpLite6InErrors
+            || UdpLite6NoPorts
+            || UdpLite6RcvbufErrors
+            || UdpLite6SndbufErrors
+            || Udp6InCsumErrors
+            || UdpLite6InCsumErrors
+        ))) {
+        do_udplite_errors = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InErrors", UdpLite6InErrors);
+        rrddim_set(st, "NoPorts", UdpLite6NoPorts);
+        rrddim_set(st, "RcvbufErrors", UdpLite6RcvbufErrors);
+        rrddim_set(st, "SndbufErrors", UdpLite6SndbufErrors);
+        rrddim_set(st, "InCsumErrors", UdpLite6InCsumErrors);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
+        do_mcast = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
+            st->isdetail = 1;
+
+            rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Ip6OutMcastOctets);
+        rrddim_set(st, "received", Ip6InMcastOctets);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
+        do_bcast = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
+            st->isdetail = 1;
+
+            rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Ip6OutBcastOctets);
+        rrddim_set(st, "received", Ip6InBcastOctets);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
+        do_mcast_p = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Ip6OutMcastPkts);
+        rrddim_set(st, "received", Ip6InMcastPkts);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
+        do_icmp = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Icmp6InMsgs);
+        rrddim_set(st, "received", Icmp6OutMsgs);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
+        do_icmp_redir = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Icmp6InRedirects);
+        rrddim_set(st, "received", Icmp6OutRedirects);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InErrors
+            || Icmp6OutErrors
+            || Icmp6InCsumErrors
+            || Icmp6InDestUnreachs
+            || Icmp6InPktTooBigs
+            || Icmp6InTimeExcds
+            || Icmp6InParmProblems
+            || Icmp6OutDestUnreachs
+            || Icmp6OutPktTooBigs
+            || Icmp6OutTimeExcds
+            || Icmp6OutParmProblems
+        ))) {
+        do_icmp_errors = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+            rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InErrors", Icmp6InErrors);
+        rrddim_set(st, "OutErrors", Icmp6OutErrors);
+        rrddim_set(st, "InCsumErrors", Icmp6InCsumErrors);
+        rrddim_set(st, "InDestUnreachs", Icmp6InDestUnreachs);
+        rrddim_set(st, "InPktTooBigs", Icmp6InPktTooBigs);
+        rrddim_set(st, "InTimeExcds", Icmp6InTimeExcds);
+        rrddim_set(st, "InParmProblems", Icmp6InParmProblems);
+        rrddim_set(st, "OutDestUnreachs", Icmp6OutDestUnreachs);
+        rrddim_set(st, "OutPktTooBigs", Icmp6OutPktTooBigs);
+        rrddim_set(st, "OutTimeExcds", Icmp6OutTimeExcds);
+        rrddim_set(st, "OutParmProblems", Icmp6OutParmProblems);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InEchos
+            || Icmp6OutEchos
+            || Icmp6InEchoReplies
+            || Icmp6OutEchoReplies
+        ))) {
+        do_icmp_echos = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InEchos", Icmp6InEchos);
+        rrddim_set(st, "OutEchos", Icmp6OutEchos);
+        rrddim_set(st, "InEchoReplies", Icmp6InEchoReplies);
+        rrddim_set(st, "OutEchoReplies", Icmp6OutEchoReplies);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InGroupMembQueries
+            || Icmp6OutGroupMembQueries
+            || Icmp6InGroupMembResponses
+            || Icmp6OutGroupMembResponses
+            || Icmp6InGroupMembReductions
+            || Icmp6OutGroupMembReductions
+        ))) {
+        do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InQueries", Icmp6InGroupMembQueries);
+        rrddim_set(st, "OutQueries", Icmp6OutGroupMembQueries);
+        rrddim_set(st, "InResponses", Icmp6InGroupMembResponses);
+        rrddim_set(st, "OutResponses", Icmp6OutGroupMembResponses);
+        rrddim_set(st, "InReductions", Icmp6InGroupMembReductions);
+        rrddim_set(st, "OutReductions", Icmp6OutGroupMembReductions);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InRouterSolicits
+            || Icmp6OutRouterSolicits
+            || Icmp6InRouterAdvertisements
+            || Icmp6OutRouterAdvertisements
+        ))) {
+        do_icmp_router = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InSolicits", Icmp6InRouterSolicits);
+        rrddim_set(st, "OutSolicits", Icmp6OutRouterSolicits);
+        rrddim_set(st, "InAdvertisements", Icmp6InRouterAdvertisements);
+        rrddim_set(st, "OutAdvertisements", Icmp6OutRouterAdvertisements);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InNeighborSolicits
+            || Icmp6OutNeighborSolicits
+            || Icmp6InNeighborAdvertisements
+            || Icmp6OutNeighborAdvertisements
+        ))) {
+        do_icmp_neighbor = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InSolicits", Icmp6InNeighborSolicits);
+        rrddim_set(st, "OutSolicits", Icmp6OutNeighborSolicits);
+        rrddim_set(st, "InAdvertisements", Icmp6InNeighborAdvertisements);
+        rrddim_set(st, "OutAdvertisements", Icmp6OutNeighborAdvertisements);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
+        do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "sent", Icmp6InMLDv2Reports);
+        rrddim_set(st, "received", Icmp6OutMLDv2Reports);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Icmp6InType1
+            || Icmp6InType128
+            || Icmp6InType129
+            || Icmp6InType136
+            || Icmp6OutType1
+            || Icmp6OutType128
+            || Icmp6OutType129
+            || Icmp6OutType133
+            || Icmp6OutType135
+            || Icmp6OutType143
+        ))) {
+        do_icmp_types = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InType1", Icmp6InType1);
+        rrddim_set(st, "InType128", Icmp6InType128);
+        rrddim_set(st, "InType129", Icmp6InType129);
+        rrddim_set(st, "InType136", Icmp6InType136);
+        rrddim_set(st, "OutType1", Icmp6OutType1);
+        rrddim_set(st, "OutType128", Icmp6OutType128);
+        rrddim_set(st, "OutType129", Icmp6OutType129);
+        rrddim_set(st, "OutType133", Icmp6OutType133);
+        rrddim_set(st, "OutType135", Icmp6OutType135);
+        rrddim_set(st, "OutType143", Icmp6OutType143);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
+        && (
+            Ip6InNoECTPkts
+            || Ip6InECT1Pkts
+            || Ip6InECT0Pkts
+            || Ip6InCEPkts
+        ))) {
+        do_ect = CONFIG_ONDEMAND_YES;
+        st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "InNoECTPkts", Ip6InNoECTPkts);
+        rrddim_set(st, "InECT1Pkts", Ip6InECT1Pkts);
+        rrddim_set(st, "InECT0Pkts", Ip6InECT0Pkts);
+        rrddim_set(st, "InCEPkts", Ip6InCEPkts);
+        rrdset_done(st);
+    }
+
+    return 0;
 }
 
index 3af66f19ff2534d4fe9dd3f7478006747c54d0d6..8234b20d28e7c4a19de12f9ded9386a4aae2f653 100644 (file)
 #include "common.h"
 
-#define RRD_TYPE_NET_STAT_NETFILTER            "netfilter"
-#define RRD_TYPE_NET_STAT_CONNTRACK    "conntrack"
-#define RRD_TYPE_NET_STAT_CONNTRACK_LEN        strlen(RRD_TYPE_NET_STAT_CONNTRACK)
+#define RRD_TYPE_NET_STAT_NETFILTER     "netfilter"
+#define RRD_TYPE_NET_STAT_CONNTRACK     "conntrack"
+#define RRD_TYPE_NET_STAT_CONNTRACK_LEN strlen(RRD_TYPE_NET_STAT_CONNTRACK)
 
 int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1;
-
-       if(do_sockets == -1)    do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", 1);
-       if(do_new == -1)                do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", 1);
-       if(do_changes == -1)    do_changes = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection changes", 1);
-       if(do_expect == -1)             do_expect = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection expectations", 1);
-       if(do_search == -1)             do_search = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection searches", 1);
-       if(do_errors == -1)             do_errors = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter errors", 1);
-
-       if(dt) {};
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       unsigned long long aentries = 0, asearched = 0, afound = 0, anew = 0, ainvalid = 0, aignore = 0, adelete = 0, adelete_list = 0,
-               ainsert = 0, ainsert_failed = 0, adrop = 0, aearly_drop = 0, aicmp_error = 0, aexpect_new = 0, aexpect_create = 0, aexpect_delete = 0, asearch_restart = 0;
-
-       for(l = 1; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(words < 17) {
-                       if(words) error("Cannot read /proc/net/stat/nf_conntrack line. Expected 17 params, read %u.", words);
-                       continue;
-               }
-
-               unsigned long long tentries = 0, tsearched = 0, tfound = 0, tnew = 0, tinvalid = 0, tignore = 0, tdelete = 0, tdelete_list = 0, tinsert = 0, tinsert_failed = 0, tdrop = 0, tearly_drop = 0, ticmp_error = 0, texpect_new = 0, texpect_create = 0, texpect_delete = 0, tsearch_restart = 0;
-
-               tentries                = strtoull(procfile_lineword(ff, l, 0), NULL, 16);
-               tsearched               = strtoull(procfile_lineword(ff, l, 1), NULL, 16);
-               tfound                  = strtoull(procfile_lineword(ff, l, 2), NULL, 16);
-               tnew                    = strtoull(procfile_lineword(ff, l, 3), NULL, 16);
-               tinvalid                = strtoull(procfile_lineword(ff, l, 4), NULL, 16);
-               tignore                 = strtoull(procfile_lineword(ff, l, 5), NULL, 16);
-               tdelete                 = strtoull(procfile_lineword(ff, l, 6), NULL, 16);
-               tdelete_list    = strtoull(procfile_lineword(ff, l, 7), NULL, 16);
-               tinsert                 = strtoull(procfile_lineword(ff, l, 8), NULL, 16);
-               tinsert_failed  = strtoull(procfile_lineword(ff, l, 9), NULL, 16);
-               tdrop                   = strtoull(procfile_lineword(ff, l, 10), NULL, 16);
-               tearly_drop             = strtoull(procfile_lineword(ff, l, 11), NULL, 16);
-               ticmp_error             = strtoull(procfile_lineword(ff, l, 12), NULL, 16);
-               texpect_new             = strtoull(procfile_lineword(ff, l, 13), NULL, 16);
-               texpect_create  = strtoull(procfile_lineword(ff, l, 14), NULL, 16);
-               texpect_delete  = strtoull(procfile_lineword(ff, l, 15), NULL, 16);
-               tsearch_restart = strtoull(procfile_lineword(ff, l, 16), NULL, 16);
-
-               if(!aentries) aentries =  tentries;
-
-               // sum all the cpus together
-               asearched                       += tsearched;           // conntrack.search
-               afound                          += tfound;                      // conntrack.search
-               anew                            += tnew;                        // conntrack.new
-               ainvalid                        += tinvalid;            // conntrack.new
-               aignore                         += tignore;                     // conntrack.new
-               adelete                         += tdelete;                     // conntrack.changes
-               adelete_list            += tdelete_list;        // conntrack.changes
-               ainsert                         += tinsert;                     // conntrack.changes
-               ainsert_failed          += tinsert_failed;      // conntrack.errors
-               adrop                           += tdrop;                       // conntrack.errors
-               aearly_drop             += tearly_drop;         // conntrack.errors
-               aicmp_error             += ticmp_error;         // conntrack.errors
-               aexpect_new             += texpect_new;         // conntrack.expect
-               aexpect_create          += texpect_create;      // conntrack.expect
-               aexpect_delete          += texpect_delete;      // conntrack.expect
-               asearch_restart         += tsearch_restart;     // conntrack.search
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       if(do_sockets) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "connections", aentries);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_new) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "new", anew);
-               rrddim_set(st, "ignore", aignore);
-               rrddim_set(st, "invalid", ainvalid);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_changes) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "inserted", ainsert);
-               rrddim_set(st, "deleted", adelete);
-               rrddim_set(st, "delete_list", adelete_list);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_expect) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "created", aexpect_create);
-               rrddim_set(st, "deleted", aexpect_delete);
-               rrddim_set(st, "new", aexpect_new);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_search) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "searched", asearched);
-               rrddim_set(st, "restarted", asearch_restart);
-               rrddim_set(st, "found", afound);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(do_errors) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "icmp_error", aicmp_error);
-               rrddim_set(st, "insert_failed", ainsert_failed);
-               rrddim_set(st, "drop", adrop);
-               rrddim_set(st, "early_drop", aearly_drop);
-               rrdset_done(st);
-       }
-
-       return 0;
+    static procfile *ff = NULL;
+    static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1;
+
+    if(do_sockets == -1)    do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", 1);
+    if(do_new == -1)        do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", 1);
+    if(do_changes == -1)    do_changes = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection changes", 1);
+    if(do_expect == -1)     do_expect = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection expectations", 1);
+    if(do_search == -1)     do_search = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection searches", 1);
+    if(do_errors == -1)     do_errors = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter errors", 1);
+
+    if(dt) {};
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    unsigned long long aentries = 0, asearched = 0, afound = 0, anew = 0, ainvalid = 0, aignore = 0, adelete = 0, adelete_list = 0,
+        ainsert = 0, ainsert_failed = 0, adrop = 0, aearly_drop = 0, aicmp_error = 0, aexpect_new = 0, aexpect_create = 0, aexpect_delete = 0, asearch_restart = 0;
+
+    for(l = 1; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(words < 17) {
+            if(words) error("Cannot read /proc/net/stat/nf_conntrack line. Expected 17 params, read %u.", words);
+            continue;
+        }
+
+        unsigned long long tentries = 0, tsearched = 0, tfound = 0, tnew = 0, tinvalid = 0, tignore = 0, tdelete = 0, tdelete_list = 0, tinsert = 0, tinsert_failed = 0, tdrop = 0, tearly_drop = 0, ticmp_error = 0, texpect_new = 0, texpect_create = 0, texpect_delete = 0, tsearch_restart = 0;
+
+        tentries        = strtoull(procfile_lineword(ff, l, 0), NULL, 16);
+        tsearched       = strtoull(procfile_lineword(ff, l, 1), NULL, 16);
+        tfound          = strtoull(procfile_lineword(ff, l, 2), NULL, 16);
+        tnew            = strtoull(procfile_lineword(ff, l, 3), NULL, 16);
+        tinvalid        = strtoull(procfile_lineword(ff, l, 4), NULL, 16);
+        tignore         = strtoull(procfile_lineword(ff, l, 5), NULL, 16);
+        tdelete         = strtoull(procfile_lineword(ff, l, 6), NULL, 16);
+        tdelete_list    = strtoull(procfile_lineword(ff, l, 7), NULL, 16);
+        tinsert         = strtoull(procfile_lineword(ff, l, 8), NULL, 16);
+        tinsert_failed  = strtoull(procfile_lineword(ff, l, 9), NULL, 16);
+        tdrop           = strtoull(procfile_lineword(ff, l, 10), NULL, 16);
+        tearly_drop     = strtoull(procfile_lineword(ff, l, 11), NULL, 16);
+        ticmp_error     = strtoull(procfile_lineword(ff, l, 12), NULL, 16);
+        texpect_new     = strtoull(procfile_lineword(ff, l, 13), NULL, 16);
+        texpect_create  = strtoull(procfile_lineword(ff, l, 14), NULL, 16);
+        texpect_delete  = strtoull(procfile_lineword(ff, l, 15), NULL, 16);
+        tsearch_restart = strtoull(procfile_lineword(ff, l, 16), NULL, 16);
+
+        if(!aentries) aentries =  tentries;
+
+        // sum all the cpus together
+        asearched           += tsearched;       // conntrack.search
+        afound              += tfound;          // conntrack.search
+        anew                += tnew;            // conntrack.new
+        ainvalid            += tinvalid;        // conntrack.new
+        aignore             += tignore;         // conntrack.new
+        adelete             += tdelete;         // conntrack.changes
+        adelete_list        += tdelete_list;    // conntrack.changes
+        ainsert             += tinsert;         // conntrack.changes
+        ainsert_failed      += tinsert_failed;  // conntrack.errors
+        adrop               += tdrop;           // conntrack.errors
+        aearly_drop         += tearly_drop;     // conntrack.errors
+        aicmp_error         += ticmp_error;     // conntrack.errors
+        aexpect_new         += texpect_new;     // conntrack.expect
+        aexpect_create      += texpect_create;  // conntrack.expect
+        aexpect_delete      += texpect_delete;  // conntrack.expect
+        asearch_restart     += tsearch_restart; // conntrack.search
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    if(do_sockets) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "connections", aentries);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_new) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "new", anew);
+        rrddim_set(st, "ignore", aignore);
+        rrddim_set(st, "invalid", ainvalid);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_changes) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "inserted", ainsert);
+        rrddim_set(st, "deleted", adelete);
+        rrddim_set(st, "delete_list", adelete_list);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_expect) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "created", aexpect_create);
+        rrddim_set(st, "deleted", aexpect_delete);
+        rrddim_set(st, "new", aexpect_new);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_search) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "searched", asearched);
+        rrddim_set(st, "restarted", asearch_restart);
+        rrddim_set(st, "found", afound);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(do_errors) {
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "icmp_error", aicmp_error);
+        rrddim_set(st, "insert_failed", ainsert_failed);
+        rrddim_set(st, "drop", adrop);
+        rrddim_set(st, "early_drop", aearly_drop);
+        rrdset_done(st);
+    }
+
+    return 0;
 }
index c3874eeeef6fb0092f59b040ad8fd0106cf40b99..758c35dee2b23fa302f109cfe5e48767e0698e8d 100644 (file)
 #include "common.h"
 
-#define RRD_TYPE_NET_STAT_NETFILTER                    "netfilter"
-#define RRD_TYPE_NET_STAT_SYNPROXY                     "synproxy"
-#define RRD_TYPE_NET_STAT_SYNPROXY_LEN         strlen(RRD_TYPE_NET_STAT_SYNPROXY)
+#define RRD_TYPE_NET_STAT_NETFILTER         "netfilter"
+#define RRD_TYPE_NET_STAT_SYNPROXY          "synproxy"
+#define RRD_TYPE_NET_STAT_SYNPROXY_LEN      strlen(RRD_TYPE_NET_STAT_SYNPROXY)
 
 int do_proc_net_stat_synproxy(int update_every, unsigned long long dt) {
-       static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
-       static procfile *ff = NULL;
+    static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
+    static procfile *ff = NULL;
 
-       if(do_entries == -1)    do_entries      = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_cookies == -1)    do_cookies      = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_syns == -1)               do_syns         = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
-       if(do_reopened == -1)   do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_entries == -1)    do_entries  = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_cookies == -1)    do_cookies  = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_syns == -1)       do_syns     = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
+    if(do_reopened == -1)   do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
 
-       if(dt) {};
+    if(dt) {};
 
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
-               ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
+        ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
-       // make sure we have 3 lines
-       size_t lines = procfile_lines(ff), l;
-       if(lines < 2) {
-               error("/proc/net/stat/synproxy has %zu lines, expected no less than 2. Disabling it.", lines);
-               return 1;
-       }
+    // make sure we have 3 lines
+    size_t lines = procfile_lines(ff), l;
+    if(lines < 2) {
+        error("/proc/net/stat/synproxy has %zu lines, expected no less than 2. Disabling it.", lines);
+        return 1;
+    }
 
-       unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
+    unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
 
-       // synproxy gives its values per CPU
-       for(l = 1; l < lines ;l++) {
-               int words = procfile_linewords(ff, l);
-               if(words < 6) continue;
+    // synproxy gives its values per CPU
+    for(l = 1; l < lines ;l++) {
+        int words = procfile_linewords(ff, l);
+        if(words < 6) continue;
 
-               entries                 += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
-               syn_received    += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
-               cookie_invalid  += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
-               cookie_valid    += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
-               cookie_retrans  += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
-               conn_reopened   += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
-       }
+        entries         += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
+        syn_received    += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
+        cookie_invalid  += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
+        cookie_valid    += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
+        cookie_retrans  += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
+        conn_reopened   += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
+    }
 
-       unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
+    unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
 
-       RRDSET *st;
+    RRDSET *st;
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
-               do_entries = CONFIG_ONDEMAND_YES;
+    if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
+        do_entries = CONFIG_ONDEMAND_YES;
 
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 1004, update_every, RRDSET_TYPE_LINE);
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 1004, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "entries", entries);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "entries", entries);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
-               do_syns = CONFIG_ONDEMAND_YES;
+    if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
+        do_syns = CONFIG_ONDEMAND_YES;
 
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 1001, update_every, RRDSET_TYPE_LINE);
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 1001, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "received", syn_received);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "received", syn_received);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
-               do_reopened = CONFIG_ONDEMAND_YES;
+    if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
+        do_reopened = CONFIG_ONDEMAND_YES;
 
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 1003, update_every, RRDSET_TYPE_LINE);
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 1003, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "reopened", conn_reopened);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "reopened", conn_reopened);
+        rrdset_done(st);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
-               do_cookies = CONFIG_ONDEMAND_YES;
+    if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
+        do_cookies = CONFIG_ONDEMAND_YES;
 
-               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
-               if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 1002, update_every, RRDSET_TYPE_LINE);
+        st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
+        if(!st) {
+            st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 1002, update_every, RRDSET_TYPE_LINE);
 
-                       rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
+            rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-               rrddim_set(st, "valid", cookie_valid);
-               rrddim_set(st, "invalid", cookie_invalid);
-               rrddim_set(st, "retransmits", cookie_retrans);
-               rrdset_done(st);
-       }
+        rrddim_set(st, "valid", cookie_valid);
+        rrddim_set(st, "invalid", cookie_invalid);
+        rrddim_set(st, "retransmits", cookie_retrans);
+        rrdset_done(st);
+    }
 
-       return 0;
+    return 0;
 }
index 623eb622a85c33e6f89d2241737830bd2a0542be..633565840dc6e2247d9f37d95e73a6c9e87936e1 100644 (file)
 // find the mount info with the given major:minor
 // in the supplied linked list of mountinfo structures
 struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) {
-       struct mountinfo *mi;
+    struct mountinfo *mi;
 
-       for(mi = root; mi ; mi = mi->next)
-               if(mi->major == major && mi->minor == minor)
-                       return mi;
+    for(mi = root; mi ; mi = mi->next)
+        if(mi->major == major && mi->minor == minor)
+            return mi;
 
-       return NULL;
+    return NULL;
 }
 
 // find the mount info with the given filesystem and mount_source
 // in the supplied linked list of mountinfo structures
 struct mountinfo *mountinfo_find_by_filesystem_mount_source(struct mountinfo *root, const char *filesystem, const char *mount_source) {
-       struct mountinfo *mi;
-       uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source);
-
-       for(mi = root; mi ; mi = mi->next)
-               if(mi->filesystem
-                               && mi->mount_source
-                               && mi->filesystem_hash == filesystem_hash
-                               && mi->mount_source_hash == mount_source_hash
-                               && !strcmp(mi->filesystem, filesystem)
-                               && !strcmp(mi->mount_source, mount_source))
-                       return mi;
-
-       return NULL;
+    struct mountinfo *mi;
+    uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source);
+
+    for(mi = root; mi ; mi = mi->next)
+        if(mi->filesystem
+                && mi->mount_source
+                && mi->filesystem_hash == filesystem_hash
+                && mi->mount_source_hash == mount_source_hash
+                && !strcmp(mi->filesystem, filesystem)
+                && !strcmp(mi->mount_source, mount_source))
+            return mi;
+
+    return NULL;
 }
 
 struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *root, const char *filesystem, const char *super_options) {
-       struct mountinfo *mi;
-       uint32_t filesystem_hash = simple_hash(filesystem);
+    struct mountinfo *mi;
+    uint32_t filesystem_hash = simple_hash(filesystem);
 
-       size_t solen = strlen(super_options);
+    size_t solen = strlen(super_options);
 
-       for(mi = root; mi ; mi = mi->next)
-               if(mi->filesystem
-                               && mi->super_options
-                               && mi->filesystem_hash == filesystem_hash
-                               && !strcmp(mi->filesystem, filesystem)) {
+    for(mi = root; mi ; mi = mi->next)
+        if(mi->filesystem
+                && mi->super_options
+                && mi->filesystem_hash == filesystem_hash
+                && !strcmp(mi->filesystem, filesystem)) {
 
-                       // super_options is a comma separated list
-                       char *s = mi->super_options, *e;
-                       while(*s) {
-                               e = s + 1;
-                               while(*e && *e != ',') e++;
+            // super_options is a comma separated list
+            char *s = mi->super_options, *e;
+            while(*s) {
+                e = s + 1;
+                while(*e && *e != ',') e++;
 
-                               size_t len = e - s;
-                               if(len == solen && !strncmp(s, super_options, len))
-                                       return mi;
+                size_t len = e - s;
+                if(len == solen && !strncmp(s, super_options, len))
+                    return mi;
 
-                               if(*e == ',') s = ++e;
-                               else s = e;
-                       }
-               }
+                if(*e == ',') s = ++e;
+                else s = e;
+            }
+        }
 
-       return NULL;
+    return NULL;
 }
 
 
 // free a linked list of mountinfo structures
 void mountinfo_free(struct mountinfo *mi) {
-       if(unlikely(!mi))
-               return;
+    if(unlikely(!mi))
+        return;
 
-       if(likely(mi->next))
-               mountinfo_free(mi->next);
+    if(likely(mi->next))
+        mountinfo_free(mi->next);
 
-       freez(mi->root);
-       freez(mi->mount_point);
-       freez(mi->mount_options);
+    freez(mi->root);
+    freez(mi->mount_point);
+    freez(mi->mount_options);
 
 /*
-       if(mi->optional_fields_count) {
-               int i;
-               for(i = 0; i < mi->optional_fields_count ; i++)
-                       free(*mi->optional_fields[i]);
-       }
-       free(mi->optional_fields);
+    if(mi->optional_fields_count) {
+        int i;
+        for(i = 0; i < mi->optional_fields_count ; i++)
+            free(*mi->optional_fields[i]);
+    }
+    free(mi->optional_fields);
 */
-       freez(mi->filesystem);
-       freez(mi->mount_source);
-       freez(mi->super_options);
-       freez(mi);
+    freez(mi->filesystem);
+    freez(mi->mount_source);
+    freez(mi->super_options);
+    freez(mi);
 }
 
 static char *strdupz_decoding_octal(const char *string) {
-       char *buffer = strdupz(string);
-
-       char *d = buffer;
-       const char *s = string;
-
-       while(*s) {
-               if(unlikely(*s == '\\')) {
-                       s++;
-                       if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) {
-                               char c = *s++ - '0';
-                               c <<= 3;
-                               c |= *s++ - '0';
-                               c <<= 3;
-                               c |= *s++ - '0';
-                               *d++ = c;
-                       }
-                       else *d++ = '_';
-               }
-               else *d++ = *s++;
-       }
-       *d = '\0';
-
-       return buffer;
+    char *buffer = strdupz(string);
+
+    char *d = buffer;
+    const char *s = string;
+
+    while(*s) {
+        if(unlikely(*s == '\\')) {
+            s++;
+            if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) {
+                char c = *s++ - '0';
+                c <<= 3;
+                c |= *s++ - '0';
+                c <<= 3;
+                c |= *s++ - '0';
+                *d++ = c;
+            }
+            else *d++ = '_';
+        }
+        else *d++ = *s++;
+    }
+    *d = '\0';
+
+    return buffer;
 }
 
 // read the whole mountinfo into a linked list
 struct mountinfo *mountinfo_read() {
-       procfile *ff = NULL;
+    procfile *ff = NULL;
 
-       char filename[FILENAME_MAX + 1];
-       snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
-       ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
-       if(!ff) {
-               snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
-               ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
-               if(!ff) return NULL;
-       }
+    char filename[FILENAME_MAX + 1];
+    snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
+    ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
+    if(!ff) {
+        snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
+        ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
+        if(!ff) return NULL;
+    }
 
-       ff = procfile_readall(ff);
-       if(!ff) return NULL;
+    ff = procfile_readall(ff);
+    if(!ff) return NULL;
 
-       struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
+    struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
 
-       unsigned long l, lines = procfile_lines(ff);
-       for(l = 0; l < lines ;l++) {
-               if(procfile_linewords(ff, l) < 5)
-                       continue;
+    unsigned long l, lines = procfile_lines(ff);
+    for(l = 0; l < lines ;l++) {
+        if(procfile_linewords(ff, l) < 5)
+            continue;
 
-               mi = mallocz(sizeof(struct mountinfo));
+        mi = mallocz(sizeof(struct mountinfo));
 
-               if(unlikely(!root))
-                       root = last = mi;
-               else
-                       last->next = mi;
+        if(unlikely(!root))
+            root = last = mi;
+        else
+            last->next = mi;
 
-               last = mi;
-               mi->next = NULL;
+        last = mi;
+        mi->next = NULL;
 
-               unsigned long w = 0;
-               mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
-               mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
+        unsigned long w = 0;
+        mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
+        mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
 
-               char *major = procfile_lineword(ff, l, w), *minor; w++;
-               for(minor = major; *minor && *minor != ':' ;minor++) ;
-               *minor = '\0';
-               minor++;
+        char *major = procfile_lineword(ff, l, w), *minor; w++;
+        for(minor = major; *minor && *minor != ':' ;minor++) ;
+        *minor = '\0';
+        minor++;
 
-               mi->major = strtoul(major, NULL, 10);
-               mi->minor = strtoul(minor, NULL, 10);
+        mi->major = strtoul(major, NULL, 10);
+        mi->minor = strtoul(minor, NULL, 10);
 
-               mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
-               mi->root_hash = simple_hash(mi->root);
+        mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
+        mi->root_hash = simple_hash(mi->root);
 
-               mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
-               mi->mount_point_hash = simple_hash(mi->mount_point);
+        mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
+        mi->mount_point_hash = simple_hash(mi->mount_point);
 
-               mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
+        mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
 
-               // count the optional fields
+        // count the optional fields
 /*
-               unsigned long wo = w;
+        unsigned long wo = w;
 */
-               mi->optional_fields_count = 0;
-               char *s = procfile_lineword(ff, l, w);
-               while(*s && *s != '-') {
-                       w++;
-                       s = procfile_lineword(ff, l, w);
-                       mi->optional_fields_count++;
-               }
+        mi->optional_fields_count = 0;
+        char *s = procfile_lineword(ff, l, w);
+        while(*s && *s != '-') {
+            w++;
+            s = procfile_lineword(ff, l, w);
+            mi->optional_fields_count++;
+        }
 
 /*
-               if(unlikely(mi->optional_fields_count)) {
-                       // we have some optional fields
-                       // read them into a new array of pointers;
-
-                       mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *));
-                       if(unlikely(!mi->optional_fields))
-                               fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count);
-
-                       int i;
-                       for(i = 0; i < mi->optional_fields_count ; i++) {
-                               *mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w));
-                               if(!mi->optional_fields[wo]) fatal("Cannot allocate memory");
-                               wo++;
-                       }
-               }
-               else
-                       mi->optional_fields = NULL;
+        if(unlikely(mi->optional_fields_count)) {
+            // we have some optional fields
+            // read them into a new array of pointers;
+
+            mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *));
+            if(unlikely(!mi->optional_fields))
+                fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count);
+
+            int i;
+            for(i = 0; i < mi->optional_fields_count ; i++) {
+                *mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w));
+                if(!mi->optional_fields[wo]) fatal("Cannot allocate memory");
+                wo++;
+            }
+        }
+        else
+            mi->optional_fields = NULL;
 */
 
-               if(likely(*s == '-')) {
-                       w++;
+        if(likely(*s == '-')) {
+            w++;
 
-                       mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
-                       mi->filesystem_hash = simple_hash(mi->filesystem);
+            mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
+            mi->filesystem_hash = simple_hash(mi->filesystem);
 
-                       mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
-                       mi->mount_source_hash = simple_hash(mi->mount_source);
+            mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
+            mi->mount_source_hash = simple_hash(mi->mount_source);
 
-                       mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
-               }
-               else {
-                       mi->filesystem = NULL;
-                       mi->mount_source = NULL;
-                       mi->super_options = NULL;
-               }
+            mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
+        }
+        else {
+            mi->filesystem = NULL;
+            mi->mount_source = NULL;
+            mi->super_options = NULL;
+        }
 
 /*
-               info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
-                    mi->id,
-                    mi->parentid,
-                    mi->major,
-                    mi->minor,
-                    mi->root,
-                    mi->mount_point,
-                    mi->mount_options,
-                    mi->filesystem,
-                    mi->mount_source,
-                    mi->super_options
-               );
+        info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
+             mi->id,
+             mi->parentid,
+             mi->major,
+             mi->minor,
+             mi->root,
+             mi->mount_point,
+             mi->mount_options,
+             mi->filesystem,
+             mi->mount_source,
+             mi->super_options
+        );
 */
-       }
+    }
 
-       procfile_close(ff);
-       return root;
+    procfile_close(ff);
+    return root;
 }
index af98ca4a58f0ad8d14a48049d9c8513843f8426f..c2d9688c19e836e221f7e0f445fc961abbad3b69 100644 (file)
@@ -2,32 +2,32 @@
 #define NETDATA_PROC_SELF_MOUNTINFO_H 1
 
 struct mountinfo {
-       long id;                // mount ID: unique identifier of the mount (may be reused after umount(2)).
-       long parentid;          // parent ID: ID of parent mount (or of self for the top of the mount tree).
-       unsigned long major;    // major:minor: value of st_dev for files on filesystem (see stat(2)).
-       unsigned long minor;
+    long id;                // mount ID: unique identifier of the mount (may be reused after umount(2)).
+    long parentid;          // parent ID: ID of parent mount (or of self for the top of the mount tree).
+    unsigned long major;    // major:minor: value of st_dev for files on filesystem (see stat(2)).
+    unsigned long minor;
 
-       char *root;             // root: root of the mount within the filesystem.
-       uint32_t root_hash;
+    char *root;             // root: root of the mount within the filesystem.
+    uint32_t root_hash;
 
-       char *mount_point;      // mount point: mount point relative to the process's root.
-       uint32_t mount_point_hash;
+    char *mount_point;      // mount point: mount point relative to the process's root.
+    uint32_t mount_point_hash;
 
-       char *mount_options;    // mount options: per-mount options.
+    char *mount_options;    // mount options: per-mount options.
 
-       int optional_fields_count;
+    int optional_fields_count;
 /*
-       char ***optional_fields; // optional fields: zero or more fields of the form "tag[:value]".
+    char ***optional_fields; // optional fields: zero or more fields of the form "tag[:value]".
 */
-       char *filesystem;       // filesystem type: name of filesystem in the form "type[.subtype]".
-       uint32_t filesystem_hash;
+    char *filesystem;       // filesystem type: name of filesystem in the form "type[.subtype]".
+    uint32_t filesystem_hash;
 
-       char *mount_source;     // mount source: filesystem-specific information or "none".
-       uint32_t mount_source_hash;
+    char *mount_source;     // mount source: filesystem-specific information or "none".
+    uint32_t mount_source_hash;
 
-       char *super_options;    // super options: per-superblock options.
+    char *super_options;    // super options: per-superblock options.
 
-       struct mountinfo *next;
+    struct mountinfo *next;
 };
 
 extern struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor);
index d966ab790f9b4b96757672dd8be05cdce393eef3..a5165040acecc9da79ba349c001c7a2729800bbc 100644 (file)
@@ -3,11 +3,11 @@
 #define MAX_INTERRUPT_NAME 50
 
 struct interrupt {
-       int used;
-       char *id;
-       char name[MAX_INTERRUPT_NAME + 1];
-       unsigned long long total;
-       unsigned long long value[];
+    int used;
+    char *id;
+    char name[MAX_INTERRUPT_NAME + 1];
+    unsigned long long total;
+    unsigned long long value[];
 };
 
 // since each interrupt is variable in size
@@ -18,157 +18,157 @@ struct interrupt {
 #define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
 
 static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
-       static struct interrupt *irrs = NULL;
-       static int allocated = 0;
+    static struct interrupt *irrs = NULL;
+    static int allocated = 0;
 
-       if(lines < allocated) return irrs;
-       else {
-               irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
-               allocated = lines;
-       }
+    if(lines < allocated) return irrs;
+    else {
+        irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
+        allocated = lines;
+    }
 
-       return irrs;
+    return irrs;
 }
 
 int do_proc_softirqs(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int cpus = -1, do_per_core = -1;
+    static procfile *ff = NULL;
+    static int cpus = -1, do_per_core = -1;
 
-       struct interrupt *irrs = NULL;
-
-       if(dt) {};
+    struct interrupt *irrs = NULL;
+
+    if(dt) {};
 
-       if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
-
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
-               ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
-
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words = procfile_linewords(ff, 0), w;
-
-       if(!lines) {
-               error("Cannot read /proc/softirqs, zero lines reported.");
-               return 1;
-       }
-
-       // find how many CPUs are there
-       if(cpus == -1) {
-               cpus = 0;
-               for(w = 0; w < words ; w++) {
-                       if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
-                               cpus++;
-               }
-       }
-
-       if(!cpus) {
-               error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs");
-               return 1;
-       }
-
-       // allocate the size we need;
-       irrs = get_interrupts_array(lines, cpus);
-       irrs[0].used = 0;
-
-       // loop through all lines
-       for(l = 1; l < lines ;l++) {
-               struct interrupt *irr = irrindex(irrs, l, cpus);
-               irr->used = 0;
-               irr->total = 0;
-
-               words = procfile_linewords(ff, l);
-               if(!words) continue;
-
-               irr->id = procfile_lineword(ff, l, 0);
-               if(!irr->id || !irr->id[0]) continue;
-
-               int idlen = strlen(irr->id);
-               if(irr->id[idlen - 1] == ':')
-                       irr->id[idlen - 1] = '\0';
-
-               int c;
-               for(c = 0; c < cpus ;c++) {
-                       if((c + 1) < (int)words)
-                               irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
-                       else
-                               irr->value[c] = 0;
-
-                       irr->total += irr->value[c];
-               }
-
-               strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
-
-               irr->used = 1;
-       }
-
-       RRDSET *st;
-
-       // --------------------------------------------------------------------
-
-       st = rrdset_find_bytype("system", "softirqs");
-       if(!st) {
-               st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
-
-               for(l = 0; l < lines ;l++) {
-                       struct interrupt *irr = irrindex(irrs, l, cpus);
-                       if(!irr->used) continue;
-                       rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
-               }
-       }
-       else rrdset_next(st);
-
-       for(l = 0; l < lines ;l++) {
-               struct interrupt *irr = irrindex(irrs, l, cpus);
-               if(!irr->used) continue;
-               rrddim_set(st, irr->id, irr->total);
-       }
-       rrdset_done(st);
-
-       if(do_per_core) {
-               int c;
-
-               for(c = 0; c < cpus ; c++) {
-                       char id[256+1];
-                       snprintfz(id, 256, "cpu%d_softirqs", c);
-
-                       st = rrdset_find_bytype("cpu", id);
-                       if(!st) {
-                               // find if everything is zero
-                               unsigned long long core_sum = 0 ;
-                               for(l = 0; l < lines ;l++) {
-                                       struct interrupt *irr = irrindex(irrs, l, cpus);
-                                       if(!irr->used) continue;
-                                       core_sum += irr->value[c];
-                               }
-                               if(core_sum == 0) continue; // try next core
-
-                               char name[256+1], title[256+1];
-                               snprintfz(name, 256, "cpu%d_softirqs", c);
-                               snprintfz(title, 256, "CPU%d softirqs", c);
-                               st = rrdset_create("cpu", id, name, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
-
-                               for(l = 0; l < lines ;l++) {
-                                       struct interrupt *irr = irrindex(irrs, l, cpus);
-                                       if(!irr->used) continue;
-                                       rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                       }
-                       else rrdset_next(st);
-
-                       for(l = 0; l < lines ;l++) {
-                               struct interrupt *irr = irrindex(irrs, l, cpus);
-                               if(!irr->used) continue;
-                               rrddim_set(st, irr->id, irr->value[c]);
-                       }
-                       rrdset_done(st);
-               }
-       }
-
-       return 0;
+    if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
+
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
+        ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
+
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words = procfile_linewords(ff, 0), w;
+
+    if(!lines) {
+        error("Cannot read /proc/softirqs, zero lines reported.");
+        return 1;
+    }
+
+    // find how many CPUs are there
+    if(cpus == -1) {
+        cpus = 0;
+        for(w = 0; w < words ; w++) {
+            if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
+                cpus++;
+        }
+    }
+
+    if(!cpus) {
+        error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs");
+        return 1;
+    }
+
+    // allocate the size we need;
+    irrs = get_interrupts_array(lines, cpus);
+    irrs[0].used = 0;
+
+    // loop through all lines
+    for(l = 1; l < lines ;l++) {
+        struct interrupt *irr = irrindex(irrs, l, cpus);
+        irr->used = 0;
+        irr->total = 0;
+
+        words = procfile_linewords(ff, l);
+        if(!words) continue;
+
+        irr->id = procfile_lineword(ff, l, 0);
+        if(!irr->id || !irr->id[0]) continue;
+
+        int idlen = strlen(irr->id);
+        if(irr->id[idlen - 1] == ':')
+            irr->id[idlen - 1] = '\0';
+
+        int c;
+        for(c = 0; c < cpus ;c++) {
+            if((c + 1) < (int)words)
+                irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
+            else
+                irr->value[c] = 0;
+
+            irr->total += irr->value[c];
+        }
+
+        strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
+
+        irr->used = 1;
+    }
+
+    RRDSET *st;
+
+    // --------------------------------------------------------------------
+
+    st = rrdset_find_bytype("system", "softirqs");
+    if(!st) {
+        st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
+
+        for(l = 0; l < lines ;l++) {
+            struct interrupt *irr = irrindex(irrs, l, cpus);
+            if(!irr->used) continue;
+            rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+        }
+    }
+    else rrdset_next(st);
+
+    for(l = 0; l < lines ;l++) {
+        struct interrupt *irr = irrindex(irrs, l, cpus);
+        if(!irr->used) continue;
+        rrddim_set(st, irr->id, irr->total);
+    }
+    rrdset_done(st);
+
+    if(do_per_core) {
+        int c;
+
+        for(c = 0; c < cpus ; c++) {
+            char id[256+1];
+            snprintfz(id, 256, "cpu%d_softirqs", c);
+
+            st = rrdset_find_bytype("cpu", id);
+            if(!st) {
+                // find if everything is zero
+                unsigned long long core_sum = 0 ;
+                for(l = 0; l < lines ;l++) {
+                    struct interrupt *irr = irrindex(irrs, l, cpus);
+                    if(!irr->used) continue;
+                    core_sum += irr->value[c];
+                }
+                if(core_sum == 0) continue; // try next core
+
+                char name[256+1], title[256+1];
+                snprintfz(name, 256, "cpu%d_softirqs", c);
+                snprintfz(title, 256, "CPU%d softirqs", c);
+                st = rrdset_create("cpu", id, name, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
+
+                for(l = 0; l < lines ;l++) {
+                    struct interrupt *irr = irrindex(irrs, l, cpus);
+                    if(!irr->used) continue;
+                    rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
+                }
+            }
+            else rrdset_next(st);
+
+            for(l = 0; l < lines ;l++) {
+                struct interrupt *irr = irrindex(irrs, l, cpus);
+                if(!irr->used) continue;
+                rrddim_set(st, irr->id, irr->value[c]);
+            }
+            rrdset_done(st);
+        }
+    }
+
+    return 0;
 }
index 9450f38190edb3afaf80faf223bd164adedf24db..88cb820b38d16f5808dc4a7967efa87c39f13af8 100644 (file)
 #include "common.h"
 
 int do_proc_stat(int update_every, unsigned long long dt) {
-       (void)dt;
-
-       static procfile *ff = NULL;
-       static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
-       static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
-
-       if(unlikely(do_cpu == -1)) {
-               do_cpu                  = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
-               do_cpu_cores    = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
-               do_interrupts   = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
-               do_context              = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
-               do_forks                = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
-               do_processes    = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
-
-               hash_intr = simple_hash("intr");
-               hash_ctxt = simple_hash("ctxt");
-               hash_processes = simple_hash("processes");
-               hash_procs_running = simple_hash("procs_running");
-               hash_procs_blocked = simple_hash("procs_blocked");
-       }
-
-       if(unlikely(!ff)) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
-               ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-               if(unlikely(!ff)) return 1;
-       }
-
-       ff = procfile_readall(ff);
-       if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
-
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
-
-       unsigned long long processes = 0, running = 0 , blocked = 0;
-       RRDSET *st;
-
-       for(l = 0; l < lines ;l++) {
-               char *row_key = procfile_lineword(ff, l, 0);
-               uint32_t hash = simple_hash(row_key);
-
-               // faster strncmp(row_key, "cpu", 3) == 0
-               if(likely(row_key[0] == 'c' && row_key[1] == 'p' && row_key[2] == 'u')) {
-                       words = procfile_linewords(ff, l);
-                       if(unlikely(words < 9)) {
-                               error("Cannot read /proc/stat cpu line. Expected 9 params, read %u.", words);
-                               continue;
-                       }
-
-                       char *id;
-                       unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
-
-                       id                      = row_key;
-                       user            = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-                       nice            = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-                       system          = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-                       idle            = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-                       iowait          = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-                       irq                     = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-                       softirq         = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-                       steal           = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-
-                       guest           = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-                       user -= guest;
-
-                       guest_nice      = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-                       nice -= guest_nice;
-
-                       char *title, *type, *context, *family;
-                       long priority;
-                       int isthistotal;
-
-                       if(unlikely(strcmp(id, "cpu")) == 0) {
-                               title = "Total CPU utilization";
-                               type = "system";
-                               context = "system.cpu";
-                               family = id;
-                               priority = 100;
-                               isthistotal = 1;
-                       }
-                       else {
-                               title = "Core utilization";
-                               type = "cpu";
-                               context = "cpu.cpu";
-                               family = "utilization";
-                               priority = 1000;
-                               isthistotal = 0;
-                       }
-
-                       if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
-                               st = rrdset_find_bytype(type, id);
-                               if(unlikely(!st)) {
-                                       st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
-
-                                       long multiplier = 1;
-                                       long divisor = 1; // sysconf(_SC_CLK_TCK);
-
-                                       rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-
-                                       rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-                                       rrddim_hide(st, "idle");
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "user", user);
-                               rrddim_set(st, "nice", nice);
-                               rrddim_set(st, "system", system);
-                               rrddim_set(st, "idle", idle);
-                               rrddim_set(st, "iowait", iowait);
-                               rrddim_set(st, "irq", irq);
-                               rrddim_set(st, "softirq", softirq);
-                               rrddim_set(st, "steal", steal);
-                               rrddim_set(st, "guest", guest);
-                               rrddim_set(st, "guest_nice", guest_nice);
-                               rrdset_done(st);
-                       }
-               }
-               else if(hash == hash_intr && strcmp(row_key, "intr") == 0) {
-                       unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-
-                       // --------------------------------------------------------------------
-
-                       if(likely(do_interrupts)) {
-                               st = rrdset_find_bytype("system", "intr");
-                               if(unlikely(!st)) {
-                                       st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
-                                       st->isdetail = 1;
-
-                                       rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "interrupts", value);
-                               rrdset_done(st);
-                       }
-               }
-               else if(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0) {
-                       unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-
-                       // --------------------------------------------------------------------
-
-                       if(likely(do_context)) {
-                               st = rrdset_find_bytype("system", "ctxt");
-                               if(unlikely(!st)) {
-                                       st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "switches", value);
-                               rrdset_done(st);
-                       }
-               }
-               else if(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0) {
-                       processes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-               }
-               else if(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0) {
-                       running = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-               }
-               else if(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0) {
-                       blocked = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-               }
-       }
-
-       // --------------------------------------------------------------------
-
-       if(likely(do_forks)) {
-               st = rrdset_find_bytype("system", "forks");
-               if(unlikely(!st)) {
-                       st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
-                       st->isdetail = 1;
-
-                       rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "started", processes);
-               rrdset_done(st);
-       }
-
-       // --------------------------------------------------------------------
-
-       if(likely(do_processes)) {
-               st = rrdset_find_bytype("system", "processes");
-               if(unlikely(!st)) {
-                       st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
-
-                       rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                       rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
-               }
-               else rrdset_next(st);
-
-               rrddim_set(st, "running", running);
-               rrddim_set(st, "blocked", blocked);
-               rrdset_done(st);
-       }
-
-       return 0;
+    (void)dt;
+
+    static procfile *ff = NULL;
+    static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
+    static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
+
+    if(unlikely(do_cpu == -1)) {
+        do_cpu          = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
+        do_cpu_cores    = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
+        do_interrupts   = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
+        do_context      = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
+        do_forks        = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
+        do_processes    = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
+
+        hash_intr = simple_hash("intr");
+        hash_ctxt = simple_hash("ctxt");
+        hash_processes = simple_hash("processes");
+        hash_procs_running = simple_hash("procs_running");
+        hash_procs_blocked = simple_hash("procs_blocked");
+    }
+
+    if(unlikely(!ff)) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
+        ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+        if(unlikely(!ff)) return 1;
+    }
+
+    ff = procfile_readall(ff);
+    if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
+
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
+
+    unsigned long long processes = 0, running = 0 , blocked = 0;
+    RRDSET *st;
+
+    for(l = 0; l < lines ;l++) {
+        char *row_key = procfile_lineword(ff, l, 0);
+        uint32_t hash = simple_hash(row_key);
+
+        // faster strncmp(row_key, "cpu", 3) == 0
+        if(likely(row_key[0] == 'c' && row_key[1] == 'p' && row_key[2] == 'u')) {
+            words = procfile_linewords(ff, l);
+            if(unlikely(words < 9)) {
+                error("Cannot read /proc/stat cpu line. Expected 9 params, read %u.", words);
+                continue;
+            }
+
+            char *id;
+            unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
+
+            id          = row_key;
+            user        = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+            nice        = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+            system      = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+            idle        = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+            iowait      = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+            irq         = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            softirq     = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+            steal       = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+
+            guest       = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+            user -= guest;
+
+            guest_nice  = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+            nice -= guest_nice;
+
+            char *title, *type, *context, *family;
+            long priority;
+            int isthistotal;
+
+            if(unlikely(strcmp(id, "cpu")) == 0) {
+                title = "Total CPU utilization";
+                type = "system";
+                context = "system.cpu";
+                family = id;
+                priority = 100;
+                isthistotal = 1;
+            }
+            else {
+                title = "Core utilization";
+                type = "cpu";
+                context = "cpu.cpu";
+                family = "utilization";
+                priority = 1000;
+                isthistotal = 0;
+            }
+
+            if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
+                st = rrdset_find_bytype(type, id);
+                if(unlikely(!st)) {
+                    st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
+
+                    long multiplier = 1;
+                    long divisor = 1; // sysconf(_SC_CLK_TCK);
+
+                    rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+
+                    rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_hide(st, "idle");
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "user", user);
+                rrddim_set(st, "nice", nice);
+                rrddim_set(st, "system", system);
+                rrddim_set(st, "idle", idle);
+                rrddim_set(st, "iowait", iowait);
+                rrddim_set(st, "irq", irq);
+                rrddim_set(st, "softirq", softirq);
+                rrddim_set(st, "steal", steal);
+                rrddim_set(st, "guest", guest);
+                rrddim_set(st, "guest_nice", guest_nice);
+                rrdset_done(st);
+            }
+        }
+        else if(hash == hash_intr && strcmp(row_key, "intr") == 0) {
+            unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+
+            // --------------------------------------------------------------------
+
+            if(likely(do_interrupts)) {
+                st = rrdset_find_bytype("system", "intr");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "interrupts", value);
+                rrdset_done(st);
+            }
+        }
+        else if(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0) {
+            unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+
+            // --------------------------------------------------------------------
+
+            if(likely(do_context)) {
+                st = rrdset_find_bytype("system", "ctxt");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "switches", value);
+                rrdset_done(st);
+            }
+        }
+        else if(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0) {
+            processes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        }
+        else if(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0) {
+            running = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        }
+        else if(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0) {
+            blocked = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_forks)) {
+        st = rrdset_find_bytype("system", "forks");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "started", processes);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_processes)) {
+        st = rrdset_find_bytype("system", "processes");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "running", running);
+        rrddim_set(st, "blocked", blocked);
+        rrdset_done(st);
+    }
+
+    return 0;
 }
index a08f494cd6461c730c68f20d19e508d24a6f8037..9515dad61693cf31d5372a7e160da1f55fcf2788 100644 (file)
@@ -1,31 +1,31 @@
 #include "common.h"
 
 int do_proc_sys_kernel_random_entropy_avail(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
+    static procfile *ff = NULL;
 
-       if(dt) {} ;
+    if(dt) {} ;
 
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
-               ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
+        ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
-       unsigned long long entropy = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
+    unsigned long long entropy = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
 
-       RRDSET *st = rrdset_find_bytype("system", "entropy");
-       if(!st) {
-               st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
-               rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(st);
+    RRDSET *st = rrdset_find_bytype("system", "entropy");
+    if(!st) {
+        st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
+        rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(st);
 
-       rrddim_set(st, "entropy", entropy);
-       rrdset_done(st);
+    rrddim_set(st, "entropy", entropy);
+    rrdset_done(st);
 
-       return 0;
+    return 0;
 }
index dcddb14db9c4e7d170af53537dc1fc154e328fef..f25d50c50b4ff1c8674a426403471d9c6cfaeb90 100644 (file)
 #include "common.h"
 
 int do_proc_vmstat(int update_every, unsigned long long dt) {
-       static procfile *ff = NULL;
-       static int do_swapio = -1, do_io = -1, do_pgfaults = -1, gen_hashes = -1;
+    static procfile *ff = NULL;
+    static int do_swapio = -1, do_io = -1, do_pgfaults = -1, gen_hashes = -1;
 
-       // static uint32_t hash_allocstall = -1;
-       // static uint32_t hash_compact_blocks_moved = -1;
-       // static uint32_t hash_compact_fail = -1;
-       // static uint32_t hash_compact_pagemigrate_failed = -1;
-       // static uint32_t hash_compact_pages_moved = -1;
-       // static uint32_t hash_compact_stall = -1;
-       // static uint32_t hash_compact_success = -1;
-       // static uint32_t hash_htlb_buddy_alloc_fail = -1;
-       // static uint32_t hash_htlb_buddy_alloc_success = -1;
-       // static uint32_t hash_kswapd_high_wmark_hit_quickly = -1;
-       // static uint32_t hash_kswapd_inodesteal = -1;
-       // static uint32_t hash_kswapd_low_wmark_hit_quickly = -1;
-       // static uint32_t hash_kswapd_skip_congestion_wait = -1;
-       // static uint32_t hash_nr_active_anon = -1;
-       // static uint32_t hash_nr_active_file = -1;
-       // static uint32_t hash_nr_anon_pages = -1;
-       // static uint32_t hash_nr_anon_transparent_hugepages = -1;
-       // static uint32_t hash_nr_bounce = -1;
-       // static uint32_t hash_nr_dirtied = -1;
-       // static uint32_t hash_nr_dirty = -1;
-       // static uint32_t hash_nr_dirty_background_threshold = -1;
-       // static uint32_t hash_nr_dirty_threshold = -1;
-       // static uint32_t hash_nr_file_pages = -1;
-       // static uint32_t hash_nr_free_pages = -1;
-       // static uint32_t hash_nr_inactive_anon = -1;
-       // static uint32_t hash_nr_inactive_file = -1;
-       // static uint32_t hash_nr_isolated_anon = -1;
-       // static uint32_t hash_nr_isolated_file = -1;
-       // static uint32_t hash_nr_kernel_stack = -1;
-       // static uint32_t hash_nr_mapped = -1;
-       // static uint32_t hash_nr_mlock = -1;
-       // static uint32_t hash_nr_page_table_pages = -1;
-       // static uint32_t hash_nr_shmem = -1;
-       // static uint32_t hash_nr_slab_reclaimable = -1;
-       // static uint32_t hash_nr_slab_unreclaimable = -1;
-       // static uint32_t hash_nr_unevictable = -1;
-       // static uint32_t hash_nr_unstable = -1;
-       // static uint32_t hash_nr_vmscan_immediate_reclaim = -1;
-       // static uint32_t hash_nr_vmscan_write = -1;
-       // static uint32_t hash_nr_writeback = -1;
-       // static uint32_t hash_nr_writeback_temp = -1;
-       // static uint32_t hash_nr_written = -1;
-       // static uint32_t hash_pageoutrun = -1;
-       // static uint32_t hash_pgactivate = -1;
-       // static uint32_t hash_pgalloc_dma = -1;
-       // static uint32_t hash_pgalloc_dma32 = -1;
-       // static uint32_t hash_pgalloc_movable = -1;
-       // static uint32_t hash_pgalloc_normal = -1;
-       // static uint32_t hash_pgdeactivate = -1;
-       static uint32_t hash_pgfault = -1;
-       // static uint32_t hash_pgfree = -1;
-       // static uint32_t hash_pginodesteal = -1;
-       static uint32_t hash_pgmajfault = -1;
-       static uint32_t hash_pgpgin = -1;
-       static uint32_t hash_pgpgout = -1;
-       // static uint32_t hash_pgrefill_dma = -1;
-       // static uint32_t hash_pgrefill_dma32 = -1;
-       // static uint32_t hash_pgrefill_movable = -1;
-       // static uint32_t hash_pgrefill_normal = -1;
-       // static uint32_t hash_pgrotated = -1;
-       // static uint32_t hash_pgscan_direct_dma = -1;
-       // static uint32_t hash_pgscan_direct_dma32 = -1;
-       // static uint32_t hash_pgscan_direct_movable = -1;
-       // static uint32_t hash_pgscan_direct_normal = -1;
-       // static uint32_t hash_pgscan_kswapd_dma = -1;
-       // static uint32_t hash_pgscan_kswapd_dma32 = -1;
-       // static uint32_t hash_pgscan_kswapd_movable = -1;
-       // static uint32_t hash_pgscan_kswapd_normal = -1;
-       // static uint32_t hash_pgsteal_direct_dma = -1;
-       // static uint32_t hash_pgsteal_direct_dma32 = -1;
-       // static uint32_t hash_pgsteal_direct_movable = -1;
-       // static uint32_t hash_pgsteal_direct_normal = -1;
-       // static uint32_t hash_pgsteal_kswapd_dma = -1;
-       // static uint32_t hash_pgsteal_kswapd_dma32 = -1;
-       // static uint32_t hash_pgsteal_kswapd_movable = -1;
-       // static uint32_t hash_pgsteal_kswapd_normal = -1;
-       static uint32_t hash_pswpin = -1;
-       static uint32_t hash_pswpout = -1;
-       // static uint32_t hash_slabs_scanned = -1;
-       // static uint32_t hash_thp_collapse_alloc = -1;
-       // static uint32_t hash_thp_collapse_alloc_failed = -1;
-       // static uint32_t hash_thp_fault_alloc = -1;
-       // static uint32_t hash_thp_fault_fallback = -1;
-       // static uint32_t hash_thp_split = -1;
-       // static uint32_t hash_unevictable_pgs_cleared = -1;
-       // static uint32_t hash_unevictable_pgs_culled = -1;
-       // static uint32_t hash_unevictable_pgs_mlocked = -1;
-       // static uint32_t hash_unevictable_pgs_mlockfreed = -1;
-       // static uint32_t hash_unevictable_pgs_munlocked = -1;
-       // static uint32_t hash_unevictable_pgs_rescued = -1;
-       // static uint32_t hash_unevictable_pgs_scanned = -1;
-       // static uint32_t hash_unevictable_pgs_stranded = -1;
+    // static uint32_t hash_allocstall = -1;
+    // static uint32_t hash_compact_blocks_moved = -1;
+    // static uint32_t hash_compact_fail = -1;
+    // static uint32_t hash_compact_pagemigrate_failed = -1;
+    // static uint32_t hash_compact_pages_moved = -1;
+    // static uint32_t hash_compact_stall = -1;
+    // static uint32_t hash_compact_success = -1;
+    // static uint32_t hash_htlb_buddy_alloc_fail = -1;
+    // static uint32_t hash_htlb_buddy_alloc_success = -1;
+    // static uint32_t hash_kswapd_high_wmark_hit_quickly = -1;
+    // static uint32_t hash_kswapd_inodesteal = -1;
+    // static uint32_t hash_kswapd_low_wmark_hit_quickly = -1;
+    // static uint32_t hash_kswapd_skip_congestion_wait = -1;
+    // static uint32_t hash_nr_active_anon = -1;
+    // static uint32_t hash_nr_active_file = -1;
+    // static uint32_t hash_nr_anon_pages = -1;
+    // static uint32_t hash_nr_anon_transparent_hugepages = -1;
+    // static uint32_t hash_nr_bounce = -1;
+    // static uint32_t hash_nr_dirtied = -1;
+    // static uint32_t hash_nr_dirty = -1;
+    // static uint32_t hash_nr_dirty_background_threshold = -1;
+    // static uint32_t hash_nr_dirty_threshold = -1;
+    // static uint32_t hash_nr_file_pages = -1;
+    // static uint32_t hash_nr_free_pages = -1;
+    // static uint32_t hash_nr_inactive_anon = -1;
+    // static uint32_t hash_nr_inactive_file = -1;
+    // static uint32_t hash_nr_isolated_anon = -1;
+    // static uint32_t hash_nr_isolated_file = -1;
+    // static uint32_t hash_nr_kernel_stack = -1;
+    // static uint32_t hash_nr_mapped = -1;
+    // static uint32_t hash_nr_mlock = -1;
+    // static uint32_t hash_nr_page_table_pages = -1;
+    // static uint32_t hash_nr_shmem = -1;
+    // static uint32_t hash_nr_slab_reclaimable = -1;
+    // static uint32_t hash_nr_slab_unreclaimable = -1;
+    // static uint32_t hash_nr_unevictable = -1;
+    // static uint32_t hash_nr_unstable = -1;
+    // static uint32_t hash_nr_vmscan_immediate_reclaim = -1;
+    // static uint32_t hash_nr_vmscan_write = -1;
+    // static uint32_t hash_nr_writeback = -1;
+    // static uint32_t hash_nr_writeback_temp = -1;
+    // static uint32_t hash_nr_written = -1;
+    // static uint32_t hash_pageoutrun = -1;
+    // static uint32_t hash_pgactivate = -1;
+    // static uint32_t hash_pgalloc_dma = -1;
+    // static uint32_t hash_pgalloc_dma32 = -1;
+    // static uint32_t hash_pgalloc_movable = -1;
+    // static uint32_t hash_pgalloc_normal = -1;
+    // static uint32_t hash_pgdeactivate = -1;
+    static uint32_t hash_pgfault = -1;
+    // static uint32_t hash_pgfree = -1;
+    // static uint32_t hash_pginodesteal = -1;
+    static uint32_t hash_pgmajfault = -1;
+    static uint32_t hash_pgpgin = -1;
+    static uint32_t hash_pgpgout = -1;
+    // static uint32_t hash_pgrefill_dma = -1;
+    // static uint32_t hash_pgrefill_dma32 = -1;
+    // static uint32_t hash_pgrefill_movable = -1;
+    // static uint32_t hash_pgrefill_normal = -1;
+    // static uint32_t hash_pgrotated = -1;
+    // static uint32_t hash_pgscan_direct_dma = -1;
+    // static uint32_t hash_pgscan_direct_dma32 = -1;
+    // static uint32_t hash_pgscan_direct_movable = -1;
+    // static uint32_t hash_pgscan_direct_normal = -1;
+    // static uint32_t hash_pgscan_kswapd_dma = -1;
+    // static uint32_t hash_pgscan_kswapd_dma32 = -1;
+    // static uint32_t hash_pgscan_kswapd_movable = -1;
+    // static uint32_t hash_pgscan_kswapd_normal = -1;
+    // static uint32_t hash_pgsteal_direct_dma = -1;
+    // static uint32_t hash_pgsteal_direct_dma32 = -1;
+    // static uint32_t hash_pgsteal_direct_movable = -1;
+    // static uint32_t hash_pgsteal_direct_normal = -1;
+    // static uint32_t hash_pgsteal_kswapd_dma = -1;
+    // static uint32_t hash_pgsteal_kswapd_dma32 = -1;
+    // static uint32_t hash_pgsteal_kswapd_movable = -1;
+    // static uint32_t hash_pgsteal_kswapd_normal = -1;
+    static uint32_t hash_pswpin = -1;
+    static uint32_t hash_pswpout = -1;
+    // static uint32_t hash_slabs_scanned = -1;
+    // static uint32_t hash_thp_collapse_alloc = -1;
+    // static uint32_t hash_thp_collapse_alloc_failed = -1;
+    // static uint32_t hash_thp_fault_alloc = -1;
+    // static uint32_t hash_thp_fault_fallback = -1;
+    // static uint32_t hash_thp_split = -1;
+    // static uint32_t hash_unevictable_pgs_cleared = -1;
+    // static uint32_t hash_unevictable_pgs_culled = -1;
+    // static uint32_t hash_unevictable_pgs_mlocked = -1;
+    // static uint32_t hash_unevictable_pgs_mlockfreed = -1;
+    // static uint32_t hash_unevictable_pgs_munlocked = -1;
+    // static uint32_t hash_unevictable_pgs_rescued = -1;
+    // static uint32_t hash_unevictable_pgs_scanned = -1;
+    // static uint32_t hash_unevictable_pgs_stranded = -1;
 
-       if(gen_hashes != 1) {
-               gen_hashes = 1;
-               // hash_allocstall = simple_hash("allocstall");
-               // hash_compact_blocks_moved = simple_hash("compact_blocks_moved");
-               // hash_compact_fail = simple_hash("compact_fail");
-               // hash_compact_pagemigrate_failed = simple_hash("compact_pagemigrate_failed");
-               // hash_compact_pages_moved = simple_hash("compact_pages_moved");
-               // hash_compact_stall = simple_hash("compact_stall");
-               // hash_compact_success = simple_hash("compact_success");
-               // hash_htlb_buddy_alloc_fail = simple_hash("htlb_buddy_alloc_fail");
-               // hash_htlb_buddy_alloc_success = simple_hash("htlb_buddy_alloc_success");
-               // hash_kswapd_high_wmark_hit_quickly = simple_hash("kswapd_high_wmark_hit_quickly");
-               // hash_kswapd_inodesteal = simple_hash("kswapd_inodesteal");
-               // hash_kswapd_low_wmark_hit_quickly = simple_hash("kswapd_low_wmark_hit_quickly");
-               // hash_kswapd_skip_congestion_wait = simple_hash("kswapd_skip_congestion_wait");
-               // hash_nr_active_anon = simple_hash("nr_active_anon");
-               // hash_nr_active_file = simple_hash("nr_active_file");
-               // hash_nr_anon_pages = simple_hash("nr_anon_pages");
-               // hash_nr_anon_transparent_hugepages = simple_hash("nr_anon_transparent_hugepages");
-               // hash_nr_bounce = simple_hash("nr_bounce");
-               // hash_nr_dirtied = simple_hash("nr_dirtied");
-               // hash_nr_dirty = simple_hash("nr_dirty");
-               // hash_nr_dirty_background_threshold = simple_hash("nr_dirty_background_threshold");
-               // hash_nr_dirty_threshold = simple_hash("nr_dirty_threshold");
-               // hash_nr_file_pages = simple_hash("nr_file_pages");
-               // hash_nr_free_pages = simple_hash("nr_free_pages");
-               // hash_nr_inactive_anon = simple_hash("nr_inactive_anon");
-               // hash_nr_inactive_file = simple_hash("nr_inactive_file");
-               // hash_nr_isolated_anon = simple_hash("nr_isolated_anon");
-               // hash_nr_isolated_file = simple_hash("nr_isolated_file");
-               // hash_nr_kernel_stack = simple_hash("nr_kernel_stack");
-               // hash_nr_mapped = simple_hash("nr_mapped");
-               // hash_nr_mlock = simple_hash("nr_mlock");
-               // hash_nr_page_table_pages = simple_hash("nr_page_table_pages");
-               // hash_nr_shmem = simple_hash("nr_shmem");
-               // hash_nr_slab_reclaimable = simple_hash("nr_slab_reclaimable");
-               // hash_nr_slab_unreclaimable = simple_hash("nr_slab_unreclaimable");
-               // hash_nr_unevictable = simple_hash("nr_unevictable");
-               // hash_nr_unstable = simple_hash("nr_unstable");
-               // hash_nr_vmscan_immediate_reclaim = simple_hash("nr_vmscan_immediate_reclaim");
-               // hash_nr_vmscan_write = simple_hash("nr_vmscan_write");
-               // hash_nr_writeback = simple_hash("nr_writeback");
-               // hash_nr_writeback_temp = simple_hash("nr_writeback_temp");
-               // hash_nr_written = simple_hash("nr_written");
-               // hash_pageoutrun = simple_hash("pageoutrun");
-               // hash_pgactivate = simple_hash("pgactivate");
-               // hash_pgalloc_dma = simple_hash("pgalloc_dma");
-               // hash_pgalloc_dma32 = simple_hash("pgalloc_dma32");
-               // hash_pgalloc_movable = simple_hash("pgalloc_movable");
-               // hash_pgalloc_normal = simple_hash("pgalloc_normal");
-               // hash_pgdeactivate = simple_hash("pgdeactivate");
-               hash_pgfault = simple_hash("pgfault");
-               // hash_pgfree = simple_hash("pgfree");
-               // hash_pginodesteal = simple_hash("pginodesteal");
-               hash_pgmajfault = simple_hash("pgmajfault");
-               hash_pgpgin = simple_hash("pgpgin");
-               hash_pgpgout = simple_hash("pgpgout");
-               // hash_pgrefill_dma = simple_hash("pgrefill_dma");
-               // hash_pgrefill_dma32 = simple_hash("pgrefill_dma32");
-               // hash_pgrefill_movable = simple_hash("pgrefill_movable");
-               // hash_pgrefill_normal = simple_hash("pgrefill_normal");
-               // hash_pgrotated = simple_hash("pgrotated");
-               // hash_pgscan_direct_dma = simple_hash("pgscan_direct_dma");
-               // hash_pgscan_direct_dma32 = simple_hash("pgscan_direct_dma32");
-               // hash_pgscan_direct_movable = simple_hash("pgscan_direct_movable");
-               // hash_pgscan_direct_normal = simple_hash("pgscan_direct_normal");
-               // hash_pgscan_kswapd_dma = simple_hash("pgscan_kswapd_dma");
-               // hash_pgscan_kswapd_dma32 = simple_hash("pgscan_kswapd_dma32");
-               // hash_pgscan_kswapd_movable = simple_hash("pgscan_kswapd_movable");
-               // hash_pgscan_kswapd_normal = simple_hash("pgscan_kswapd_normal");
-               // hash_pgsteal_direct_dma = simple_hash("pgsteal_direct_dma");
-               // hash_pgsteal_direct_dma32 = simple_hash("pgsteal_direct_dma32");
-               // hash_pgsteal_direct_movable = simple_hash("pgsteal_direct_movable");
-               // hash_pgsteal_direct_normal = simple_hash("pgsteal_direct_normal");
-               // hash_pgsteal_kswapd_dma = simple_hash("pgsteal_kswapd_dma");
-               // hash_pgsteal_kswapd_dma32 = simple_hash("pgsteal_kswapd_dma32");
-               // hash_pgsteal_kswapd_movable = simple_hash("pgsteal_kswapd_movable");
-               // hash_pgsteal_kswapd_normal = simple_hash("pgsteal_kswapd_normal");
-               hash_pswpin = simple_hash("pswpin");
-               hash_pswpout = simple_hash("pswpout");
-               // hash_slabs_scanned = simple_hash("slabs_scanned");
-               // hash_thp_collapse_alloc = simple_hash("thp_collapse_alloc");
-               // hash_thp_collapse_alloc_failed = simple_hash("thp_collapse_alloc_failed");
-               // hash_thp_fault_alloc = simple_hash("thp_fault_alloc");
-               // hash_thp_fault_fallback = simple_hash("thp_fault_fallback");
-               // hash_thp_split = simple_hash("thp_split");
-               // hash_unevictable_pgs_cleared = simple_hash("unevictable_pgs_cleared");
-               // hash_unevictable_pgs_culled = simple_hash("unevictable_pgs_culled");
-               // hash_unevictable_pgs_mlocked = simple_hash("unevictable_pgs_mlocked");
-               // hash_unevictable_pgs_mlockfreed = simple_hash("unevictable_pgs_mlockfreed");
-               // hash_unevictable_pgs_munlocked = simple_hash("unevictable_pgs_munlocked");
-               // hash_unevictable_pgs_rescued = simple_hash("unevictable_pgs_rescued");
-               // hash_unevictable_pgs_scanned = simple_hash("unevictable_pgs_scanned");
-               // hash_unevictable_pgs_stranded = simple_hash("unevictable_pgs_stranded");
-       }
+    if(gen_hashes != 1) {
+        gen_hashes = 1;
+        // hash_allocstall = simple_hash("allocstall");
+        // hash_compact_blocks_moved = simple_hash("compact_blocks_moved");
+        // hash_compact_fail = simple_hash("compact_fail");
+        // hash_compact_pagemigrate_failed = simple_hash("compact_pagemigrate_failed");
+        // hash_compact_pages_moved = simple_hash("compact_pages_moved");
+        // hash_compact_stall = simple_hash("compact_stall");
+        // hash_compact_success = simple_hash("compact_success");
+        // hash_htlb_buddy_alloc_fail = simple_hash("htlb_buddy_alloc_fail");
+        // hash_htlb_buddy_alloc_success = simple_hash("htlb_buddy_alloc_success");
+        // hash_kswapd_high_wmark_hit_quickly = simple_hash("kswapd_high_wmark_hit_quickly");
+        // hash_kswapd_inodesteal = simple_hash("kswapd_inodesteal");
+        // hash_kswapd_low_wmark_hit_quickly = simple_hash("kswapd_low_wmark_hit_quickly");
+        // hash_kswapd_skip_congestion_wait = simple_hash("kswapd_skip_congestion_wait");
+        // hash_nr_active_anon = simple_hash("nr_active_anon");
+        // hash_nr_active_file = simple_hash("nr_active_file");
+        // hash_nr_anon_pages = simple_hash("nr_anon_pages");
+        // hash_nr_anon_transparent_hugepages = simple_hash("nr_anon_transparent_hugepages");
+        // hash_nr_bounce = simple_hash("nr_bounce");
+        // hash_nr_dirtied = simple_hash("nr_dirtied");
+        // hash_nr_dirty = simple_hash("nr_dirty");
+        // hash_nr_dirty_background_threshold = simple_hash("nr_dirty_background_threshold");
+        // hash_nr_dirty_threshold = simple_hash("nr_dirty_threshold");
+        // hash_nr_file_pages = simple_hash("nr_file_pages");
+        // hash_nr_free_pages = simple_hash("nr_free_pages");
+        // hash_nr_inactive_anon = simple_hash("nr_inactive_anon");
+        // hash_nr_inactive_file = simple_hash("nr_inactive_file");
+        // hash_nr_isolated_anon = simple_hash("nr_isolated_anon");
+        // hash_nr_isolated_file = simple_hash("nr_isolated_file");
+        // hash_nr_kernel_stack = simple_hash("nr_kernel_stack");
+        // hash_nr_mapped = simple_hash("nr_mapped");
+        // hash_nr_mlock = simple_hash("nr_mlock");
+        // hash_nr_page_table_pages = simple_hash("nr_page_table_pages");
+        // hash_nr_shmem = simple_hash("nr_shmem");
+        // hash_nr_slab_reclaimable = simple_hash("nr_slab_reclaimable");
+        // hash_nr_slab_unreclaimable = simple_hash("nr_slab_unreclaimable");
+        // hash_nr_unevictable = simple_hash("nr_unevictable");
+        // hash_nr_unstable = simple_hash("nr_unstable");
+        // hash_nr_vmscan_immediate_reclaim = simple_hash("nr_vmscan_immediate_reclaim");
+        // hash_nr_vmscan_write = simple_hash("nr_vmscan_write");
+        // hash_nr_writeback = simple_hash("nr_writeback");
+        // hash_nr_writeback_temp = simple_hash("nr_writeback_temp");
+        // hash_nr_written = simple_hash("nr_written");
+        // hash_pageoutrun = simple_hash("pageoutrun");
+        // hash_pgactivate = simple_hash("pgactivate");
+        // hash_pgalloc_dma = simple_hash("pgalloc_dma");
+        // hash_pgalloc_dma32 = simple_hash("pgalloc_dma32");
+        // hash_pgalloc_movable = simple_hash("pgalloc_movable");
+        // hash_pgalloc_normal = simple_hash("pgalloc_normal");
+        // hash_pgdeactivate = simple_hash("pgdeactivate");
+        hash_pgfault = simple_hash("pgfault");
+        // hash_pgfree = simple_hash("pgfree");
+        // hash_pginodesteal = simple_hash("pginodesteal");
+        hash_pgmajfault = simple_hash("pgmajfault");
+        hash_pgpgin = simple_hash("pgpgin");
+        hash_pgpgout = simple_hash("pgpgout");
+        // hash_pgrefill_dma = simple_hash("pgrefill_dma");
+        // hash_pgrefill_dma32 = simple_hash("pgrefill_dma32");
+        // hash_pgrefill_movable = simple_hash("pgrefill_movable");
+        // hash_pgrefill_normal = simple_hash("pgrefill_normal");
+        // hash_pgrotated = simple_hash("pgrotated");
+        // hash_pgscan_direct_dma = simple_hash("pgscan_direct_dma");
+        // hash_pgscan_direct_dma32 = simple_hash("pgscan_direct_dma32");
+        // hash_pgscan_direct_movable = simple_hash("pgscan_direct_movable");
+        // hash_pgscan_direct_normal = simple_hash("pgscan_direct_normal");
+        // hash_pgscan_kswapd_dma = simple_hash("pgscan_kswapd_dma");
+        // hash_pgscan_kswapd_dma32 = simple_hash("pgscan_kswapd_dma32");
+        // hash_pgscan_kswapd_movable = simple_hash("pgscan_kswapd_movable");
+        // hash_pgscan_kswapd_normal = simple_hash("pgscan_kswapd_normal");
+        // hash_pgsteal_direct_dma = simple_hash("pgsteal_direct_dma");
+        // hash_pgsteal_direct_dma32 = simple_hash("pgsteal_direct_dma32");
+        // hash_pgsteal_direct_movable = simple_hash("pgsteal_direct_movable");
+        // hash_pgsteal_direct_normal = simple_hash("pgsteal_direct_normal");
+        // hash_pgsteal_kswapd_dma = simple_hash("pgsteal_kswapd_dma");
+        // hash_pgsteal_kswapd_dma32 = simple_hash("pgsteal_kswapd_dma32");
+        // hash_pgsteal_kswapd_movable = simple_hash("pgsteal_kswapd_movable");
+        // hash_pgsteal_kswapd_normal = simple_hash("pgsteal_kswapd_normal");
+        hash_pswpin = simple_hash("pswpin");
+        hash_pswpout = simple_hash("pswpout");
+        // hash_slabs_scanned = simple_hash("slabs_scanned");
+        // hash_thp_collapse_alloc = simple_hash("thp_collapse_alloc");
+        // hash_thp_collapse_alloc_failed = simple_hash("thp_collapse_alloc_failed");
+        // hash_thp_fault_alloc = simple_hash("thp_fault_alloc");
+        // hash_thp_fault_fallback = simple_hash("thp_fault_fallback");
+        // hash_thp_split = simple_hash("thp_split");
+        // hash_unevictable_pgs_cleared = simple_hash("unevictable_pgs_cleared");
+        // hash_unevictable_pgs_culled = simple_hash("unevictable_pgs_culled");
+        // hash_unevictable_pgs_mlocked = simple_hash("unevictable_pgs_mlocked");
+        // hash_unevictable_pgs_mlockfreed = simple_hash("unevictable_pgs_mlockfreed");
+        // hash_unevictable_pgs_munlocked = simple_hash("unevictable_pgs_munlocked");
+        // hash_unevictable_pgs_rescued = simple_hash("unevictable_pgs_rescued");
+        // hash_unevictable_pgs_scanned = simple_hash("unevictable_pgs_scanned");
+        // hash_unevictable_pgs_stranded = simple_hash("unevictable_pgs_stranded");
+    }
 
-       if(do_swapio == -1)     do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
-       if(do_io == -1)         do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
-       if(do_pgfaults == -1)   do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
+    if(do_swapio == -1) do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
+    if(do_io == -1)     do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
+    if(do_pgfaults == -1)   do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
 
-       if(dt) {};
+    if(dt) {};
 
-       if(!ff) {
-               char filename[FILENAME_MAX + 1];
-               snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
-               ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
-       }
-       if(!ff) return 1;
+    if(!ff) {
+        char filename[FILENAME_MAX + 1];
+        snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
+        ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
+    }
+    if(!ff) return 1;
 
-       ff = procfile_readall(ff);
-       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+    ff = procfile_readall(ff);
+    if(!ff) return 0; // we return 0, so that we will retry to open it next time
 
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words;
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words;
 
-       // unsigned long long allocstall = 0ULL;
-       // unsigned long long compact_blocks_moved = 0ULL;
-       // unsigned long long compact_fail = 0ULL;
-       // unsigned long long compact_pagemigrate_failed = 0ULL;
-       // unsigned long long compact_pages_moved = 0ULL;
-       // unsigned long long compact_stall = 0ULL;
-       // unsigned long long compact_success = 0ULL;
-       // unsigned long long htlb_buddy_alloc_fail = 0ULL;
-       // unsigned long long htlb_buddy_alloc_success = 0ULL;
-       // unsigned long long kswapd_high_wmark_hit_quickly = 0ULL;
-       // unsigned long long kswapd_inodesteal = 0ULL;
-       // unsigned long long kswapd_low_wmark_hit_quickly = 0ULL;
-       // unsigned long long kswapd_skip_congestion_wait = 0ULL;
-       // unsigned long long nr_active_anon = 0ULL;
-       // unsigned long long nr_active_file = 0ULL;
-       // unsigned long long nr_anon_pages = 0ULL;
-       // unsigned long long nr_anon_transparent_hugepages = 0ULL;
-       // unsigned long long nr_bounce = 0ULL;
-       // unsigned long long nr_dirtied = 0ULL;
-       // unsigned long long nr_dirty = 0ULL;
-       // unsigned long long nr_dirty_background_threshold = 0ULL;
-       // unsigned long long nr_dirty_threshold = 0ULL;
-       // unsigned long long nr_file_pages = 0ULL;
-       // unsigned long long nr_free_pages = 0ULL;
-       // unsigned long long nr_inactive_anon = 0ULL;
-       // unsigned long long nr_inactive_file = 0ULL;
-       // unsigned long long nr_isolated_anon = 0ULL;
-       // unsigned long long nr_isolated_file = 0ULL;
-       // unsigned long long nr_kernel_stack = 0ULL;
-       // unsigned long long nr_mapped = 0ULL;
-       // unsigned long long nr_mlock = 0ULL;
-       // unsigned long long nr_page_table_pages = 0ULL;
-       // unsigned long long nr_shmem = 0ULL;
-       // unsigned long long nr_slab_reclaimable = 0ULL;
-       // unsigned long long nr_slab_unreclaimable = 0ULL;
-       // unsigned long long nr_unevictable = 0ULL;
-       // unsigned long long nr_unstable = 0ULL;
-       // unsigned long long nr_vmscan_immediate_reclaim = 0ULL;
-       // unsigned long long nr_vmscan_write = 0ULL;
-       // unsigned long long nr_writeback = 0ULL;
-       // unsigned long long nr_writeback_temp = 0ULL;
-       // unsigned long long nr_written = 0ULL;
-       // unsigned long long pageoutrun = 0ULL;
-       // unsigned long long pgactivate = 0ULL;
-       // unsigned long long pgalloc_dma = 0ULL;
-       // unsigned long long pgalloc_dma32 = 0ULL;
-       // unsigned long long pgalloc_movable = 0ULL;
-       // unsigned long long pgalloc_normal = 0ULL;
-       // unsigned long long pgdeactivate = 0ULL;
-       unsigned long long pgfault = 0ULL;
-       // unsigned long long pgfree = 0ULL;
-       // unsigned long long pginodesteal = 0ULL;
-       unsigned long long pgmajfault = 0ULL;
-       unsigned long long pgpgin = 0ULL;
-       unsigned long long pgpgout = 0ULL;
-       // unsigned long long pgrefill_dma = 0ULL;
-       // unsigned long long pgrefill_dma32 = 0ULL;
-       // unsigned long long pgrefill_movable = 0ULL;
-       // unsigned long long pgrefill_normal = 0ULL;
-       // unsigned long long pgrotated = 0ULL;
-       // unsigned long long pgscan_direct_dma = 0ULL;
-       // unsigned long long pgscan_direct_dma32 = 0ULL;
-       // unsigned long long pgscan_direct_movable = 0ULL;
-       // unsigned long long pgscan_direct_normal = 0ULL;
-       // unsigned long long pgscan_kswapd_dma = 0ULL;
-       // unsigned long long pgscan_kswapd_dma32 = 0ULL;
-       // unsigned long long pgscan_kswapd_movable = 0ULL;
-       // unsigned long long pgscan_kswapd_normal = 0ULL;
-       // unsigned long long pgsteal_direct_dma = 0ULL;
-       // unsigned long long pgsteal_direct_dma32 = 0ULL;
-       // unsigned long long pgsteal_direct_movable = 0ULL;
-       // unsigned long long pgsteal_direct_normal = 0ULL;
-       // unsigned long long pgsteal_kswapd_dma = 0ULL;
-       // unsigned long long pgsteal_kswapd_dma32 = 0ULL;
-       // unsigned long long pgsteal_kswapd_movable = 0ULL;
-       // unsigned long long pgsteal_kswapd_normal = 0ULL;
-       unsigned long long pswpin = 0ULL;
-       unsigned long long pswpout = 0ULL;
-       // unsigned long long slabs_scanned = 0ULL;
-       // unsigned long long thp_collapse_alloc = 0ULL;
-       // unsigned long long thp_collapse_alloc_failed = 0ULL;
-       // unsigned long long thp_fault_alloc = 0ULL;
-       // unsigned long long thp_fault_fallback = 0ULL;
-       // unsigned long long thp_split = 0ULL;
-       // unsigned long long unevictable_pgs_cleared = 0ULL;
-       // unsigned long long unevictable_pgs_culled = 0ULL;
-       // unsigned long long unevictable_pgs_mlocked = 0ULL;
-       // unsigned long long unevictable_pgs_mlockfreed = 0ULL;
-       // unsigned long long unevictable_pgs_munlocked = 0ULL;
-       // unsigned long long unevictable_pgs_rescued = 0ULL;
-       // unsigned long long unevictable_pgs_scanned = 0ULL;
-       // unsigned long long unevictable_pgs_stranded = 0ULL;
+    // unsigned long long allocstall = 0ULL;
+    // unsigned long long compact_blocks_moved = 0ULL;
+    // unsigned long long compact_fail = 0ULL;
+    // unsigned long long compact_pagemigrate_failed = 0ULL;
+    // unsigned long long compact_pages_moved = 0ULL;
+    // unsigned long long compact_stall = 0ULL;
+    // unsigned long long compact_success = 0ULL;
+    // unsigned long long htlb_buddy_alloc_fail = 0ULL;
+    // unsigned long long htlb_buddy_alloc_success = 0ULL;
+    // unsigned long long kswapd_high_wmark_hit_quickly = 0ULL;
+    // unsigned long long kswapd_inodesteal = 0ULL;
+    // unsigned long long kswapd_low_wmark_hit_quickly = 0ULL;
+    // unsigned long long kswapd_skip_congestion_wait = 0ULL;
+    // unsigned long long nr_active_anon = 0ULL;
+    // unsigned long long nr_active_file = 0ULL;
+    // unsigned long long nr_anon_pages = 0ULL;
+    // unsigned long long nr_anon_transparent_hugepages = 0ULL;
+    // unsigned long long nr_bounce = 0ULL;
+    // unsigned long long nr_dirtied = 0ULL;
+    // unsigned long long nr_dirty = 0ULL;
+    // unsigned long long nr_dirty_background_threshold = 0ULL;
+    // unsigned long long nr_dirty_threshold = 0ULL;
+    // unsigned long long nr_file_pages = 0ULL;
+    // unsigned long long nr_free_pages = 0ULL;
+    // unsigned long long nr_inactive_anon = 0ULL;
+    // unsigned long long nr_inactive_file = 0ULL;
+    // unsigned long long nr_isolated_anon = 0ULL;
+    // unsigned long long nr_isolated_file = 0ULL;
+    // unsigned long long nr_kernel_stack = 0ULL;
+    // unsigned long long nr_mapped = 0ULL;
+    // unsigned long long nr_mlock = 0ULL;
+    // unsigned long long nr_page_table_pages = 0ULL;
+    // unsigned long long nr_shmem = 0ULL;
+    // unsigned long long nr_slab_reclaimable = 0ULL;
+    // unsigned long long nr_slab_unreclaimable = 0ULL;
+    // unsigned long long nr_unevictable = 0ULL;
+    // unsigned long long nr_unstable = 0ULL;
+    // unsigned long long nr_vmscan_immediate_reclaim = 0ULL;
+    // unsigned long long nr_vmscan_write = 0ULL;
+    // unsigned long long nr_writeback = 0ULL;
+    // unsigned long long nr_writeback_temp = 0ULL;
+    // unsigned long long nr_written = 0ULL;
+    // unsigned long long pageoutrun = 0ULL;
+    // unsigned long long pgactivate = 0ULL;
+    // unsigned long long pgalloc_dma = 0ULL;
+    // unsigned long long pgalloc_dma32 = 0ULL;
+    // unsigned long long pgalloc_movable = 0ULL;
+    // unsigned long long pgalloc_normal = 0ULL;
+    // unsigned long long pgdeactivate = 0ULL;
+    unsigned long long pgfault = 0ULL;
+    // unsigned long long pgfree = 0ULL;
+    // unsigned long long pginodesteal = 0ULL;
+    unsigned long long pgmajfault = 0ULL;
+    unsigned long long pgpgin = 0ULL;
+    unsigned long long pgpgout = 0ULL;
+    // unsigned long long pgrefill_dma = 0ULL;
+    // unsigned long long pgrefill_dma32 = 0ULL;
+    // unsigned long long pgrefill_movable = 0ULL;
+    // unsigned long long pgrefill_normal = 0ULL;
+    // unsigned long long pgrotated = 0ULL;
+    // unsigned long long pgscan_direct_dma = 0ULL;
+    // unsigned long long pgscan_direct_dma32 = 0ULL;
+    // unsigned long long pgscan_direct_movable = 0ULL;
+    // unsigned long long pgscan_direct_normal = 0ULL;
+    // unsigned long long pgscan_kswapd_dma = 0ULL;
+    // unsigned long long pgscan_kswapd_dma32 = 0ULL;
+    // unsigned long long pgscan_kswapd_movable = 0ULL;
+    // unsigned long long pgscan_kswapd_normal = 0ULL;
+    // unsigned long long pgsteal_direct_dma = 0ULL;
+    // unsigned long long pgsteal_direct_dma32 = 0ULL;
+    // unsigned long long pgsteal_direct_movable = 0ULL;
+    // unsigned long long pgsteal_direct_normal = 0ULL;
+    // unsigned long long pgsteal_kswapd_dma = 0ULL;
+    // unsigned long long pgsteal_kswapd_dma32 = 0ULL;
+    // unsigned long long pgsteal_kswapd_movable = 0ULL;
+    // unsigned long long pgsteal_kswapd_normal = 0ULL;
+    unsigned long long pswpin = 0ULL;
+    unsigned long long pswpout = 0ULL;
+    // unsigned long long slabs_scanned = 0ULL;
+    // unsigned long long thp_collapse_alloc = 0ULL;
+    // unsigned long long thp_collapse_alloc_failed = 0ULL;
+    // unsigned long long thp_fault_alloc = 0ULL;
+    // unsigned long long thp_fault_fallback = 0ULL;
+    // unsigned long long thp_split = 0ULL;
+    // unsigned long long unevictable_pgs_cleared = 0ULL;
+    // unsigned long long unevictable_pgs_culled = 0ULL;
+    // unsigned long long unevictable_pgs_mlocked = 0ULL;
+    // unsigned long long unevictable_pgs_mlockfreed = 0ULL;
+    // unsigned long long unevictable_pgs_munlocked = 0ULL;
+    // unsigned long long unevictable_pgs_rescued = 0ULL;
+    // unsigned long long unevictable_pgs_scanned = 0ULL;
+    // unsigned long long unevictable_pgs_stranded = 0ULL;
 
-       for(l = 0; l < lines ;l++) {
-               words = procfile_linewords(ff, l);
-               if(words < 2) {
-                       if(words) error("Cannot read /proc/vmstat line %u. Expected 2 params, read %u.", l, words);
-                       continue;
-               }
+    for(l = 0; l < lines ;l++) {
+        words = procfile_linewords(ff, l);
+        if(words < 2) {
+            if(words) error("Cannot read /proc/vmstat line %u. Expected 2 params, read %u.", l, words);
+            continue;
+        }
 
-               char *name = procfile_lineword(ff, l, 0);
-               char * value = procfile_lineword(ff, l, 1);
-               if(!name || !*name || !value || !*value) continue;
+        char *name = procfile_lineword(ff, l, 0);
+        char * value = procfile_lineword(ff, l, 1);
+        if(!name || !*name || !value || !*value) continue;
 
-               uint32_t hash = simple_hash(name);
+        uint32_t hash = simple_hash(name);
 
-               if(0) ;
-               // else if(hash == hash_allocstall && strcmp(name, "allocstall") == 0) allocstall = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_blocks_moved && strcmp(name, "compact_blocks_moved") == 0) compact_blocks_moved = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_fail && strcmp(name, "compact_fail") == 0) compact_fail = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_pagemigrate_failed && strcmp(name, "compact_pagemigrate_failed") == 0) compact_pagemigrate_failed = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_pages_moved && strcmp(name, "compact_pages_moved") == 0) compact_pages_moved = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_stall && strcmp(name, "compact_stall") == 0) compact_stall = strtoull(value, NULL, 10);
-               // else if(hash == hash_compact_success && strcmp(name, "compact_success") == 0) compact_success = strtoull(value, NULL, 10);
-               // else if(hash == hash_htlb_buddy_alloc_fail && strcmp(name, "htlb_buddy_alloc_fail") == 0) htlb_buddy_alloc_fail = strtoull(value, NULL, 10);
-               // else if(hash == hash_htlb_buddy_alloc_success && strcmp(name, "htlb_buddy_alloc_success") == 0) htlb_buddy_alloc_success = strtoull(value, NULL, 10);
-               // else if(hash == hash_kswapd_high_wmark_hit_quickly && strcmp(name, "kswapd_high_wmark_hit_quickly") == 0) kswapd_high_wmark_hit_quickly = strtoull(value, NULL, 10);
-               // else if(hash == hash_kswapd_inodesteal && strcmp(name, "kswapd_inodesteal") == 0) kswapd_inodesteal = strtoull(value, NULL, 10);
-               // else if(hash == hash_kswapd_low_wmark_hit_quickly && strcmp(name, "kswapd_low_wmark_hit_quickly") == 0) kswapd_low_wmark_hit_quickly = strtoull(value, NULL, 10);
-               // else if(hash == hash_kswapd_skip_congestion_wait && strcmp(name, "kswapd_skip_congestion_wait") == 0) kswapd_skip_congestion_wait = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_active_anon && strcmp(name, "nr_active_anon") == 0) nr_active_anon = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_active_file && strcmp(name, "nr_active_file") == 0) nr_active_file = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_anon_pages && strcmp(name, "nr_anon_pages") == 0) nr_anon_pages = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_anon_transparent_hugepages && strcmp(name, "nr_anon_transparent_hugepages") == 0) nr_anon_transparent_hugepages = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_bounce && strcmp(name, "nr_bounce") == 0) nr_bounce = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_dirtied && strcmp(name, "nr_dirtied") == 0) nr_dirtied = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_dirty && strcmp(name, "nr_dirty") == 0) nr_dirty = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_dirty_background_threshold && strcmp(name, "nr_dirty_background_threshold") == 0) nr_dirty_background_threshold = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_dirty_threshold && strcmp(name, "nr_dirty_threshold") == 0) nr_dirty_threshold = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_file_pages && strcmp(name, "nr_file_pages") == 0) nr_file_pages = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_free_pages && strcmp(name, "nr_free_pages") == 0) nr_free_pages = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_inactive_anon && strcmp(name, "nr_inactive_anon") == 0) nr_inactive_anon = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_inactive_file && strcmp(name, "nr_inactive_file") == 0) nr_inactive_file = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_isolated_anon && strcmp(name, "nr_isolated_anon") == 0) nr_isolated_anon = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_isolated_file && strcmp(name, "nr_isolated_file") == 0) nr_isolated_file = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_kernel_stack && strcmp(name, "nr_kernel_stack") == 0) nr_kernel_stack = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_mapped && strcmp(name, "nr_mapped") == 0) nr_mapped = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_mlock && strcmp(name, "nr_mlock") == 0) nr_mlock = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_page_table_pages && strcmp(name, "nr_page_table_pages") == 0) nr_page_table_pages = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_shmem && strcmp(name, "nr_shmem") == 0) nr_shmem = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_slab_reclaimable && strcmp(name, "nr_slab_reclaimable") == 0) nr_slab_reclaimable = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_slab_unreclaimable && strcmp(name, "nr_slab_unreclaimable") == 0) nr_slab_unreclaimable = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_unevictable && strcmp(name, "nr_unevictable") == 0) nr_unevictable = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_unstable && strcmp(name, "nr_unstable") == 0) nr_unstable = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_vmscan_immediate_reclaim && strcmp(name, "nr_vmscan_immediate_reclaim") == 0) nr_vmscan_immediate_reclaim = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_vmscan_write && strcmp(name, "nr_vmscan_write") == 0) nr_vmscan_write = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_writeback && strcmp(name, "nr_writeback") == 0) nr_writeback = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_writeback_temp && strcmp(name, "nr_writeback_temp") == 0) nr_writeback_temp = strtoull(value, NULL, 10);
-               // else if(hash == hash_nr_written && strcmp(name, "nr_written") == 0) nr_written = strtoull(value, NULL, 10);
-               // else if(hash == hash_pageoutrun && strcmp(name, "pageoutrun") == 0) pageoutrun = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgactivate && strcmp(name, "pgactivate") == 0) pgactivate = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgalloc_dma && strcmp(name, "pgalloc_dma") == 0) pgalloc_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgalloc_dma32 && strcmp(name, "pgalloc_dma32") == 0) pgalloc_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgalloc_movable && strcmp(name, "pgalloc_movable") == 0) pgalloc_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgalloc_normal && strcmp(name, "pgalloc_normal") == 0) pgalloc_normal = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgdeactivate && strcmp(name, "pgdeactivate") == 0) pgdeactivate = strtoull(value, NULL, 10);
-               else if(hash == hash_pgfault && strcmp(name, "pgfault") == 0) pgfault = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgfree && strcmp(name, "pgfree") == 0) pgfree = strtoull(value, NULL, 10);
-               // else if(hash == hash_pginodesteal && strcmp(name, "pginodesteal") == 0) pginodesteal = strtoull(value, NULL, 10);
-               else if(hash == hash_pgmajfault && strcmp(name, "pgmajfault") == 0) pgmajfault = strtoull(value, NULL, 10);
-               else if(hash == hash_pgpgin && strcmp(name, "pgpgin") == 0) pgpgin = strtoull(value, NULL, 10);
-               else if(hash == hash_pgpgout && strcmp(name, "pgpgout") == 0) pgpgout = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgrefill_dma && strcmp(name, "pgrefill_dma") == 0) pgrefill_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgrefill_dma32 && strcmp(name, "pgrefill_dma32") == 0) pgrefill_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgrefill_movable && strcmp(name, "pgrefill_movable") == 0) pgrefill_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgrefill_normal && strcmp(name, "pgrefill_normal") == 0) pgrefill_normal = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgrotated && strcmp(name, "pgrotated") == 0) pgrotated = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_direct_dma && strcmp(name, "pgscan_direct_dma") == 0) pgscan_direct_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_direct_dma32 && strcmp(name, "pgscan_direct_dma32") == 0) pgscan_direct_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_direct_movable && strcmp(name, "pgscan_direct_movable") == 0) pgscan_direct_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_direct_normal && strcmp(name, "pgscan_direct_normal") == 0) pgscan_direct_normal = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_kswapd_dma && strcmp(name, "pgscan_kswapd_dma") == 0) pgscan_kswapd_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_kswapd_dma32 && strcmp(name, "pgscan_kswapd_dma32") == 0) pgscan_kswapd_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_kswapd_movable && strcmp(name, "pgscan_kswapd_movable") == 0) pgscan_kswapd_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgscan_kswapd_normal && strcmp(name, "pgscan_kswapd_normal") == 0) pgscan_kswapd_normal = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_direct_dma && strcmp(name, "pgsteal_direct_dma") == 0) pgsteal_direct_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_direct_dma32 && strcmp(name, "pgsteal_direct_dma32") == 0) pgsteal_direct_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_direct_movable && strcmp(name, "pgsteal_direct_movable") == 0) pgsteal_direct_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_direct_normal && strcmp(name, "pgsteal_direct_normal") == 0) pgsteal_direct_normal = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_kswapd_dma && strcmp(name, "pgsteal_kswapd_dma") == 0) pgsteal_kswapd_dma = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_kswapd_dma32 && strcmp(name, "pgsteal_kswapd_dma32") == 0) pgsteal_kswapd_dma32 = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_kswapd_movable && strcmp(name, "pgsteal_kswapd_movable") == 0) pgsteal_kswapd_movable = strtoull(value, NULL, 10);
-               // else if(hash == hash_pgsteal_kswapd_normal && strcmp(name, "pgsteal_kswapd_normal") == 0) pgsteal_kswapd_normal = strtoull(value, NULL, 10);
-               else if(hash == hash_pswpin && strcmp(name, "pswpin") == 0) pswpin = strtoull(value, NULL, 10);
-               else if(hash == hash_pswpout && strcmp(name, "pswpout") == 0) pswpout = strtoull(value, NULL, 10);
-               // else if(hash == hash_slabs_scanned && strcmp(name, "slabs_scanned") == 0) slabs_scanned = strtoull(value, NULL, 10);
-               // else if(hash == hash_thp_collapse_alloc && strcmp(name, "thp_collapse_alloc") == 0) thp_collapse_alloc = strtoull(value, NULL, 10);
-               // else if(hash == hash_thp_collapse_alloc_failed && strcmp(name, "thp_collapse_alloc_failed") == 0) thp_collapse_alloc_failed = strtoull(value, NULL, 10);
-               // else if(hash == hash_thp_fault_alloc && strcmp(name, "thp_fault_alloc") == 0) thp_fault_alloc = strtoull(value, NULL, 10);
-               // else if(hash == hash_thp_fault_fallback && strcmp(name, "thp_fault_fallback") == 0) thp_fault_fallback = strtoull(value, NULL, 10);
-               // else if(hash == hash_thp_split && strcmp(name, "thp_split") == 0) thp_split = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_cleared && strcmp(name, "unevictable_pgs_cleared") == 0) unevictable_pgs_cleared = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_culled && strcmp(name, "unevictable_pgs_culled") == 0) unevictable_pgs_culled = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_mlocked && strcmp(name, "unevictable_pgs_mlocked") == 0) unevictable_pgs_mlocked = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_mlockfreed && strcmp(name, "unevictable_pgs_mlockfreed") == 0) unevictable_pgs_mlockfreed = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_munlocked && strcmp(name, "unevictable_pgs_munlocked") == 0) unevictable_pgs_munlocked = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_rescued && strcmp(name, "unevictable_pgs_rescued") == 0) unevictable_pgs_rescued = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_scanned && strcmp(name, "unevictable_pgs_scanned") == 0) unevictable_pgs_scanned = strtoull(value, NULL, 10);
-               // else if(hash == hash_unevictable_pgs_stranded && strcmp(name, "unevictable_pgs_stranded") == 0) unevictable_pgs_stranded = strtoull(value, NULL, 10);
-       }
+        if(0) ;
+        // else if(hash == hash_allocstall && strcmp(name, "allocstall") == 0) allocstall = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_blocks_moved && strcmp(name, "compact_blocks_moved") == 0) compact_blocks_moved = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_fail && strcmp(name, "compact_fail") == 0) compact_fail = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_pagemigrate_failed && strcmp(name, "compact_pagemigrate_failed") == 0) compact_pagemigrate_failed = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_pages_moved && strcmp(name, "compact_pages_moved") == 0) compact_pages_moved = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_stall && strcmp(name, "compact_stall") == 0) compact_stall = strtoull(value, NULL, 10);
+        // else if(hash == hash_compact_success && strcmp(name, "compact_success") == 0) compact_success = strtoull(value, NULL, 10);
+        // else if(hash == hash_htlb_buddy_alloc_fail && strcmp(name, "htlb_buddy_alloc_fail") == 0) htlb_buddy_alloc_fail = strtoull(value, NULL, 10);
+        // else if(hash == hash_htlb_buddy_alloc_success && strcmp(name, "htlb_buddy_alloc_success") == 0) htlb_buddy_alloc_success = strtoull(value, NULL, 10);
+        // else if(hash == hash_kswapd_high_wmark_hit_quickly && strcmp(name, "kswapd_high_wmark_hit_quickly") == 0) kswapd_high_wmark_hit_quickly = strtoull(value, NULL, 10);
+        // else if(hash == hash_kswapd_inodesteal && strcmp(name, "kswapd_inodesteal") == 0) kswapd_inodesteal = strtoull(value, NULL, 10);
+        // else if(hash == hash_kswapd_low_wmark_hit_quickly && strcmp(name, "kswapd_low_wmark_hit_quickly") == 0) kswapd_low_wmark_hit_quickly = strtoull(value, NULL, 10);
+        // else if(hash == hash_kswapd_skip_congestion_wait && strcmp(name, "kswapd_skip_congestion_wait") == 0) kswapd_skip_congestion_wait = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_active_anon && strcmp(name, "nr_active_anon") == 0) nr_active_anon = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_active_file && strcmp(name, "nr_active_file") == 0) nr_active_file = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_anon_pages && strcmp(name, "nr_anon_pages") == 0) nr_anon_pages = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_anon_transparent_hugepages && strcmp(name, "nr_anon_transparent_hugepages") == 0) nr_anon_transparent_hugepages = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_bounce && strcmp(name, "nr_bounce") == 0) nr_bounce = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_dirtied && strcmp(name, "nr_dirtied") == 0) nr_dirtied = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_dirty && strcmp(name, "nr_dirty") == 0) nr_dirty = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_dirty_background_threshold && strcmp(name, "nr_dirty_background_threshold") == 0) nr_dirty_background_threshold = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_dirty_threshold && strcmp(name, "nr_dirty_threshold") == 0) nr_dirty_threshold = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_file_pages && strcmp(name, "nr_file_pages") == 0) nr_file_pages = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_free_pages && strcmp(name, "nr_free_pages") == 0) nr_free_pages = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_inactive_anon && strcmp(name, "nr_inactive_anon") == 0) nr_inactive_anon = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_inactive_file && strcmp(name, "nr_inactive_file") == 0) nr_inactive_file = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_isolated_anon && strcmp(name, "nr_isolated_anon") == 0) nr_isolated_anon = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_isolated_file && strcmp(name, "nr_isolated_file") == 0) nr_isolated_file = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_kernel_stack && strcmp(name, "nr_kernel_stack") == 0) nr_kernel_stack = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_mapped && strcmp(name, "nr_mapped") == 0) nr_mapped = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_mlock && strcmp(name, "nr_mlock") == 0) nr_mlock = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_page_table_pages && strcmp(name, "nr_page_table_pages") == 0) nr_page_table_pages = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_shmem && strcmp(name, "nr_shmem") == 0) nr_shmem = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_slab_reclaimable && strcmp(name, "nr_slab_reclaimable") == 0) nr_slab_reclaimable = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_slab_unreclaimable && strcmp(name, "nr_slab_unreclaimable") == 0) nr_slab_unreclaimable = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_unevictable && strcmp(name, "nr_unevictable") == 0) nr_unevictable = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_unstable && strcmp(name, "nr_unstable") == 0) nr_unstable = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_vmscan_immediate_reclaim && strcmp(name, "nr_vmscan_immediate_reclaim") == 0) nr_vmscan_immediate_reclaim = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_vmscan_write && strcmp(name, "nr_vmscan_write") == 0) nr_vmscan_write = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_writeback && strcmp(name, "nr_writeback") == 0) nr_writeback = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_writeback_temp && strcmp(name, "nr_writeback_temp") == 0) nr_writeback_temp = strtoull(value, NULL, 10);
+        // else if(hash == hash_nr_written && strcmp(name, "nr_written") == 0) nr_written = strtoull(value, NULL, 10);
+        // else if(hash == hash_pageoutrun && strcmp(name, "pageoutrun") == 0) pageoutrun = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgactivate && strcmp(name, "pgactivate") == 0) pgactivate = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgalloc_dma && strcmp(name, "pgalloc_dma") == 0) pgalloc_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgalloc_dma32 && strcmp(name, "pgalloc_dma32") == 0) pgalloc_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgalloc_movable && strcmp(name, "pgalloc_movable") == 0) pgalloc_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgalloc_normal && strcmp(name, "pgalloc_normal") == 0) pgalloc_normal = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgdeactivate && strcmp(name, "pgdeactivate") == 0) pgdeactivate = strtoull(value, NULL, 10);
+        else if(hash == hash_pgfault && strcmp(name, "pgfault") == 0) pgfault = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgfree && strcmp(name, "pgfree") == 0) pgfree = strtoull(value, NULL, 10);
+        // else if(hash == hash_pginodesteal && strcmp(name, "pginodesteal") == 0) pginodesteal = strtoull(value, NULL, 10);
+        else if(hash == hash_pgmajfault && strcmp(name, "pgmajfault") == 0) pgmajfault = strtoull(value, NULL, 10);
+        else if(hash == hash_pgpgin && strcmp(name, "pgpgin") == 0) pgpgin = strtoull(value, NULL, 10);
+        else if(hash == hash_pgpgout && strcmp(name, "pgpgout") == 0) pgpgout = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgrefill_dma && strcmp(name, "pgrefill_dma") == 0) pgrefill_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgrefill_dma32 && strcmp(name, "pgrefill_dma32") == 0) pgrefill_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgrefill_movable && strcmp(name, "pgrefill_movable") == 0) pgrefill_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgrefill_normal && strcmp(name, "pgrefill_normal") == 0) pgrefill_normal = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgrotated && strcmp(name, "pgrotated") == 0) pgrotated = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_direct_dma && strcmp(name, "pgscan_direct_dma") == 0) pgscan_direct_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_direct_dma32 && strcmp(name, "pgscan_direct_dma32") == 0) pgscan_direct_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_direct_movable && strcmp(name, "pgscan_direct_movable") == 0) pgscan_direct_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_direct_normal && strcmp(name, "pgscan_direct_normal") == 0) pgscan_direct_normal = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_kswapd_dma && strcmp(name, "pgscan_kswapd_dma") == 0) pgscan_kswapd_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_kswapd_dma32 && strcmp(name, "pgscan_kswapd_dma32") == 0) pgscan_kswapd_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_kswapd_movable && strcmp(name, "pgscan_kswapd_movable") == 0) pgscan_kswapd_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgscan_kswapd_normal && strcmp(name, "pgscan_kswapd_normal") == 0) pgscan_kswapd_normal = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_direct_dma && strcmp(name, "pgsteal_direct_dma") == 0) pgsteal_direct_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_direct_dma32 && strcmp(name, "pgsteal_direct_dma32") == 0) pgsteal_direct_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_direct_movable && strcmp(name, "pgsteal_direct_movable") == 0) pgsteal_direct_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_direct_normal && strcmp(name, "pgsteal_direct_normal") == 0) pgsteal_direct_normal = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_kswapd_dma && strcmp(name, "pgsteal_kswapd_dma") == 0) pgsteal_kswapd_dma = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_kswapd_dma32 && strcmp(name, "pgsteal_kswapd_dma32") == 0) pgsteal_kswapd_dma32 = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_kswapd_movable && strcmp(name, "pgsteal_kswapd_movable") == 0) pgsteal_kswapd_movable = strtoull(value, NULL, 10);
+        // else if(hash == hash_pgsteal_kswapd_normal && strcmp(name, "pgsteal_kswapd_normal") == 0) pgsteal_kswapd_normal = strtoull(value, NULL, 10);
+        else if(hash == hash_pswpin && strcmp(name, "pswpin") == 0) pswpin = strtoull(value, NULL, 10);
+        else if(hash == hash_pswpout && strcmp(name, "pswpout") == 0) pswpout = strtoull(value, NULL, 10);
+        // else if(hash == hash_slabs_scanned && strcmp(name, "slabs_scanned") == 0) slabs_scanned = strtoull(value, NULL, 10);
+        // else if(hash == hash_thp_collapse_alloc && strcmp(name, "thp_collapse_alloc") == 0) thp_collapse_alloc = strtoull(value, NULL, 10);
+        // else if(hash == hash_thp_collapse_alloc_failed && strcmp(name, "thp_collapse_alloc_failed") == 0) thp_collapse_alloc_failed = strtoull(value, NULL, 10);
+        // else if(hash == hash_thp_fault_alloc && strcmp(name, "thp_fault_alloc") == 0) thp_fault_alloc = strtoull(value, NULL, 10);
+        // else if(hash == hash_thp_fault_fallback && strcmp(name, "thp_fault_fallback") == 0) thp_fault_fallback = strtoull(value, NULL, 10);
+        // else if(hash == hash_thp_split && strcmp(name, "thp_split") == 0) thp_split = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_cleared && strcmp(name, "unevictable_pgs_cleared") == 0) unevictable_pgs_cleared = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_culled && strcmp(name, "unevictable_pgs_culled") == 0) unevictable_pgs_culled = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_mlocked && strcmp(name, "unevictable_pgs_mlocked") == 0) unevictable_pgs_mlocked = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_mlockfreed && strcmp(name, "unevictable_pgs_mlockfreed") == 0) unevictable_pgs_mlockfreed = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_munlocked && strcmp(name, "unevictable_pgs_munlocked") == 0) unevictable_pgs_munlocked = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_rescued && strcmp(name, "unevictable_pgs_rescued") == 0) unevictable_pgs_rescued = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_scanned && strcmp(name, "unevictable_pgs_scanned") == 0) unevictable_pgs_scanned = strtoull(value, NULL, 10);
+        // else if(hash == hash_unevictable_pgs_stranded && strcmp(name, "unevictable_pgs_stranded") == 0) unevictable_pgs_stranded = strtoull(value, NULL, 10);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_swapio) {
-               static RRDSET *st_swapio = NULL;
-               if(!st_swapio) {
-                       st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+    if(do_swapio) {
+        static RRDSET *st_swapio = NULL;
+        if(!st_swapio) {
+            st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
 
-                       rrddim_add(st_swapio, "in",  NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
-                       rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st_swapio);
+            rrddim_add(st_swapio, "in",  NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
+            rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st_swapio);
 
-               rrddim_set(st_swapio, "in", pswpin);
-               rrddim_set(st_swapio, "out", pswpout);
-               rrdset_done(st_swapio);
-       }
+        rrddim_set(st_swapio, "in", pswpin);
+        rrddim_set(st_swapio, "out", pswpout);
+        rrdset_done(st_swapio);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_io) {
-               static RRDSET *st_io = NULL;
-               if(!st_io) {
-                       st_io = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
+    if(do_io) {
+        static RRDSET *st_io = NULL;
+        if(!st_io) {
+            st_io = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
 
-                       rrddim_add(st_io, "in",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st_io);
+            rrddim_add(st_io, "in",  NULL,  1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st_io);
 
-               rrddim_set(st_io, "in", pgpgin);
-               rrddim_set(st_io, "out", pgpgout);
-               rrdset_done(st_io);
-       }
+        rrddim_set(st_io, "in", pgpgin);
+        rrddim_set(st_io, "out", pgpgout);
+        rrdset_done(st_io);
+    }
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       if(do_pgfaults) {
-               static RRDSET *st_pgfaults = NULL;
-               if(!st_pgfaults) {
-                       st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
-                       st_pgfaults->isdetail = 1;
+    if(do_pgfaults) {
+        static RRDSET *st_pgfaults = NULL;
+        if(!st_pgfaults) {
+            st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
+            st_pgfaults->isdetail = 1;
 
-                       rrddim_add(st_pgfaults, "minor",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                       rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
-               }
-               else rrdset_next(st_pgfaults);
+            rrddim_add(st_pgfaults, "minor",  NULL,  1, 1, RRDDIM_INCREMENTAL);
+            rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st_pgfaults);
 
-               rrddim_set(st_pgfaults, "minor", pgfault);
-               rrddim_set(st_pgfaults, "major", pgmajfault);
-               rrdset_done(st_pgfaults);
-       }
+        rrddim_set(st_pgfaults, "minor", pgfault);
+        rrddim_set(st_pgfaults, "major", pgmajfault);
+        rrdset_done(st_pgfaults);
+    }
 
-       return 0;
+    return 0;
 }
 
index efe569e593bd608f8459c7847778ef21530174bf..e2aa605820e4197dc1d9cb1809bcced5f53f21ed 100644 (file)
@@ -19,40 +19,40 @@ size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER;
 
 
 pfwords *pfwords_add(pfwords *fw, char *str) {
-       // debug(D_PROCFILE, PF_PREFIX ":       adding word No %d: '%s'", fw->len, str);
+    // debug(D_PROCFILE, PF_PREFIX ":   adding word No %d: '%s'", fw->len, str);
 
-       if(unlikely(fw->len == fw->size)) {
-               // debug(D_PROCFILE, PF_PREFIX ":       expanding words");
+    if(unlikely(fw->len == fw->size)) {
+        // debug(D_PROCFILE, PF_PREFIX ":   expanding words");
 
-               fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
-               fw->size += PFWORDS_INCREASE_STEP;
-       }
+        fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
+        fw->size += PFWORDS_INCREASE_STEP;
+    }
 
-       fw->words[fw->len++] = str;
+    fw->words[fw->len++] = str;
 
-       return fw;
+    return fw;
 }
 
 pfwords *pfwords_new(void) {
-       // debug(D_PROCFILE, PF_PREFIX ":       initializing words");
+    // debug(D_PROCFILE, PF_PREFIX ":   initializing words");
 
-       uint32_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP;
+    uint32_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP;
 
-       pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *));
-       new->len = 0;
-       new->size = size;
-       return new;
+    pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *));
+    new->len = 0;
+    new->size = size;
+    return new;
 }
 
 void pfwords_reset(pfwords *fw) {
-       // debug(D_PROCFILE, PF_PREFIX ":       reseting words");
-       fw->len = 0;
+    // debug(D_PROCFILE, PF_PREFIX ":   reseting words");
+    fw->len = 0;
 }
 
 void pfwords_free(pfwords *fw) {
-       // debug(D_PROCFILE, PF_PREFIX ":       freeing words");
+    // debug(D_PROCFILE, PF_PREFIX ":   freeing words");
 
-       freez(fw);
+    freez(fw);
 }
 
 
@@ -60,402 +60,402 @@ void pfwords_free(pfwords *fw) {
 // An array of lines
 
 pflines *pflines_add(pflines *fl, uint32_t first_word) {
-       // debug(D_PROCFILE, PF_PREFIX ":       adding line %d at word %d", fl->len, first_word);
+    // debug(D_PROCFILE, PF_PREFIX ":   adding line %d at word %d", fl->len, first_word);
 
-       if(unlikely(fl->len == fl->size)) {
-               // debug(D_PROCFILE, PF_PREFIX ":       expanding lines");
+    if(unlikely(fl->len == fl->size)) {
+        // debug(D_PROCFILE, PF_PREFIX ":   expanding lines");
 
-               fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
-               fl->size += PFLINES_INCREASE_STEP;
-       }
+        fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
+        fl->size += PFLINES_INCREASE_STEP;
+    }
 
-       fl->lines[fl->len].words = 0;
-       fl->lines[fl->len++].first = first_word;
+    fl->lines[fl->len].words = 0;
+    fl->lines[fl->len++].first = first_word;
 
-       return fl;
+    return fl;
 }
 
 pflines *pflines_new(void) {
-       // debug(D_PROCFILE, PF_PREFIX ":       initializing lines");
+    // debug(D_PROCFILE, PF_PREFIX ":   initializing lines");
 
-       uint32_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP;
+    uint32_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP;
 
-       pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline));
-       new->len = 0;
-       new->size = size;
-       return new;
+    pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline));
+    new->len = 0;
+    new->size = size;
+    return new;
 }
 
 void pflines_reset(pflines *fl) {
-       // debug(D_PROCFILE, PF_PREFIX ":       reseting lines");
+    // debug(D_PROCFILE, PF_PREFIX ":   reseting lines");
 
-       fl->len = 0;
+    fl->len = 0;
 }
 
 void pflines_free(pflines *fl) {
-       // debug(D_PROCFILE, PF_PREFIX ":       freeing lines");
+    // debug(D_PROCFILE, PF_PREFIX ":   freeing lines");
 
-       freez(fl);
+    freez(fl);
 }
 
 
 // ----------------------------------------------------------------------------
 // The procfile
 
-#define PF_CHAR_IS_SEPARATOR   ' '
-#define PF_CHAR_IS_NEWLINE             'N'
-#define PF_CHAR_IS_WORD                        'W'
+#define PF_CHAR_IS_SEPARATOR    ' '
+#define PF_CHAR_IS_NEWLINE      'N'
+#define PF_CHAR_IS_WORD         'W'
 #define PF_CHAR_IS_QUOTE        'Q'
 #define PF_CHAR_IS_OPEN         'O'
 #define PF_CHAR_IS_CLOSE        'C'
 
 void procfile_close(procfile *ff) {
-       debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
+    debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
 
-       if(likely(ff->lines)) pflines_free(ff->lines);
-       if(likely(ff->words)) pfwords_free(ff->words);
+    if(likely(ff->lines)) pflines_free(ff->lines);
+    if(likely(ff->words)) pfwords_free(ff->words);
 
-       if(likely(ff->fd != -1)) close(ff->fd);
-       freez(ff);
+    if(likely(ff->fd != -1)) close(ff->fd);
+    freez(ff);
 }
 
 procfile *procfile_parser(procfile *ff) {
-       debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
-
-       char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
-       uint32_t l = 0, w = 0;
-       int opened = 0;
-
-       ff->lines = pflines_add(ff->lines, w);
-       if(unlikely(!ff->lines)) goto cleanup;
-
-       while(likely(s < e)) {
-               // we are not at the end
-
-               switch(ff->separators[(uint8_t)(*s)]) {
-                       case PF_CHAR_IS_OPEN:
-                               if(s == t) {
-                                       opened++;
-                                       t = ++s;
-                               }
-                               else if(opened) {
-                                       opened++;
-                                       s++;
-                               }
-                               else
-                                       s++;
-                               continue;
-
-                       case PF_CHAR_IS_CLOSE:
-                               if(opened) {
-                                       opened--;
-
-                                       if(!opened) {
-                                               *s = '\0';
-                                               ff->words = pfwords_add(ff->words, t);
-                                               if(unlikely(!ff->words)) goto cleanup;
-
-                                               ff->lines->lines[l].words++;
-                                               w++;
-
-                                               t = ++s;
-                                       }
-                                       else
-                                               s++;
-                               }
-                               else
-                                       s++;
-                               continue;
-
-                       case PF_CHAR_IS_QUOTE:
-                               if(unlikely(!quote && s == t)) {
-                                       // quote opened at the beginning
-                                       quote = *s;
-                                       t = ++s;
-                               }
-                               else if(unlikely(quote && quote == *s)) {
-                                       // quote closed
-                                       quote = 0;
-
-                                       *s = '\0';
-                                       ff->words = pfwords_add(ff->words, t);
-                                       if(unlikely(!ff->words)) goto cleanup;
-
-                                       ff->lines->lines[l].words++;
-                                       w++;
-
-                                       t = ++s;
-                               }
-                               else
-                                       s++;
-                               continue;
-
-                       case PF_CHAR_IS_SEPARATOR:
-                               if(unlikely(quote || opened)) {
-                                       // we are inside a quote
-                                       s++;
-                                       continue;
-                               }
-
-                               if(unlikely(s == t)) {
-                                       // skip all leading white spaces
-                                       t = ++s;
-                                       continue;
-                               }
-
-                               // end of word
-                               *s = '\0';
-
-                               ff->words = pfwords_add(ff->words, t);
-                               if(unlikely(!ff->words)) goto cleanup;
-
-                               ff->lines->lines[l].words++;
-                               w++;
-
-                               t = ++s;
-                               continue;
-
-                       case PF_CHAR_IS_NEWLINE:
-                               // end of line
-                               *s = '\0';
-
-                               ff->words = pfwords_add(ff->words, t);
-                               if(unlikely(!ff->words)) goto cleanup;
-
-                               ff->lines->lines[l].words++;
-                               w++;
-
-                               // debug(D_PROCFILE, PF_PREFIX ":       ended line %d with %d words", l, ff->lines->lines[l].words);
-
-                               ff->lines = pflines_add(ff->lines, w);
-                               if(unlikely(!ff->lines)) goto cleanup;
-                               l++;
-
-                               t = ++s;
-                               continue;
-
-                       default:
-                               s++;
-                               continue;
-               }
-       }
-
-       if(likely(s > t && t < e)) {
-               // the last word
-               if(likely(ff->len < ff->size))
-                       *s = '\0';
-               else {
-                       // we are going to loose the last byte
-                       ff->data[ff->size - 1] = '\0';
-               }
-
-               ff->words = pfwords_add(ff->words, t);
-               if(unlikely(!ff->words)) goto cleanup;
-
-               ff->lines->lines[l].words++;
-               w++;
-       }
-
-       return ff;
+    debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
+
+    char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
+    uint32_t l = 0, w = 0;
+    int opened = 0;
+
+    ff->lines = pflines_add(ff->lines, w);
+    if(unlikely(!ff->lines)) goto cleanup;
+
+    while(likely(s < e)) {
+        // we are not at the end
+
+        switch(ff->separators[(uint8_t)(*s)]) {
+            case PF_CHAR_IS_OPEN:
+                if(s == t) {
+                    opened++;
+                    t = ++s;
+                }
+                else if(opened) {
+                    opened++;
+                    s++;
+                }
+                else
+                    s++;
+                continue;
+
+            case PF_CHAR_IS_CLOSE:
+                if(opened) {
+                    opened--;
+
+                    if(!opened) {
+                        *s = '\0';
+                        ff->words = pfwords_add(ff->words, t);
+                        if(unlikely(!ff->words)) goto cleanup;
+
+                        ff->lines->lines[l].words++;
+                        w++;
+
+                        t = ++s;
+                    }
+                    else
+                        s++;
+                }
+                else
+                    s++;
+                continue;
+
+            case PF_CHAR_IS_QUOTE:
+                if(unlikely(!quote && s == t)) {
+                    // quote opened at the beginning
+                    quote = *s;
+                    t = ++s;
+                }
+                else if(unlikely(quote && quote == *s)) {
+                    // quote closed
+                    quote = 0;
+
+                    *s = '\0';
+                    ff->words = pfwords_add(ff->words, t);
+                    if(unlikely(!ff->words)) goto cleanup;
+
+                    ff->lines->lines[l].words++;
+                    w++;
+
+                    t = ++s;
+                }
+                else
+                    s++;
+                continue;
+
+            case PF_CHAR_IS_SEPARATOR:
+                if(unlikely(quote || opened)) {
+                    // we are inside a quote
+                    s++;
+                    continue;
+                }
+
+                if(unlikely(s == t)) {
+                    // skip all leading white spaces
+                    t = ++s;
+                    continue;
+                }
+
+                // end of word
+                *s = '\0';
+
+                ff->words = pfwords_add(ff->words, t);
+                if(unlikely(!ff->words)) goto cleanup;
+
+                ff->lines->lines[l].words++;
+                w++;
+
+                t = ++s;
+                continue;
+
+            case PF_CHAR_IS_NEWLINE:
+                // end of line
+                *s = '\0';
+
+                ff->words = pfwords_add(ff->words, t);
+                if(unlikely(!ff->words)) goto cleanup;
+
+                ff->lines->lines[l].words++;
+                w++;
+
+                // debug(D_PROCFILE, PF_PREFIX ":   ended line %d with %d words", l, ff->lines->lines[l].words);
+
+                ff->lines = pflines_add(ff->lines, w);
+                if(unlikely(!ff->lines)) goto cleanup;
+                l++;
+
+                t = ++s;
+                continue;
+
+            default:
+                s++;
+                continue;
+        }
+    }
+
+    if(likely(s > t && t < e)) {
+        // the last word
+        if(likely(ff->len < ff->size))
+            *s = '\0';
+        else {
+            // we are going to loose the last byte
+            ff->data[ff->size - 1] = '\0';
+        }
+
+        ff->words = pfwords_add(ff->words, t);
+        if(unlikely(!ff->words)) goto cleanup;
+
+        ff->lines->lines[l].words++;
+        w++;
+    }
+
+    return ff;
 
 cleanup:
-       error(PF_PREFIX ": Failed to parse file '%s'", ff->filename);
-       procfile_close(ff);
-       return NULL;
+    error(PF_PREFIX ": Failed to parse file '%s'", ff->filename);
+    procfile_close(ff);
+    return NULL;
 }
 
 procfile *procfile_readall(procfile *ff) {
-       debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
+    debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
 
-       ssize_t s, r = 1, x;
-       ff->len = 0;
+    ssize_t s, r = 1, x;
+    ff->len = 0;
 
-       while(likely(r > 0)) {
-               s = ff->len;
-               x = ff->size - s;
+    while(likely(r > 0)) {
+        s = ff->len;
+        x = ff->size - s;
 
-               if(!x) {
-                       debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
+        if(!x) {
+            debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
 
-                       ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
-                       ff->size += PROCFILE_INCREMENT_BUFFER;
-               }
+            ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
+            ff->size += PROCFILE_INCREMENT_BUFFER;
+        }
 
-               debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
-               r = read(ff->fd, &ff->data[s], ff->size - s);
-               if(unlikely(r == -1)) {
-                       if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
-                       procfile_close(ff);
-                       return NULL;
-               }
+        debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
+        r = read(ff->fd, &ff->data[s], ff->size - s);
+        if(unlikely(r == -1)) {
+            if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
+            procfile_close(ff);
+            return NULL;
+        }
 
-               ff->len += r;
-       }
+        ff->len += r;
+    }
 
-       debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
-       if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
-               if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
-               procfile_close(ff);
-               return NULL;
-       }
+    debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
+    if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
+        if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
+        procfile_close(ff);
+        return NULL;
+    }
 
-       pflines_reset(ff->lines);
-       pfwords_reset(ff->words);
+    pflines_reset(ff->lines);
+    pfwords_reset(ff->words);
 
-       ff = procfile_parser(ff);
+    ff = procfile_parser(ff);
 
-       if(unlikely(procfile_adaptive_initial_allocation)) {
-               if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len;
-               if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len;
-               if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
-       }
+    if(unlikely(procfile_adaptive_initial_allocation)) {
+        if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len;
+        if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len;
+        if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
+    }
 
-       debug(D_PROCFILE, "File '%s' updated.", ff->filename);
-       return ff;
+    debug(D_PROCFILE, "File '%s' updated.", ff->filename);
+    return ff;
 }
 
 static void procfile_set_separators(procfile *ff, const char *separators) {
-       static char def[256] = { [0 ... 255] = 0 };
-       int i;
-
-       if(unlikely(!def[255])) {
-               // this is thread safe
-               // we check that the last byte is non-zero
-               // if it is zero, multiple threads may be executing this at the same time
-               // setting in def[] the exact same values
-               for(i = 0; likely(i < 256) ;i++) {
-                       if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
-                       else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
-                       else def[i] = PF_CHAR_IS_WORD;
-               }
-       }
-
-       // copy the default
-       char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
-       while(likely(ffd != ffe)) *ffs++ = *ffd++;
-
-       // set the separators
-       if(unlikely(!separators))
-               separators = " \t=|";
-
-       ffs = ff->separators;
-       const char *s = separators;
-       while(likely(*s))
-               ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
+    static char def[256] = { [0 ... 255] = 0 };
+    int i;
+
+    if(unlikely(!def[255])) {
+        // this is thread safe
+        // we check that the last byte is non-zero
+        // if it is zero, multiple threads may be executing this at the same time
+        // setting in def[] the exact same values
+        for(i = 0; likely(i < 256) ;i++) {
+            if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
+            else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
+            else def[i] = PF_CHAR_IS_WORD;
+        }
+    }
+
+    // copy the default
+    char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
+    while(likely(ffd != ffe)) *ffs++ = *ffd++;
+
+    // set the separators
+    if(unlikely(!separators))
+        separators = " \t=|";
+
+    ffs = ff->separators;
+    const char *s = separators;
+    while(likely(*s))
+        ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
 }
 
 void procfile_set_quotes(procfile *ff, const char *quotes) {
-       // remove all quotes
-       int i;
-       for(i = 0; i < 256 ; i++)
-               if(ff->separators[i] == PF_CHAR_IS_QUOTE)
-                       ff->separators[i] = PF_CHAR_IS_WORD;
-
-       // if nothing given, return
-       if(unlikely(!quotes || !*quotes))
-               return;
-
-       // set the quotes
-       char *ffs = ff->separators;
-       const char *s = quotes;
-       while(likely(*s))
-               ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
+    // remove all quotes
+    int i;
+    for(i = 0; i < 256 ; i++)
+        if(ff->separators[i] == PF_CHAR_IS_QUOTE)
+            ff->separators[i] = PF_CHAR_IS_WORD;
+
+    // if nothing given, return
+    if(unlikely(!quotes || !*quotes))
+        return;
+
+    // set the quotes
+    char *ffs = ff->separators;
+    const char *s = quotes;
+    while(likely(*s))
+        ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
 }
 
 void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
-       // remove all open/close
-       int i;
-       for(i = 0; i < 256 ; i++)
-               if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
-                       ff->separators[i] = PF_CHAR_IS_WORD;
-
-       // if nothing given, return
-       if(unlikely(!open || !*open || !close || !*close))
-               return;
-
-       // set the openings
-       char *ffs = ff->separators;
-       const char *s = open;
-       while(likely(*s))
-               ffs[(int)*s++] = PF_CHAR_IS_OPEN;
-
-       s = close;
-       while(likely(*s))
-               ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
+    // remove all open/close
+    int i;
+    for(i = 0; i < 256 ; i++)
+        if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
+            ff->separators[i] = PF_CHAR_IS_WORD;
+
+    // if nothing given, return
+    if(unlikely(!open || !*open || !close || !*close))
+        return;
+
+    // set the openings
+    char *ffs = ff->separators;
+    const char *s = open;
+    while(likely(*s))
+        ffs[(int)*s++] = PF_CHAR_IS_OPEN;
+
+    s = close;
+    while(likely(*s))
+        ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
 }
 
 procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
-       debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
+    debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
 
-       int fd = open(filename, O_RDONLY, 0666);
-       if(unlikely(fd == -1)) {
-               if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename);
-               return NULL;
-       }
+    int fd = open(filename, O_RDONLY, 0666);
+    if(unlikely(fd == -1)) {
+        if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename);
+        return NULL;
+    }
 
-       size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
-       procfile *ff = mallocz(sizeof(procfile) + size);
-       strncpyz(ff->filename, filename, FILENAME_MAX);
+    size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
+    procfile *ff = mallocz(sizeof(procfile) + size);
+    strncpyz(ff->filename, filename, FILENAME_MAX);
 
-       ff->fd = fd;
-       ff->size = size;
-       ff->len = 0;
-       ff->flags = flags;
+    ff->fd = fd;
+    ff->size = size;
+    ff->len = 0;
+    ff->flags = flags;
 
-       ff->lines = pflines_new();
-       ff->words = pfwords_new();
+    ff->lines = pflines_new();
+    ff->words = pfwords_new();
 
-       if(unlikely(!ff->lines || !ff->words)) {
-               error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename);
-               procfile_close(ff);
-               return NULL;
-       }
+    if(unlikely(!ff->lines || !ff->words)) {
+        error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename);
+        procfile_close(ff);
+        return NULL;
+    }
 
-       procfile_set_separators(ff, separators);
+    procfile_set_separators(ff, separators);
 
-       debug(D_PROCFILE, "File '%s' opened.", filename);
-       return ff;
+    debug(D_PROCFILE, "File '%s' opened.", filename);
+    return ff;
 }
 
 procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags) {
-       if(unlikely(!ff)) return procfile_open(filename, separators, flags);
+    if(unlikely(!ff)) return procfile_open(filename, separators, flags);
 
-       if(likely(ff->fd != -1)) close(ff->fd);
+    if(likely(ff->fd != -1)) close(ff->fd);
 
-       ff->fd = open(filename, O_RDONLY, 0666);
-       if(unlikely(ff->fd == -1)) {
-               procfile_close(ff);
-               return NULL;
-       }
+    ff->fd = open(filename, O_RDONLY, 0666);
+    if(unlikely(ff->fd == -1)) {
+        procfile_close(ff);
+        return NULL;
+    }
 
-       strncpyz(ff->filename, filename, FILENAME_MAX);
+    strncpyz(ff->filename, filename, FILENAME_MAX);
 
-       ff->flags = flags;
+    ff->flags = flags;
 
-       // do not do the separators again if NULL is given
-       if(likely(separators)) procfile_set_separators(ff, separators);
+    // do not do the separators again if NULL is given
+    if(likely(separators)) procfile_set_separators(ff, separators);
 
-       return ff;
+    return ff;
 }
 
 // ----------------------------------------------------------------------------
 // example parsing of procfile data
 
 void procfile_print(procfile *ff) {
-       uint32_t lines = procfile_lines(ff), l;
-       uint32_t words, w;
-       char *s;
+    uint32_t lines = procfile_lines(ff), l;
+    uint32_t words, w;
+    char *s;
 
-       debug(D_PROCFILE, "File '%s' with %u lines and %u words", ff->filename, ff->lines->len, ff->words->len);
+    debug(D_PROCFILE, "File '%s' with %u lines and %u words", ff->filename, ff->lines->len, ff->words->len);
 
-       for(l = 0; likely(l < lines) ;l++) {
-               words = procfile_linewords(ff, l);
+    for(l = 0; likely(l < lines) ;l++) {
+        words = procfile_linewords(ff, l);
 
-               debug(D_PROCFILE, "     line %u starts at word %u and has %u words", l, ff->lines->lines[l].first, ff->lines->lines[l].words);
+        debug(D_PROCFILE, " line %u starts at word %u and has %u words", l, ff->lines->lines[l].first, ff->lines->lines[l].words);
 
-               for(w = 0; likely(w < words) ;w++) {
-                       s = procfile_lineword(ff, l, w);
-                       debug(D_PROCFILE, "             [%u.%u] '%s'", l, w, s);
-               }
-       }
+        for(w = 0; likely(w < words) ;w++) {
+            s = procfile_lineword(ff, l, w);
+            debug(D_PROCFILE, "     [%u.%u] '%s'", l, w, s);
+        }
+    }
 }
index 122e153f1eb7c76bc320fa98ca90b38afaf8d34e..5e00b25842613e205aba7052647965d6c17694cf 100644 (file)
@@ -30,9 +30,9 @@
 // An array of words
 
 typedef struct {
-       uint32_t len;   // used entries
-       uint32_t size;  // capacity
-       char *words[];  // array of pointers
+    uint32_t len;   // used entries
+    uint32_t size;  // capacity
+    char *words[];  // array of pointers
 } pfwords;
 
 
@@ -40,15 +40,15 @@ typedef struct {
 // An array of lines
 
 typedef struct {
-       uint32_t words;         // how many words this line has
-       uint32_t first;         // the id of the first word of this line
-                               // in the words array
+    uint32_t words;     // how many words this line has
+    uint32_t first;     // the id of the first word of this line
+                // in the words array
 } ffline;
 
 typedef struct {
-       uint32_t len;           // used entries
-       uint32_t size;          // capacity
-       ffline lines[];         // array of lines
+    uint32_t len;       // used entries
+    uint32_t size;      // capacity
+    ffline lines[];     // array of lines
 } pflines;
 
 
@@ -59,15 +59,15 @@ typedef struct {
 #define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
 
 typedef struct {
-       char filename[FILENAME_MAX + 1];
-       uint32_t flags;
-       int fd;                 // the file desriptor
-       size_t len;             // the bytes we have placed into data
-       size_t size;            // the bytes we have allocated for data
-       pflines *lines;
-       pfwords *words;
-       char separators[256];
-       char data[];            // allocated buffer to keep file contents
+    char filename[FILENAME_MAX + 1];
+    uint32_t flags;
+    int fd;         // the file desriptor
+    size_t len;     // the bytes we have placed into data
+    size_t size;        // the bytes we have allocated for data
+    pflines *lines;
+    pfwords *words;
+    char separators[256];
+    char data[];        // allocated buffer to keep file contents
 } procfile;
 
 // close the proc file and free all related memory
index 988ed78d67a3c8203efadbeea141b73ff392bb8d..e43c16b1b759fea61f0c679810d07fd31aeb2a1e 100644 (file)
 // COMMON structures
 
 struct registry {
-       int enabled;
-
-       char machine_guid[36 + 1];
-
-       // entries counters / statistics
-       unsigned long long persons_count;
-       unsigned long long machines_count;
-       unsigned long long usages_count;
-       unsigned long long urls_count;
-       unsigned long long persons_urls_count;
-       unsigned long long machines_urls_count;
-       unsigned long long log_count;
-
-       // memory counters / statistics
-       unsigned long long persons_memory;
-       unsigned long long machines_memory;
-       unsigned long long urls_memory;
-       unsigned long long persons_urls_memory;
-       unsigned long long machines_urls_memory;
-
-       // configuration
-       unsigned long long save_registry_every_entries;
-       char *registry_domain;
-       char *hostname;
-       char *registry_to_announce;
-       time_t persons_expiration; // seconds to expire idle persons
-       int verify_cookies_redirects;
-
-       size_t max_url_length;
-       size_t max_name_length;
-
-       // file/path names
-       char *pathname;
-       char *db_filename;
-       char *log_filename;
-       char *machine_guid_filename;
-
-       // open files
-       FILE *log_fp;
-
-       // the database
-       DICTIONARY *persons;    // dictionary of PERSON *, with key the PERSON.guid
-       DICTIONARY *machines;   // dictionary of MACHINE *, with key the MACHINE.guid
-       DICTIONARY *urls;               // dictionary of URL *, with key the URL.url
-
-       // concurrency locking
-       // we keep different locks for different things
-       // so that many tasks can be completed in parallel
-       pthread_mutex_t persons_lock;
-       pthread_mutex_t machines_lock;
-       pthread_mutex_t urls_lock;
-       pthread_mutex_t person_urls_lock;
-       pthread_mutex_t machine_urls_lock;
-       pthread_mutex_t log_lock;
+    int enabled;
+
+    char machine_guid[36 + 1];
+
+    // entries counters / statistics
+    unsigned long long persons_count;
+    unsigned long long machines_count;
+    unsigned long long usages_count;
+    unsigned long long urls_count;
+    unsigned long long persons_urls_count;
+    unsigned long long machines_urls_count;
+    unsigned long long log_count;
+
+    // memory counters / statistics
+    unsigned long long persons_memory;
+    unsigned long long machines_memory;
+    unsigned long long urls_memory;
+    unsigned long long persons_urls_memory;
+    unsigned long long machines_urls_memory;
+
+    // configuration
+    unsigned long long save_registry_every_entries;
+    char *registry_domain;
+    char *hostname;
+    char *registry_to_announce;
+    time_t persons_expiration; // seconds to expire idle persons
+    int verify_cookies_redirects;
+
+    size_t max_url_length;
+    size_t max_name_length;
+
+    // file/path names
+    char *pathname;
+    char *db_filename;
+    char *log_filename;
+    char *machine_guid_filename;
+
+    // open files
+    FILE *log_fp;
+
+    // the database
+    DICTIONARY *persons;    // dictionary of PERSON *, with key the PERSON.guid
+    DICTIONARY *machines;   // dictionary of MACHINE *, with key the MACHINE.guid
+    DICTIONARY *urls;       // dictionary of URL *, with key the URL.url
+
+    // concurrency locking
+    // we keep different locks for different things
+    // so that many tasks can be completed in parallel
+    pthread_mutex_t persons_lock;
+    pthread_mutex_t machines_lock;
+    pthread_mutex_t urls_lock;
+    pthread_mutex_t person_urls_lock;
+    pthread_mutex_t machine_urls_lock;
+    pthread_mutex_t log_lock;
 } registry;
 
 
@@ -103,9 +103,9 @@ struct registry {
 // we store them here and we keep pointers elsewhere
 
 struct url {
-       uint32_t links; // the number of links to this URL - when none is left, we free it
-       uint16_t len;   // the length of the URL in bytes
-       char url[1];    // the URL - dynamically allocated to more size
+    uint32_t links; // the number of links to this URL - when none is left, we free it
+    uint16_t len;   // the length of the URL in bytes
+    char url[1];    // the URL - dynamically allocated to more size
 };
 typedef struct url URL;
 
@@ -115,27 +115,27 @@ typedef struct url URL;
 
 // For each MACHINE-URL pair we keep this
 struct machine_url {
-       URL *url;                                       // de-duplicated URL
-//     DICTIONARY *persons;            // dictionary of PERSON *
+    URL *url;                   // de-duplicated URL
+//  DICTIONARY *persons;        // dictionary of PERSON *
 
-       uint8_t flags;
-       uint32_t first_t;                       // the first time we saw this
-       uint32_t last_t;                        // the last time we saw this
-       uint32_t usages;                        // how many times this has been accessed
+    uint8_t flags;
+    uint32_t first_t;           // the first time we saw this
+    uint32_t last_t;            // the last time we saw this
+    uint32_t usages;            // how many times this has been accessed
 };
 typedef struct machine_url MACHINE_URL;
 
 // A machine
 struct machine {
-       char guid[36 + 1];                      // the GUID
+    char guid[36 + 1];          // the GUID
 
-       uint32_t links;                         // the number of PERSON_URLs linked to this machine
+    uint32_t links;             // the number of PERSON_URLs linked to this machine
 
-       DICTIONARY *urls;                       // MACHINE_URL *
+    DICTIONARY *urls;           // MACHINE_URL *
 
-       uint32_t first_t;                       // the first time we saw this
-       uint32_t last_t;                        // the last time we saw this
-       uint32_t usages;                        // how many times this has been accessed
+    uint32_t first_t;           // the first time we saw this
+    uint32_t last_t;            // the last time we saw this
+    uint32_t usages;            // how many times this has been accessed
 };
 typedef struct machine MACHINE;
 
@@ -145,28 +145,28 @@ typedef struct machine MACHINE;
 
 // for each PERSON-URL pair we keep this
 struct person_url {
-       URL *url;                                       // de-duplicated URL
-       MACHINE *machine;                       // link the MACHINE of this URL
+    URL *url;                   // de-duplicated URL
+    MACHINE *machine;           // link the MACHINE of this URL
 
-       uint8_t flags;
-       uint32_t first_t;                       // the first time we saw this
-       uint32_t last_t;                        // the last time we saw this
-       uint32_t usages;                        // how many times this has been accessed
+    uint8_t flags;
+    uint32_t first_t;           // the first time we saw this
+    uint32_t last_t;            // the last time we saw this
+    uint32_t usages;            // how many times this has been accessed
 
-       char name[1];                           // the name of the URL, as known by the user
-                                                               // dynamically allocated to fit properly
+    char name[1];               // the name of the URL, as known by the user
+                                // dynamically allocated to fit properly
 };
 typedef struct person_url PERSON_URL;
 
 // A person
 struct person {
-       char guid[36 + 1];                      // the person GUID
+    char guid[36 + 1];          // the person GUID
 
-       DICTIONARY *urls;                       // dictionary of PERSON_URL *
+    DICTIONARY *urls;           // dictionary of PERSON_URL *
 
-       uint32_t first_t;                       // the first time we saw this
-       uint32_t last_t;                        // the last time we saw this
-       uint32_t usages;                        // how many times this has been accessed
+    uint32_t first_t;           // the first time we saw this
+    uint32_t last_t;            // the last time we saw this
+    uint32_t usages;            // how many times this has been accessed
 };
 typedef struct person PERSON;
 
@@ -175,27 +175,27 @@ typedef struct person PERSON;
 // REGISTRY concurrency locking
 
 static inline void registry_persons_lock(void) {
-       pthread_mutex_lock(&registry.persons_lock);
+    pthread_mutex_lock(&registry.persons_lock);
 }
 
 static inline void registry_persons_unlock(void) {
-       pthread_mutex_unlock(&registry.persons_lock);
+    pthread_mutex_unlock(&registry.persons_lock);
 }
 
 static inline void registry_machines_lock(void) {
-       pthread_mutex_lock(&registry.machines_lock);
+    pthread_mutex_lock(&registry.machines_lock);
 }
 
 static inline void registry_machines_unlock(void) {
-       pthread_mutex_unlock(&registry.machines_lock);
+    pthread_mutex_unlock(&registry.machines_lock);
 }
 
 static inline void registry_urls_lock(void) {
-       pthread_mutex_lock(&registry.urls_lock);
+    pthread_mutex_lock(&registry.urls_lock);
 }
 
 static inline void registry_urls_unlock(void) {
-       pthread_mutex_unlock(&registry.urls_lock);
+    pthread_mutex_unlock(&registry.urls_lock);
 }
 
 // ideally, we should not lock the whole registry for
@@ -203,13 +203,13 @@ static inline void registry_urls_unlock(void) {
 // however, to save the memory required for keeping a
 // mutex (40 bytes) per person, we do...
 static inline void registry_person_urls_lock(PERSON *p) {
-       (void)p;
-       pthread_mutex_lock(&registry.person_urls_lock);
+    (void)p;
+    pthread_mutex_lock(&registry.person_urls_lock);
 }
 
 static inline void registry_person_urls_unlock(PERSON *p) {
-       (void)p;
-       pthread_mutex_unlock(&registry.person_urls_lock);
+    (void)p;
+    pthread_mutex_unlock(&registry.person_urls_lock);
 }
 
 // ideally, we should not lock the whole registry for
@@ -217,21 +217,21 @@ static inline void registry_person_urls_unlock(PERSON *p) {
 // however, to save the memory required for keeping a
 // mutex (40 bytes) per machine, we do...
 static inline void registry_machine_urls_lock(MACHINE *m) {
-       (void)m;
-       pthread_mutex_lock(&registry.machine_urls_lock);
+    (void)m;
+    pthread_mutex_lock(&registry.machine_urls_lock);
 }
 
 static inline void registry_machine_urls_unlock(MACHINE *m) {
-       (void)m;
-       pthread_mutex_unlock(&registry.machine_urls_lock);
+    (void)m;
+    pthread_mutex_unlock(&registry.machine_urls_lock);
 }
 
 static inline void registry_log_lock(void) {
-       pthread_mutex_lock(&registry.log_lock);
+    pthread_mutex_lock(&registry.log_lock);
 }
 
 static inline void registry_log_unlock(void) {
-       pthread_mutex_unlock(&registry.log_lock);
+    pthread_mutex_unlock(&registry.log_lock);
 }
 
 
@@ -241,58 +241,58 @@ static inline void registry_log_unlock(void) {
 // parse a GUID and re-generated to be always lower case
 // this is used as a protection against the variations of GUIDs
 static inline int registry_regenerate_guid(const char *guid, char *result) {
-       uuid_t uuid;
-       if(unlikely(uuid_parse(guid, uuid) == -1)) {
-               info("Registry: GUID '%s' is not a valid GUID.", guid);
-               return -1;
-       }
-       else {
-               uuid_unparse_lower(uuid, result);
+    uuid_t uuid;
+    if(unlikely(uuid_parse(guid, uuid) == -1)) {
+        info("Registry: GUID '%s' is not a valid GUID.", guid);
+        return -1;
+    }
+    else {
+        uuid_unparse_lower(uuid, result);
 
 #ifdef NETDATA_INTERNAL_CHECKS
-               if(strcmp(guid, result))
-                       info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
+        if(strcmp(guid, result))
+            info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
 #endif /* NETDATA_INTERNAL_CHECKS */
-       }
+    }
 
-       return 0;
+    return 0;
 }
 
 // make sure the names of the machines / URLs do not contain any tabs
 // (which are used as our separator in the database files)
 // and are properly trimmed (before and after)
 static inline char *registry_fix_machine_name(char *name, size_t *len) {
-       char *s = name?name:"";
+    char *s = name?name:"";
 
-       // skip leading spaces
-       while(*s && isspace(*s)) s++;
+    // skip leading spaces
+    while(*s && isspace(*s)) s++;
 
-       // make sure all spaces are a SPACE
-       char *t = s;
-       while(*t) {
-               if(unlikely(isspace(*t)))
-                       *t = ' ';
+    // make sure all spaces are a SPACE
+    char *t = s;
+    while(*t) {
+        if(unlikely(isspace(*t)))
+            *t = ' ';
 
-               t++;
-       }
+        t++;
+    }
 
-       // remove trailing spaces
-       while(--t >= s) {
-               if(*t == ' ')
-                       *t = '\0';
-               else
-                       break;
-       }
-       t++;
+    // remove trailing spaces
+    while(--t >= s) {
+        if(*t == ' ')
+            *t = '\0';
+        else
+            break;
+    }
+    t++;
 
-       if(likely(len))
-               *len = (t - s);
+    if(likely(len))
+        *len = (t - s);
 
-       return s;
+    return s;
 }
 
 static inline char *registry_fix_url(char *url, size_t *len) {
-       return registry_fix_machine_name(url, len);
+    return registry_fix_machine_name(url, len);
 }
 
 
@@ -307,57 +307,57 @@ extern PERSON *registry_request_delete(char *person_guid, char *machine_guid, ch
 // URL
 
 static inline URL *registry_url_allocate_nolock(const char *url, size_t urllen) {
-       // protection from too big URLs
-       if(urllen > registry.max_url_length)
-               urllen = registry.max_url_length;
+    // protection from too big URLs
+    if(urllen > registry.max_url_length)
+        urllen = registry.max_url_length;
 
-       debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(URL) + urllen);
-       URL *u = mallocz(sizeof(URL) + urllen);
+    debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(URL) + urllen);
+    URL *u = mallocz(sizeof(URL) + urllen);
 
-       // a simple strcpy() should do the job
-       // but I prefer to be safe, since the caller specified urllen
-       u->len = (uint16_t)urllen;
-       strncpyz(u->url, url, u->len);
-       u->links = 0;
+    // a simple strcpy() should do the job
+    // but I prefer to be safe, since the caller specified urllen
+    u->len = (uint16_t)urllen;
+    strncpyz(u->url, url, u->len);
+    u->links = 0;
 
-       registry.urls_memory += sizeof(URL) + urllen;
+    registry.urls_memory += sizeof(URL) + urllen;
 
-       debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): indexing it", url);
-       dictionary_set(registry.urls, u->url, u, sizeof(URL));
+    debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): indexing it", url);
+    dictionary_set(registry.urls, u->url, u, sizeof(URL));
 
-       return u;
+    return u;
 }
 
 static inline URL *registry_url_get(const char *url, size_t urllen) {
-       debug(D_REGISTRY, "Registry: registry_url_get('%s')", url);
+    debug(D_REGISTRY, "Registry: registry_url_get('%s')", url);
 
-       registry_urls_lock();
+    registry_urls_lock();
 
-       URL *u = dictionary_get(registry.urls, url);
-       if(!u) {
-               u = registry_url_allocate_nolock(url, urllen);
-               registry.urls_count++;
-       }
+    URL *u = dictionary_get(registry.urls, url);
+    if(!u) {
+        u = registry_url_allocate_nolock(url, urllen);
+        registry.urls_count++;
+    }
 
-       registry_urls_unlock();
+    registry_urls_unlock();
 
-       return u;
+    return u;
 }
 
 static inline void registry_url_link_nolock(URL *u) {
-       u->links++;
-       debug(D_REGISTRY, "Registry: registry_url_link_nolock('%s'): URL has now %u links", u->url, u->links);
+    u->links++;
+    debug(D_REGISTRY, "Registry: registry_url_link_nolock('%s'): URL has now %u links", u->url, u->links);
 }
 
 static inline void registry_url_unlink_nolock(URL *u) {
-       u->links--;
-       if(!u->links) {
-               debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
-               dictionary_del(registry.urls, u->url);
-               freez(u);
-       }
-       else
-               debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
+    u->links--;
+    if(!u->links) {
+        debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
+        dictionary_del(registry.urls, u->url);
+        freez(u);
+    }
+    else
+        debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
 }
 
 
@@ -365,76 +365,76 @@ static inline void registry_url_unlink_nolock(URL *u) {
 // MACHINE
 
 static inline MACHINE *registry_machine_find(const char *machine_guid) {
-       debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
-       return dictionary_get(registry.machines, machine_guid);
+    debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
+    return dictionary_get(registry.machines, machine_guid);
 }
 
 static inline MACHINE_URL *registry_machine_url_allocate(MACHINE *m, URL *u, time_t when) {
-       debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL));
+    debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL));
 
-       MACHINE_URL *mu = mallocz(sizeof(MACHINE_URL));
+    MACHINE_URL *mu = mallocz(sizeof(MACHINE_URL));
 
-       // mu->persons = dictionary_create(DICTIONARY_FLAGS);
-       // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
+    // mu->persons = dictionary_create(DICTIONARY_FLAGS);
+    // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
 
-       mu->first_t = mu->last_t = (uint32_t)when;
-       mu->usages = 1;
-       mu->url = u;
-       mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
+    mu->first_t = mu->last_t = (uint32_t)when;
+    mu->usages = 1;
+    mu->url = u;
+    mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
 
-       registry.machines_urls_memory += sizeof(MACHINE_URL);
+    registry.machines_urls_memory += sizeof(MACHINE_URL);
 
-       debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url);
-       dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL));
-       registry_url_link_nolock(u);
+    debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url);
+    dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL));
+    registry_url_link_nolock(u);
 
-       return mu;
+    return mu;
 }
 
 static inline MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) {
-       debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(MACHINE));
+    debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(MACHINE));
 
-       MACHINE *m = mallocz(sizeof(MACHINE));
+    MACHINE *m = mallocz(sizeof(MACHINE));
 
-       strncpyz(m->guid, machine_guid, 36);
+    strncpyz(m->guid, machine_guid, 36);
 
-       debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
-       m->urls = dictionary_create(DICTIONARY_FLAGS);
+    debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
+    m->urls = dictionary_create(DICTIONARY_FLAGS);
 
-       m->first_t = m->last_t = (uint32_t)when;
-       m->usages = 0;
+    m->first_t = m->last_t = (uint32_t)when;
+    m->usages = 0;
 
-       registry.machines_memory += sizeof(MACHINE);
+    registry.machines_memory += sizeof(MACHINE);
 
-       registry.machines_count++;
-       dictionary_set(registry.machines, m->guid, m, sizeof(MACHINE));
+    registry.machines_count++;
+    dictionary_set(registry.machines, m->guid, m, sizeof(MACHINE));
 
-       return m;
+    return m;
 }
 
 // 1. validate machine GUID
 // 2. if it is valid, find it or create it and return it
 // 3. if it is not valid, return NULL
 static inline MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
-       MACHINE *m = NULL;
+    MACHINE *m = NULL;
 
-       registry_machines_lock();
+    registry_machines_lock();
 
-       if(likely(machine_guid && *machine_guid)) {
-               // validate it is a GUID
-               char buf[36 + 1];
-               if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
-                       info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
-               else {
-                       machine_guid = buf;
-                       m = registry_machine_find(machine_guid);
-                       if(!m) m = registry_machine_allocate(machine_guid, when);
-               }
-       }
+    if(likely(machine_guid && *machine_guid)) {
+        // validate it is a GUID
+        char buf[36 + 1];
+        if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
+            info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
+        else {
+            machine_guid = buf;
+            m = registry_machine_find(machine_guid);
+            if(!m) m = registry_machine_allocate(machine_guid, when);
+        }
+    }
 
-       registry_machines_unlock();
+    registry_machines_unlock();
 
-       return m;
+    return m;
 }
 
 
@@ -442,99 +442,99 @@ static inline MACHINE *registry_machine_get(const char *machine_guid, time_t whe
 // PERSON
 
 static inline PERSON *registry_person_find(const char *person_guid) {
-       debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
-       return dictionary_get(registry.persons, person_guid);
+    debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
+    return dictionary_get(registry.persons, person_guid);
 }
 
 static inline PERSON_URL *registry_person_url_allocate(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when) {
-       // protection from too big names
-       if(namelen > registry.max_name_length)
-               namelen = registry.max_name_length;
+    // protection from too big names
+    if(namelen > registry.max_name_length)
+        namelen = registry.max_name_length;
 
-       debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
-                 sizeof(PERSON_URL) + namelen);
+    debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
+          sizeof(PERSON_URL) + namelen);
 
-       PERSON_URL *pu = mallocz(sizeof(PERSON_URL) + namelen);
+    PERSON_URL *pu = mallocz(sizeof(PERSON_URL) + namelen);
 
-       // a simple strcpy() should do the job
-       // but I prefer to be safe, since the caller specified urllen
-       strncpyz(pu->name, name, namelen);
+    // a simple strcpy() should do the job
+    // but I prefer to be safe, since the caller specified urllen
+    strncpyz(pu->name, name, namelen);
 
-       pu->machine = m;
-       pu->first_t = pu->last_t = when;
-       pu->usages = 1;
-       pu->url = u;
-       pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
-       m->links++;
+    pu->machine = m;
+    pu->first_t = pu->last_t = when;
+    pu->usages = 1;
+    pu->url = u;
+    pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
+    m->links++;
 
-       registry.persons_urls_memory += sizeof(PERSON_URL) + namelen;
+    registry.persons_urls_memory += sizeof(PERSON_URL) + namelen;
 
-       debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
-       dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL));
-       registry_url_link_nolock(u);
+    debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
+    dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL));
+    registry_url_link_nolock(u);
 
-       return pu;
+    return pu;
 }
 
 static inline PERSON_URL *registry_person_url_reallocate(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when, PERSON_URL *pu) {
-       // this function is needed to change the name of a PERSON_URL
+    // this function is needed to change the name of a PERSON_URL
 
-       debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
-                 sizeof(PERSON_URL) + namelen);
+    debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
+          sizeof(PERSON_URL) + namelen);
 
-       PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
-       tpu->first_t = pu->first_t;
-       tpu->last_t = pu->last_t;
-       tpu->usages = pu->usages;
+    PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
+    tpu->first_t = pu->first_t;
+    tpu->last_t = pu->last_t;
+    tpu->usages = pu->usages;
 
-       // ok, these are a hack - since the registry_person_url_allocate() is
-       // adding these, we have to subtract them
-       tpu->machine->links--;
-       registry.persons_urls_memory -= sizeof(PERSON_URL) + strlen(pu->name);
-       registry_url_unlink_nolock(u);
+    // ok, these are a hack - since the registry_person_url_allocate() is
+    // adding these, we have to subtract them
+    tpu->machine->links--;
+    registry.persons_urls_memory -= sizeof(PERSON_URL) + strlen(pu->name);
+    registry_url_unlink_nolock(u);
 
-       freez(pu);
+    freez(pu);
 
-       return tpu;
+    return tpu;
 }
 
 static inline PERSON *registry_person_allocate(const char *person_guid, time_t when) {
-       PERSON *p = NULL;
+    PERSON *p = NULL;
 
-       debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON));
+    debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON));
 
-       p = mallocz(sizeof(PERSON));
+    p = mallocz(sizeof(PERSON));
 
-       if(!person_guid) {
-               for (; ;) {
-                       uuid_t uuid;
-                       uuid_generate(uuid);
-                       uuid_unparse_lower(uuid, p->guid);
+    if(!person_guid) {
+        for (; ;) {
+            uuid_t uuid;
+            uuid_generate(uuid);
+            uuid_unparse_lower(uuid, p->guid);
 
-                       debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
-                       if (!dictionary_get(registry.persons, p->guid)) {
-                               debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
-                               break;
-                       }
-                       else
-                               info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
-               }
-       }
-       else
-               strncpyz(p->guid, person_guid, 36);
+            debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
+            if (!dictionary_get(registry.persons, p->guid)) {
+                debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
+                break;
+            }
+            else
+                info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
+        }
+    }
+    else
+        strncpyz(p->guid, person_guid, 36);
 
-       debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
-       p->urls = dictionary_create(DICTIONARY_FLAGS);
+    debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
+    p->urls = dictionary_create(DICTIONARY_FLAGS);
 
-       p->first_t = p->last_t = when;
-       p->usages = 0;
+    p->first_t = p->last_t = when;
+    p->usages = 0;
 
-       registry.persons_memory += sizeof(PERSON);
+    registry.persons_memory += sizeof(PERSON);
 
-       registry.persons_count++;
-       dictionary_set(registry.persons, p->guid, p, sizeof(PERSON));
+    registry.persons_count++;
+    dictionary_set(registry.persons, p->guid, p, sizeof(PERSON));
 
-       return p;
+    return p;
 }
 
 
@@ -543,260 +543,260 @@ static inline PERSON *registry_person_allocate(const char *person_guid, time_t w
 // 3. if it is not valid, create a new one
 // 4. return it
 static inline PERSON *registry_person_get(const char *person_guid, time_t when) {
-       PERSON *p = NULL;
+    PERSON *p = NULL;
 
-       registry_persons_lock();
+    registry_persons_lock();
 
-       if(person_guid && *person_guid) {
-               char buf[36 + 1];
-               // validate it is a GUID
-               if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
-                       info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
-               else {
-                       person_guid = buf;
-                       p = registry_person_find(person_guid);
-                       if(!p) person_guid = NULL;
-               }
-       }
+    if(person_guid && *person_guid) {
+        char buf[36 + 1];
+        // validate it is a GUID
+        if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
+            info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
+        else {
+            person_guid = buf;
+            p = registry_person_find(person_guid);
+            if(!p) person_guid = NULL;
+        }
+    }
 
-       if(!p) p = registry_person_allocate(NULL, when);
+    if(!p) p = registry_person_allocate(NULL, when);
 
-       registry_persons_unlock();
+    registry_persons_unlock();
 
-       return p;
+    return p;
 }
 
 // ----------------------------------------------------------------------------
 // LINKING OF OBJECTS
 
 static inline PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when) {
-       debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
-
-       registry_person_urls_lock(p);
-
-       PERSON_URL *pu = dictionary_get(p->urls, u->url);
-       if(!pu) {
-               debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
-               pu = registry_person_url_allocate(p, m, u, name, namelen, when);
-               registry.persons_urls_count++;
-       }
-       else {
-               debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
-               pu->usages++;
-               if(likely(pu->last_t < (uint32_t)when)) pu->last_t = when;
-
-               if(pu->machine != m) {
-                       MACHINE_URL *mu = dictionary_get(pu->machine->urls, u->url);
-                       if(mu) {
-                               info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
-                                        p->guid, m->guid, u->url, pu->machine->guid);
-                               mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
-                       }
-                       else {
-                               info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
-                                        p->guid, m->guid, u->url, pu->machine->guid);
-                       }
-
-                       pu->machine->links--;
-                       pu->machine = m;
-               }
-
-               if(strcmp(pu->name, name)) {
-                       // the name of the PERSON_URL has changed !
-                       pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
-               }
-       }
-
-       p->usages++;
-       if(likely(p->last_t < (uint32_t)when)) p->last_t = when;
-
-       if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
-               info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
-               pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
-       }
-
-       registry_person_urls_unlock(p);
-
-       return pu;
+    debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
+
+    registry_person_urls_lock(p);
+
+    PERSON_URL *pu = dictionary_get(p->urls, u->url);
+    if(!pu) {
+        debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
+        pu = registry_person_url_allocate(p, m, u, name, namelen, when);
+        registry.persons_urls_count++;
+    }
+    else {
+        debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
+        pu->usages++;
+        if(likely(pu->last_t < (uint32_t)when)) pu->last_t = when;
+
+        if(pu->machine != m) {
+            MACHINE_URL *mu = dictionary_get(pu->machine->urls, u->url);
+            if(mu) {
+                info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
+                     p->guid, m->guid, u->url, pu->machine->guid);
+                mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
+            }
+            else {
+                info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
+                     p->guid, m->guid, u->url, pu->machine->guid);
+            }
+
+            pu->machine->links--;
+            pu->machine = m;
+        }
+
+        if(strcmp(pu->name, name)) {
+            // the name of the PERSON_URL has changed !
+            pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
+        }
+    }
+
+    p->usages++;
+    if(likely(p->last_t < (uint32_t)when)) p->last_t = when;
+
+    if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
+        info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
+        pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
+    }
+
+    registry_person_urls_unlock(p);
+
+    return pu;
 }
 
 static inline MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, URL *u, time_t when) {
-       debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): searching for URL in machine", p->guid, m->guid, u->url);
+    debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): searching for URL in machine", p->guid, m->guid, u->url);
 
-       registry_machine_urls_lock(m);
+    registry_machine_urls_lock(m);
 
-       MACHINE_URL *mu = dictionary_get(m->urls, u->url);
-       if(!mu) {
-               debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
-               mu = registry_machine_url_allocate(m, u, when);
-               registry.machines_urls_count++;
-       }
-       else {
-               debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
-               mu->usages++;
-               if(likely(mu->last_t < (uint32_t)when)) mu->last_t = when;
-       }
+    MACHINE_URL *mu = dictionary_get(m->urls, u->url);
+    if(!mu) {
+        debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
+        mu = registry_machine_url_allocate(m, u, when);
+        registry.machines_urls_count++;
+    }
+    else {
+        debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
+        mu->usages++;
+        if(likely(mu->last_t < (uint32_t)when)) mu->last_t = when;
+    }
 
-       //debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing person in machine", p->guid, m->guid, u->url);
-       //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
+    //debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing person in machine", p->guid, m->guid, u->url);
+    //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
 
-       m->usages++;
-       if(likely(m->last_t < (uint32_t)when)) m->last_t = when;
+    m->usages++;
+    if(likely(m->last_t < (uint32_t)when)) m->last_t = when;
 
-       if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
-               info("registry_machine_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url);
-               mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
-       }
+    if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
+        info("registry_machine_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url);
+        mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
+    }
 
-       registry_machine_urls_unlock(m);
+    registry_machine_urls_unlock(m);
 
-       return mu;
+    return mu;
 }
 
 // ----------------------------------------------------------------------------
 // REGISTRY LOG LOAD/SAVE
 
 static inline int registry_should_save_db(void) {
-       debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries);
-       return registry.log_count > registry.save_registry_every_entries;
+    debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries);
+    return registry.log_count > registry.save_registry_every_entries;
 }
 
 static inline void registry_log(const char action, PERSON *p, MACHINE *m, URL *u, char *name) {
-       if(likely(registry.log_fp)) {
-               // we lock only if the file is open
-               // to allow replaying the log at registry_log_load()
-               registry_log_lock();
-
-               if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
-                               action,
-                               p->last_t,
-                               p->guid,
-                               m->guid,
-                               name,
-                               u->url) < 0))
-                       error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
-
-               // we increase the counter even on failures
-               // so that the registry will be saved periodically
-               registry.log_count++;
-
-               registry_log_unlock();
-
-               // this must be outside the log_lock(), or a deadlock will happen.
-               // registry_save() checks the same inside the log_lock, so only
-               // one thread will save the db
-               if(unlikely(registry_should_save_db()))
-                       registry_save();
-       }
+    if(likely(registry.log_fp)) {
+        // we lock only if the file is open
+        // to allow replaying the log at registry_log_load()
+        registry_log_lock();
+
+        if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
+                action,
+                p->last_t,
+                p->guid,
+                m->guid,
+                name,
+                u->url) < 0))
+            error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
+
+        // we increase the counter even on failures
+        // so that the registry will be saved periodically
+        registry.log_count++;
+
+        registry_log_unlock();
+
+        // this must be outside the log_lock(), or a deadlock will happen.
+        // registry_save() checks the same inside the log_lock, so only
+        // one thread will save the db
+        if(unlikely(registry_should_save_db()))
+            registry_save();
+    }
 }
 
 static inline int registry_log_open_nolock(void) {
-       if(registry.log_fp)
-               fclose(registry.log_fp);
+    if(registry.log_fp)
+        fclose(registry.log_fp);
 
-       registry.log_fp = fopen(registry.log_filename, "a");
+    registry.log_fp = fopen(registry.log_filename, "a");
 
-       if(registry.log_fp) {
-               if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
-                       error("Cannot set line buffering on registry log file.");
-               return 0;
-       }
+    if(registry.log_fp) {
+        if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
+            error("Cannot set line buffering on registry log file.");
+        return 0;
+    }
 
-       error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
-       return -1;
+    error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
+    return -1;
 }
 
 static inline void registry_log_close_nolock(void) {
-       if(registry.log_fp) {
-               fclose(registry.log_fp);
-               registry.log_fp = NULL;
-       }
+    if(registry.log_fp) {
+        fclose(registry.log_fp);
+        registry.log_fp = NULL;
+    }
 }
 
 static inline void registry_log_recreate_nolock(void) {
-       if(registry.log_fp != NULL) {
-               registry_log_close_nolock();
+    if(registry.log_fp != NULL) {
+        registry_log_close_nolock();
 
-               // open it with truncate
-               registry.log_fp = fopen(registry.log_filename, "w");
-               if(registry.log_fp) fclose(registry.log_fp);
-               else error("Cannot truncate registry log '%s'", registry.log_filename);
+        // open it with truncate
+        registry.log_fp = fopen(registry.log_filename, "w");
+        if(registry.log_fp) fclose(registry.log_fp);
+        else error("Cannot truncate registry log '%s'", registry.log_filename);
 
-               registry.log_fp = NULL;
+        registry.log_fp = NULL;
 
-               registry_log_open_nolock();
-       }
+        registry_log_open_nolock();
+    }
 }
 
 int registry_log_load(void) {
-       char *s, buf[4096 + 1];
-       size_t line = -1;
-
-       // closing the log is required here
-       // otherwise we will append to it the values we read
-       registry_log_close_nolock();
-
-       debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
-       FILE *fp = fopen(registry.log_filename, "r");
-       if(!fp)
-               error("Registry: cannot open registry file: %s", registry.log_filename);
-       else {
-               line = 0;
-               size_t len = 0;
-               while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
-                       line++;
-
-                       switch (s[0]) {
-                               case 'A': // accesses
-                               case 'D': // deletes
-
-                                       // verify it is valid
-                                       if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
-                                               error("Registry: log line %zu is wrong (len = %zu).", line, len);
-                                               continue;
-                                       }
-                                       s[1] = s[10] = s[47] = s[84] = '\0';
-
-                                       // get the variables
-                                       time_t when = strtoul(&s[2], NULL, 16);
-                                       char *person_guid = &s[11];
-                                       char *machine_guid = &s[48];
-                                       char *name = &s[85];
-
-                                       // skip the name to find the url
-                                       char *url = name;
-                                       while(*url && *url != '\t') url++;
-                                       if(!*url) {
-                                               error("Registry: log line %zu does not have a url.", line);
-                                               continue;
-                                       }
-                                       *url++ = '\0';
-
-                                       // make sure the person exists
-                                       // without this, a new person guid will be created
-                                       PERSON *p = registry_person_find(person_guid);
-                                       if(!p) p = registry_person_allocate(person_guid, when);
-
-                                       if(s[0] == 'A')
-                                               registry_request_access(p->guid, machine_guid, url, name, when);
-                                       else
-                                               registry_request_delete(p->guid, machine_guid, url, name, when);
-
-                                       break;
-
-                               default:
-                                       error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.log_filename, s);
-                                       break;
-                       }
-               }
-               
-               fclose(fp);
-       }
-
-       // open the log again
-       registry_log_open_nolock();
-
-       return line;
+    char *s, buf[4096 + 1];
+    size_t line = -1;
+
+    // closing the log is required here
+    // otherwise we will append to it the values we read
+    registry_log_close_nolock();
+
+    debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
+    FILE *fp = fopen(registry.log_filename, "r");
+    if(!fp)
+        error("Registry: cannot open registry file: %s", registry.log_filename);
+    else {
+        line = 0;
+        size_t len = 0;
+        while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
+            line++;
+
+            switch (s[0]) {
+                case 'A': // accesses
+                case 'D': // deletes
+
+                    // verify it is valid
+                    if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
+                        error("Registry: log line %zu is wrong (len = %zu).", line, len);
+                        continue;
+                    }
+                    s[1] = s[10] = s[47] = s[84] = '\0';
+
+                    // get the variables
+                    time_t when = strtoul(&s[2], NULL, 16);
+                    char *person_guid = &s[11];
+                    char *machine_guid = &s[48];
+                    char *name = &s[85];
+
+                    // skip the name to find the url
+                    char *url = name;
+                    while(*url && *url != '\t') url++;
+                    if(!*url) {
+                        error("Registry: log line %zu does not have a url.", line);
+                        continue;
+                    }
+                    *url++ = '\0';
+
+                    // make sure the person exists
+                    // without this, a new person guid will be created
+                    PERSON *p = registry_person_find(person_guid);
+                    if(!p) p = registry_person_allocate(person_guid, when);
+
+                    if(s[0] == 'A')
+                        registry_request_access(p->guid, machine_guid, url, name, when);
+                    else
+                        registry_request_delete(p->guid, machine_guid, url, name, when);
+
+                    break;
+
+                default:
+                    error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.log_filename, s);
+                    break;
+            }
+        }
+        
+        fclose(fp);
+    }
+
+    // open the log again
+    registry_log_open_nolock();
+
+    return line;
 }
 
 
@@ -804,176 +804,176 @@ int registry_log_load(void) {
 // REGISTRY REQUESTS
 
 PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
-       debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url);
+    debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url);
 
-       MACHINE *m = registry_machine_get(machine_guid, when);
-       if(!m) return NULL;
+    MACHINE *m = registry_machine_get(machine_guid, when);
+    if(!m) return NULL;
 
-       // make sure the name is valid
-       size_t namelen;
-       name = registry_fix_machine_name(name, &namelen);
+    // make sure the name is valid
+    size_t namelen;
+    name = registry_fix_machine_name(name, &namelen);
 
-       size_t urllen;
-       url = registry_fix_url(url, &urllen);
+    size_t urllen;
+    url = registry_fix_url(url, &urllen);
 
-       URL *u = registry_url_get(url, urllen);
-       PERSON *p = registry_person_get(person_guid, when);
+    URL *u = registry_url_get(url, urllen);
+    PERSON *p = registry_person_get(person_guid, when);
 
-       registry_person_link_to_url(p, m, u, name, namelen, when);
-       registry_machine_link_to_url(p, m, u, when);
+    registry_person_link_to_url(p, m, u, name, namelen, when);
+    registry_machine_link_to_url(p, m, u, when);
 
-       registry_log('A', p, m, u, name);
+    registry_log('A', p, m, u, name);
 
-       registry.usages_count++;
-       return p;
+    registry.usages_count++;
+    return p;
 }
 
 // verify the person, the machine and the URL exist in our DB
 PERSON_URL *registry_verify_request(char *person_guid, char *machine_guid, char *url, PERSON **pp, MACHINE **mm) {
-       char pbuf[36 + 1], mbuf[36 + 1];
-
-       if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) {
-               info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET");
-               return NULL;
-       }
-
-       // normalize the url
-       url = registry_fix_url(url, NULL);
-
-       // make sure the person GUID is valid
-       if(registry_regenerate_guid(person_guid, pbuf) == -1) {
-               info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
-               return NULL;
-       }
-       person_guid = pbuf;
-
-       // make sure the machine GUID is valid
-       if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
-               info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
-               return NULL;
-       }
-       machine_guid = mbuf;
-
-       // make sure the machine exists
-       MACHINE *m = registry_machine_find(machine_guid);
-       if(!m) {
-               info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
-               return NULL;
-       }
-       if(mm) *mm = m;
-
-       // make sure the person exist
-       PERSON *p = registry_person_find(person_guid);
-       if(!p) {
-               info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
-               return NULL;
-       }
-       if(pp) *pp = p;
-
-       PERSON_URL *pu = dictionary_get(p->urls, url);
-       if(!pu) {
-               info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
-               return NULL;
-       }
-       return pu;
+    char pbuf[36 + 1], mbuf[36 + 1];
+
+    if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) {
+        info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET");
+        return NULL;
+    }
+
+    // normalize the url
+    url = registry_fix_url(url, NULL);
+
+    // make sure the person GUID is valid
+    if(registry_regenerate_guid(person_guid, pbuf) == -1) {
+        info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
+        return NULL;
+    }
+    person_guid = pbuf;
+
+    // make sure the machine GUID is valid
+    if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
+        info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
+        return NULL;
+    }
+    machine_guid = mbuf;
+
+    // make sure the machine exists
+    MACHINE *m = registry_machine_find(machine_guid);
+    if(!m) {
+        info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
+        return NULL;
+    }
+    if(mm) *mm = m;
+
+    // make sure the person exist
+    PERSON *p = registry_person_find(person_guid);
+    if(!p) {
+        info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
+        return NULL;
+    }
+    if(pp) *pp = p;
+
+    PERSON_URL *pu = dictionary_get(p->urls, url);
+    if(!pu) {
+        info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
+        return NULL;
+    }
+    return pu;
 }
 
 PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
-       (void)when;
+    (void)when;
 
-       PERSON *p = NULL;
-       MACHINE *m = NULL;
-       PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
-       if(!pu || !p || !m) return NULL;
+    PERSON *p = NULL;
+    MACHINE *m = NULL;
+    PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
+    if(!pu || !p || !m) return NULL;
 
-       // normalize the url
-       delete_url = registry_fix_url(delete_url, NULL);
+    // normalize the url
+    delete_url = registry_fix_url(delete_url, NULL);
 
-       // make sure the user is not deleting the url it uses
-       if(!strcmp(delete_url, pu->url->url)) {
-               info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
-               return NULL;
-       }
+    // make sure the user is not deleting the url it uses
+    if(!strcmp(delete_url, pu->url->url)) {
+        info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
+        return NULL;
+    }
 
-       registry_person_urls_lock(p);
+    registry_person_urls_lock(p);
 
-       PERSON_URL *dpu = dictionary_get(p->urls, delete_url);
-       if(!dpu) {
-               info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
-               registry_person_urls_unlock(p);
-               return NULL;
-       }
+    PERSON_URL *dpu = dictionary_get(p->urls, delete_url);
+    if(!dpu) {
+        info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
+        registry_person_urls_unlock(p);
+        return NULL;
+    }
 
-       registry_log('D', p, m, pu->url, dpu->url->url);
+    registry_log('D', p, m, pu->url, dpu->url->url);
 
-       dictionary_del(p->urls, dpu->url->url);
-       registry_url_unlink_nolock(dpu->url);
-       freez(dpu);
+    dictionary_del(p->urls, dpu->url->url);
+    registry_url_unlink_nolock(dpu->url);
+    freez(dpu);
 
-       registry_person_urls_unlock(p);
-       return p;
+    registry_person_urls_unlock(p);
+    return p;
 }
 
 
 // a structure to pass to the dictionary_get_all() callback handler
 struct machine_request_callback_data {
-       MACHINE *find_this_machine;
-       PERSON_URL *result;
+    MACHINE *find_this_machine;
+    PERSON_URL *result;
 };
 
 // the callback function
 // this will be run for every PERSON_URL of this PERSON
 int machine_request_callback(void *entry, void *data) {
-       PERSON_URL *mypu = (PERSON_URL *)entry;
-       struct machine_request_callback_data *myrdata = (struct machine_request_callback_data *)data;
+    PERSON_URL *mypu = (PERSON_URL *)entry;
+    struct machine_request_callback_data *myrdata = (struct machine_request_callback_data *)data;
 
-       if(mypu->machine == myrdata->find_this_machine) {
-               myrdata->result = mypu;
-               return -1; // this will also stop the walk through
-       }
+    if(mypu->machine == myrdata->find_this_machine) {
+        myrdata->result = mypu;
+        return -1; // this will also stop the walk through
+    }
 
-       return 0; // continue
+    return 0; // continue
 }
 
 MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
-       (void)when;
+    (void)when;
 
-       char mbuf[36 + 1];
+    char mbuf[36 + 1];
 
-       PERSON *p = NULL;
-       MACHINE *m = NULL;
-       PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
-       if(!pu || !p || !m) return NULL;
+    PERSON *p = NULL;
+    MACHINE *m = NULL;
+    PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
+    if(!pu || !p || !m) return NULL;
 
-       // make sure the machine GUID is valid
-       if(registry_regenerate_guid(request_machine, mbuf) == -1) {
-               info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
-               return NULL;
-       }
-       request_machine = mbuf;
+    // make sure the machine GUID is valid
+    if(registry_regenerate_guid(request_machine, mbuf) == -1) {
+        info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
+        return NULL;
+    }
+    request_machine = mbuf;
 
-       // make sure the machine exists
-       m = registry_machine_find(request_machine);
-       if(!m) {
-               info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
-               return NULL;
-       }
+    // make sure the machine exists
+    m = registry_machine_find(request_machine);
+    if(!m) {
+        info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
+        return NULL;
+    }
 
-       // Verify the user has in the past accessed this machine
-       // We will walk through the PERSON_URLs to find the machine
-       // linking to our machine
+    // Verify the user has in the past accessed this machine
+    // We will walk through the PERSON_URLs to find the machine
+    // linking to our machine
 
-       // a structure to pass to the dictionary_get_all() callback handler
-       struct machine_request_callback_data rdata = { m, NULL };
+    // a structure to pass to the dictionary_get_all() callback handler
+    struct machine_request_callback_data rdata = { m, NULL };
 
-       // request a walk through on the dictionary
-       // no need for locking here, the underlying dictionary has its own
-       dictionary_get_all(p->urls, machine_request_callback, &rdata);
+    // request a walk through on the dictionary
+    // no need for locking here, the underlying dictionary has its own
+    dictionary_get_all(p->urls, machine_request_callback, &rdata);
 
-       if(rdata.result)
-               return m;
+    if(rdata.result)
+        return m;
 
-       return NULL;
+    return NULL;
 }
 
 
@@ -985,242 +985,242 @@ MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *u
 #define REGISTRY_STATUS_DISABLED "disabled"
 
 int registry_verify_cookies_redirects(void) {
-       return registry.verify_cookies_redirects;
+    return registry.verify_cookies_redirects;
 }
 
 const char *registry_to_announce(void) {
-       return registry.registry_to_announce;
+    return registry.registry_to_announce;
 }
 
 void registry_set_cookie(struct web_client *w, const char *guid) {
-       char edate[100];
-       time_t et = time(NULL) + registry.persons_expiration;
-       struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
-       strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
+    char edate[100];
+    time_t et = time(NULL) + registry.persons_expiration;
+    struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
+    strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
 
-       snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate);
+    snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate);
 
-       if(registry.registry_domain && registry.registry_domain[0])
-               snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate);
+    if(registry.registry_domain && registry.registry_domain[0])
+        snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate);
 }
 
 static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) {
-       registry_set_cookie(w, p->guid);
+    registry_set_cookie(w, p->guid);
 }
 
 static inline void registry_json_header(struct web_client *w, const char *action, const char *status) {
-       buffer_flush(w->response.data);
-       w->response.data->contenttype = CT_APPLICATION_JSON;
-       buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
-                                  action, status, registry.hostname, registry.machine_guid);
+    buffer_flush(w->response.data);
+    w->response.data->contenttype = CT_APPLICATION_JSON;
+    buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
+                   action, status, registry.hostname, registry.machine_guid);
 }
 
 static inline void registry_json_footer(struct web_client *w) {
-       buffer_strcat(w->response.data, "\n}\n");
+    buffer_strcat(w->response.data, "\n}\n");
 }
 
 int registry_request_hello_json(struct web_client *w) {
-       registry_json_header(w, "hello", REGISTRY_STATUS_OK);
+    registry_json_header(w, "hello", REGISTRY_STATUS_OK);
 
-       buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
-                                  registry.registry_to_announce);
+    buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
+                   registry.registry_to_announce);
 
-       registry_json_footer(w);
-       return 200;
+    registry_json_footer(w);
+    return 200;
 }
 
 static inline int registry_json_disabled(struct web_client *w, const char *action) {
-       registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
+    registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
 
-       buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
-                                  registry.registry_to_announce);
+    buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
+                   registry.registry_to_announce);
 
-       registry_json_footer(w);
-       return 200;
+    registry_json_footer(w);
+    return 200;
 }
 
 // structure used be the callbacks below
 struct registry_json_walk_person_urls_callback {
-       PERSON *p;
-       MACHINE *m;
-       struct web_client *w;
-       int count;
+    PERSON *p;
+    MACHINE *m;
+    struct web_client *w;
+    int count;
 };
 
 // callback for rendering PERSON_URLs
 static inline int registry_json_person_url_callback(void *entry, void *data) {
-       PERSON_URL *pu = (PERSON_URL *)entry;
-       struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
-       struct web_client *w = c->w;
+    PERSON_URL *pu = (PERSON_URL *)entry;
+    struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
+    struct web_client *w = c->w;
 
-       if(unlikely(c->count++))
-               buffer_strcat(w->response.data, ",");
+    if(unlikely(c->count++))
+        buffer_strcat(w->response.data, ",");
 
-       buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
-                                  pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->name);
+    buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
+                   pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->name);
 
-       return 1;
+    return 1;
 }
 
 // callback for rendering MACHINE_URLs
 static inline int registry_json_machine_url_callback(void *entry, void *data) {
-       MACHINE_URL *mu = (MACHINE_URL *)entry;
-       struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
-       struct web_client *w = c->w;
-       MACHINE *m = c->m;
+    MACHINE_URL *mu = (MACHINE_URL *)entry;
+    struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
+    struct web_client *w = c->w;
+    MACHINE *m = c->m;
 
-       if(unlikely(c->count++))
-               buffer_strcat(w->response.data, ",");
+    if(unlikely(c->count++))
+        buffer_strcat(w->response.data, ",");
 
-       buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u ]",
-                                  m->guid, mu->url->url, mu->last_t, mu->usages);
+    buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u ]",
+                   m->guid, mu->url->url, mu->last_t, mu->usages);
 
-       return 1;
+    return 1;
 }
 
 
 // the main method for registering an access
 int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
-       if(!registry.enabled)
-               return registry_json_disabled(w, "access");
+    if(!registry.enabled)
+        return registry_json_disabled(w, "access");
 
-       PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
-       if(!p) {
-               registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 412;
-       }
+    PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
+    if(!p) {
+        registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 412;
+    }
 
-       // set the cookie
-       registry_set_person_cookie(w, p);
+    // set the cookie
+    registry_set_person_cookie(w, p);
 
-       // generate the response
-       registry_json_header(w, "access", REGISTRY_STATUS_OK);
+    // generate the response
+    registry_json_header(w, "access", REGISTRY_STATUS_OK);
 
-       buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
-       struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
-       dictionary_get_all(p->urls, registry_json_person_url_callback, &c);
-       buffer_strcat(w->response.data, "\n\t]\n");
+    buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
+    struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
+    dictionary_get_all(p->urls, registry_json_person_url_callback, &c);
+    buffer_strcat(w->response.data, "\n\t]\n");
 
-       registry_json_footer(w);
-       return 200;
+    registry_json_footer(w);
+    return 200;
 }
 
 // the main method for deleting a URL from a person
 int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
-       if(!registry.enabled)
-               return registry_json_disabled(w, "delete");
+    if(!registry.enabled)
+        return registry_json_disabled(w, "delete");
 
-       PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
-       if(!p) {
-               registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 412;
-       }
+    PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
+    if(!p) {
+        registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 412;
+    }
 
-       // generate the response
-       registry_json_header(w, "delete", REGISTRY_STATUS_OK);
-       registry_json_footer(w);
-       return 200;
+    // generate the response
+    registry_json_header(w, "delete", REGISTRY_STATUS_OK);
+    registry_json_footer(w);
+    return 200;
 }
 
 // the main method for searching the URLs of a netdata
 int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
-       if(!registry.enabled)
-               return registry_json_disabled(w, "search");
+    if(!registry.enabled)
+        return registry_json_disabled(w, "search");
 
-       MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
-       if(!m) {
-               registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 404;
-       }
+    MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
+    if(!m) {
+        registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 404;
+    }
 
-       registry_json_header(w, "search", REGISTRY_STATUS_OK);
+    registry_json_header(w, "search", REGISTRY_STATUS_OK);
 
-       buffer_strcat(w->response.data, ",\n\t\"urls\": [");
-       struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
-       dictionary_get_all(m->urls, registry_json_machine_url_callback, &c);
-       buffer_strcat(w->response.data, "\n\t]\n");
+    buffer_strcat(w->response.data, ",\n\t\"urls\": [");
+    struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
+    dictionary_get_all(m->urls, registry_json_machine_url_callback, &c);
+    buffer_strcat(w->response.data, "\n\t]\n");
 
-       registry_json_footer(w);
-       return 200;
+    registry_json_footer(w);
+    return 200;
 }
 
 // structure used be the callbacks below
 struct registry_person_url_callback_verify_machine_exists_data {
-       MACHINE *m;
-       int count;
+    MACHINE *m;
+    int count;
 };
 
 int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
-       struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
-       PERSON_URL *pu = (PERSON_URL *)entry;
-       MACHINE *m = d->m;
+    struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
+    PERSON_URL *pu = (PERSON_URL *)entry;
+    MACHINE *m = d->m;
 
-       if(pu->machine == m)
-               d->count++;
+    if(pu->machine == m)
+        d->count++;
 
-       return 0;
+    return 0;
 }
 
 // the main method for switching user identity
 int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
-       (void)url;
-       (void)when;
-
-       if(!registry.enabled)
-               return registry_json_disabled(w, "switch");
-
-       PERSON *op = registry_person_find(person_guid);
-       if(!op) {
-               registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 430;
-       }
-
-       PERSON *np = registry_person_find(new_person_guid);
-       if(!np) {
-               registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 431;
-       }
-
-       MACHINE *m = registry_machine_find(machine_guid);
-       if(!m) {
-               registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 432;
-       }
-
-       struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
-
-       // verify the old person has access to this machine
-       dictionary_get_all(op->urls, registry_person_url_callback_verify_machine_exists, &data);
-       if(!data.count) {
-               registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 433;
-       }
-
-       // verify the new person has access to this machine
-       data.count = 0;
-       dictionary_get_all(np->urls, registry_person_url_callback_verify_machine_exists, &data);
-       if(!data.count) {
-               registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
-               registry_json_footer(w);
-               return 434;
-       }
-
-       // set the cookie of the new person
-       // the user just switched identity
-       registry_set_person_cookie(w, np);
-
-       // generate the response
-       registry_json_header(w, "switch", REGISTRY_STATUS_OK);
-       buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
-       registry_json_footer(w);
-       return 200;
+    (void)url;
+    (void)when;
+
+    if(!registry.enabled)
+        return registry_json_disabled(w, "switch");
+
+    PERSON *op = registry_person_find(person_guid);
+    if(!op) {
+        registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 430;
+    }
+
+    PERSON *np = registry_person_find(new_person_guid);
+    if(!np) {
+        registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 431;
+    }
+
+    MACHINE *m = registry_machine_find(machine_guid);
+    if(!m) {
+        registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 432;
+    }
+
+    struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
+
+    // verify the old person has access to this machine
+    dictionary_get_all(op->urls, registry_person_url_callback_verify_machine_exists, &data);
+    if(!data.count) {
+        registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 433;
+    }
+
+    // verify the new person has access to this machine
+    data.count = 0;
+    dictionary_get_all(np->urls, registry_person_url_callback_verify_machine_exists, &data);
+    if(!data.count) {
+        registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
+        registry_json_footer(w);
+        return 434;
+    }
+
+    // set the cookie of the new person
+    // the user just switched identity
+    registry_set_person_cookie(w, np);
+
+    // generate the response
+    registry_json_header(w, "switch", REGISTRY_STATUS_OK);
+    buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
+    registry_json_footer(w);
+    return 200;
 }
 
 
@@ -1228,47 +1228,47 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
 // REGISTRY THIS MACHINE UNIQUE ID
 
 char *registry_get_this_machine_guid(void) {
-       if(likely(registry.machine_guid[0]))
-               return registry.machine_guid;
+    if(likely(registry.machine_guid[0]))
+        return registry.machine_guid;
 
-       // read it from disk
-       int fd = open(registry.machine_guid_filename, O_RDONLY);
-       if(fd != -1) {
-               char buf[36 + 1];
-               if(read(fd, buf, 36) != 36)
-                       error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
-               else {
-                       buf[36] = '\0';
-                       if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
-                               error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
-                                         buf, registry.machine_guid_filename);
+    // read it from disk
+    int fd = open(registry.machine_guid_filename, O_RDONLY);
+    if(fd != -1) {
+        char buf[36 + 1];
+        if(read(fd, buf, 36) != 36)
+            error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
+        else {
+            buf[36] = '\0';
+            if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
+                error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
+                      buf, registry.machine_guid_filename);
 
-                               registry.machine_guid[0] = '\0';
-                       }
-               }
-               close(fd);
-       }
+                registry.machine_guid[0] = '\0';
+            }
+        }
+        close(fd);
+    }
 
-       // generate a new one?
-       if(!registry.machine_guid[0]) {
-               uuid_t uuid;
+    // generate a new one?
+    if(!registry.machine_guid[0]) {
+        uuid_t uuid;
 
-               uuid_generate_time(uuid);
-               uuid_unparse_lower(uuid, registry.machine_guid);
-               registry.machine_guid[36] = '\0';
+        uuid_generate_time(uuid);
+        uuid_unparse_lower(uuid, registry.machine_guid);
+        registry.machine_guid[36] = '\0';
 
-               // save it
-               fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
-               if(fd == -1)
-                       fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
+        // save it
+        fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
+        if(fd == -1)
+            fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
 
-               if(write(fd, registry.machine_guid, 36) != 36)
-                       fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
+        if(write(fd, registry.machine_guid, 36) != 36)
+            fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
 
-               close(fd);
-       }
+        close(fd);
+    }
 
-       return registry.machine_guid;
+    return registry.machine_guid;
 }
 
 
@@ -1276,560 +1276,560 @@ char *registry_get_this_machine_guid(void) {
 // REGISTRY LOAD/SAVE
 
 int registry_machine_save_url(void *entry, void *file) {
-       MACHINE_URL *mu = entry;
-       FILE *fp = file;
+    MACHINE_URL *mu = entry;
+    FILE *fp = file;
 
-       debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url);
+    debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url);
 
-       int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n",
-                       mu->first_t,
-                       mu->last_t,
-                       mu->usages,
-                       mu->flags,
-                       mu->url->url
-       );
+    int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n",
+            mu->first_t,
+            mu->last_t,
+            mu->usages,
+            mu->flags,
+            mu->url->url
+    );
 
-       // error handling is done at registry_save()
+    // error handling is done at registry_save()
 
-       return ret;
+    return ret;
 }
 
 int registry_machine_save(void *entry, void *file) {
-       MACHINE *m = entry;
-       FILE *fp = file;
+    MACHINE *m = entry;
+    FILE *fp = file;
 
-       debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid);
+    debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid);
 
-       int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n",
-                       m->first_t,
-                       m->last_t,
-                       m->usages,
-                       m->guid
-       );
+    int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n",
+            m->first_t,
+            m->last_t,
+            m->usages,
+            m->guid
+    );
 
-       if(ret >= 0) {
-               int ret2 = dictionary_get_all(m->urls, registry_machine_save_url, fp);
-               if(ret2 < 0) return ret2;
-               ret += ret2;
-       }
+    if(ret >= 0) {
+        int ret2 = dictionary_get_all(m->urls, registry_machine_save_url, fp);
+        if(ret2 < 0) return ret2;
+        ret += ret2;
+    }
 
-       // error handling is done at registry_save()
+    // error handling is done at registry_save()
 
-       return ret;
+    return ret;
 }
 
 static inline int registry_person_save_url(void *entry, void *file) {
-       PERSON_URL *pu = entry;
-       FILE *fp = file;
+    PERSON_URL *pu = entry;
+    FILE *fp = file;
 
-       debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url);
+    debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url);
 
-       int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n",
-                       pu->first_t,
-                       pu->last_t,
-                       pu->usages,
-                       pu->flags,
-                       pu->machine->guid,
-                       pu->name,
-                       pu->url->url
-       );
+    int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n",
+            pu->first_t,
+            pu->last_t,
+            pu->usages,
+            pu->flags,
+            pu->machine->guid,
+            pu->name,
+            pu->url->url
+    );
 
-       // error handling is done at registry_save()
+    // error handling is done at registry_save()
 
-       return ret;
+    return ret;
 }
 
 static inline int registry_person_save(void *entry, void *file) {
-       PERSON *p = entry;
-       FILE *fp = file;
+    PERSON *p = entry;
+    FILE *fp = file;
 
-       debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid);
+    debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid);
 
-       int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n",
-                       p->first_t,
-                       p->last_t,
-                       p->usages,
-                       p->guid
-       );
+    int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n",
+            p->first_t,
+            p->last_t,
+            p->usages,
+            p->guid
+    );
 
-       if(ret >= 0) {
-               int ret2 = dictionary_get_all(p->urls, registry_person_save_url, fp);
-               if (ret2 < 0) return ret2;
-               ret += ret2;
-       }
+    if(ret >= 0) {
+        int ret2 = dictionary_get_all(p->urls, registry_person_save_url, fp);
+        if (ret2 < 0) return ret2;
+        ret += ret2;
+    }
 
-       // error handling is done at registry_save()
+    // error handling is done at registry_save()
 
-       return ret;
+    return ret;
 }
 
 int registry_save(void) {
-       if(!registry.enabled) return -1;
-
-       // make sure the log is not updated
-       registry_log_lock();
-
-       if(unlikely(!registry_should_save_db())) {
-               registry_log_unlock();
-               return -2;
-       }
-
-       char tmp_filename[FILENAME_MAX + 1];
-       char old_filename[FILENAME_MAX + 1];
-
-       snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename);
-       snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename);
-
-       debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename);
-       FILE *fp = fopen(tmp_filename, "w");
-       if(!fp) {
-               error("Registry: Cannot create file: %s", tmp_filename);
-               registry_log_unlock();
-               return -1;
-       }
-
-       // dictionary_get_all() has its own locking, so this is safe to do
-
-       debug(D_REGISTRY, "Saving all machines");
-       int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp);
-       if(bytes1 < 0) {
-               error("Registry: Cannot save registry machines - return value %d", bytes1);
-               fclose(fp);
-               registry_log_unlock();
-               return bytes1;
-       }
-       debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1);
-
-       debug(D_REGISTRY, "Saving all persons");
-       int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp);
-       if(bytes2 < 0) {
-               error("Registry: Cannot save registry persons - return value %d", bytes2);
-               fclose(fp);
-               registry_log_unlock();
-               return bytes2;
-       }
-       debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2);
-
-       // save the totals
-       fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n",
-                       registry.persons_count,
-                       registry.machines_count,
-                       registry.usages_count + 1, // this is required - it is lost on db rotation
-                       registry.urls_count,
-                       registry.persons_urls_count,
-                       registry.machines_urls_count
-       );
-
-       fclose(fp);
-
-       errno = 0;
-
-       // remove the .old db
-       debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename);
-       if(unlink(old_filename) == -1 && errno != ENOENT)
-               error("Registry: cannot remove old registry file '%s'", old_filename);
-
-       // rename the db to .old
-       debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
-       if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT)
-               error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, registry.db_filename);
-
-       else {
-               // remove the database (it is saved in .old)
-               debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename);
-               if (unlink(registry.db_filename) == -1 && errno != ENOENT)
-                       error("Registry: cannot remove old registry file '%s'", registry.db_filename);
-
-               // move the .tmp to make it active
-               debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
-               if (link(tmp_filename, registry.db_filename) == -1) {
-                       error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
-                                 registry.db_filename);
-
-                       // move the .old back
-                       debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
-                       if(link(old_filename, registry.db_filename) == -1)
-                               error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
-               }
-               else {
-                       debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename);
-                       if(unlink(tmp_filename) == -1)
-                               error("Registry: cannot remove tmp registry file '%s'", tmp_filename);
-
-                       // it has been moved successfully
-                       // discard the current registry log
-                       registry_log_recreate_nolock();
-
-                       registry.log_count = 0;
-               }
-       }
-
-       // continue operations
-       registry_log_unlock();
-
-       return -1;
+    if(!registry.enabled) return -1;
+
+    // make sure the log is not updated
+    registry_log_lock();
+
+    if(unlikely(!registry_should_save_db())) {
+        registry_log_unlock();
+        return -2;
+    }
+
+    char tmp_filename[FILENAME_MAX + 1];
+    char old_filename[FILENAME_MAX + 1];
+
+    snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename);
+    snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename);
+
+    debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename);
+    FILE *fp = fopen(tmp_filename, "w");
+    if(!fp) {
+        error("Registry: Cannot create file: %s", tmp_filename);
+        registry_log_unlock();
+        return -1;
+    }
+
+    // dictionary_get_all() has its own locking, so this is safe to do
+
+    debug(D_REGISTRY, "Saving all machines");
+    int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp);
+    if(bytes1 < 0) {
+        error("Registry: Cannot save registry machines - return value %d", bytes1);
+        fclose(fp);
+        registry_log_unlock();
+        return bytes1;
+    }
+    debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1);
+
+    debug(D_REGISTRY, "Saving all persons");
+    int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp);
+    if(bytes2 < 0) {
+        error("Registry: Cannot save registry persons - return value %d", bytes2);
+        fclose(fp);
+        registry_log_unlock();
+        return bytes2;
+    }
+    debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2);
+
+    // save the totals
+    fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n",
+            registry.persons_count,
+            registry.machines_count,
+            registry.usages_count + 1, // this is required - it is lost on db rotation
+            registry.urls_count,
+            registry.persons_urls_count,
+            registry.machines_urls_count
+    );
+
+    fclose(fp);
+
+    errno = 0;
+
+    // remove the .old db
+    debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename);
+    if(unlink(old_filename) == -1 && errno != ENOENT)
+        error("Registry: cannot remove old registry file '%s'", old_filename);
+
+    // rename the db to .old
+    debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
+    if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT)
+        error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, registry.db_filename);
+
+    else {
+        // remove the database (it is saved in .old)
+        debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename);
+        if (unlink(registry.db_filename) == -1 && errno != ENOENT)
+            error("Registry: cannot remove old registry file '%s'", registry.db_filename);
+
+        // move the .tmp to make it active
+        debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
+        if (link(tmp_filename, registry.db_filename) == -1) {
+            error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
+                  registry.db_filename);
+
+            // move the .old back
+            debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
+            if(link(old_filename, registry.db_filename) == -1)
+                error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
+        }
+        else {
+            debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename);
+            if(unlink(tmp_filename) == -1)
+                error("Registry: cannot remove tmp registry file '%s'", tmp_filename);
+
+            // it has been moved successfully
+            // discard the current registry log
+            registry_log_recreate_nolock();
+
+            registry.log_count = 0;
+        }
+    }
+
+    // continue operations
+    registry_log_unlock();
+
+    return -1;
 }
 
 static inline size_t registry_load(void) {
-       char *s, buf[4096 + 1];
-       PERSON *p = NULL;
-       MACHINE *m = NULL;
-       URL *u = NULL;
-       size_t line = 0;
-
-       debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename);
-       FILE *fp = fopen(registry.db_filename, "r");
-       if(!fp) {
-               error("Registry: cannot open registry file: '%s'", registry.db_filename);
-               return 0;
-       }
-
-       size_t len = 0;
-       buf[4096] = '\0';
-       while((s = fgets_trim_len(buf, 4096, fp, &len))) {
-               line++;
-
-               debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s);
-               switch(*s) {
-                       case 'T': // totals
-                               if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
-                                       error("Registry totals line %zu is wrong (len = %zu).", line, len);
-                                       continue;
-                               }
-                               registry.persons_count = strtoull(&s[2], NULL, 16);
-                               registry.machines_count = strtoull(&s[19], NULL, 16);
-                               registry.usages_count = strtoull(&s[36], NULL, 16);
-                               registry.urls_count = strtoull(&s[53], NULL, 16);
-                               registry.persons_urls_count = strtoull(&s[70], NULL, 16);
-                               registry.machines_urls_count = strtoull(&s[87], NULL, 16);
-                               break;
-
-                       case 'P': // person
-                               m = NULL;
-                               // verify it is valid
-                               if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
-                                       error("Registry person line %zu is wrong (len = %zu).", line, len);
-                                       continue;
-                               }
-
-                               s[1] = s[10] = s[19] = s[28] = '\0';
-                               p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16));
-                               p->last_t = strtoul(&s[11], NULL, 16);
-                               p->usages = strtoul(&s[20], NULL, 16);
-                               debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
-                               break;
-
-                       case 'M': // machine
-                               p = NULL;
-                               // verify it is valid
-                               if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
-                                       error("Registry person line %zu is wrong (len = %zu).", line, len);
-                                       continue;
-                               }
-
-                               s[1] = s[10] = s[19] = s[28] = '\0';
-                               m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16));
-                               m->last_t = strtoul(&s[11], NULL, 16);
-                               m->usages = strtoul(&s[20], NULL, 16);
-                               debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
-                               break;
-
-                       case 'U': // person URL
-                               if(unlikely(!p)) {
-                                       error("Registry: ignoring line %zu, no person loaded: %s", line, s);
-                                       continue;
-                               }
-
-                               // verify it is valid
-                               if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') {
-                                       error("Registry person URL line %zu is wrong (len = %zu).", line, len);
-                                       continue;
-                               }
-
-                               s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0';
-
-                               // skip the name to find the url
-                               char *url = &s[69];
-                               while(*url && *url != '\t') url++;
-                               if(!*url) {
-                                       error("Registry person URL line %zu does not have a url.", line);
-                                       continue;
-                               }
-                               *url++ = '\0';
-
-                               u = registry_url_allocate_nolock(url, strlen(url));
-
-                               time_t first_t = strtoul(&s[2], NULL, 16);
-
-                               m = registry_machine_find(&s[32]);
-                               if(!m) m = registry_machine_allocate(&s[32], first_t);
-
-                               PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
-                               pu->last_t = strtoul(&s[11], NULL, 16);
-                               pu->usages = strtoul(&s[20], NULL, 16);
-                               pu->flags = strtoul(&s[29], NULL, 16);
-                               debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
-                               break;
-
-                       case 'V': // machine URL
-                               if(unlikely(!m)) {
-                                       error("Registry: ignoring line %zu, no machine loaded: %s", line, s);
-                                       continue;
-                               }
-
-                               // verify it is valid
-                               if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') {
-                                       error("Registry person URL line %zu is wrong (len = %zu).", line, len);
-                                       continue;
-                               }
-
-                               s[1] = s[10] = s[19] = s[28] = s[31] = '\0';
-                               u = registry_url_allocate_nolock(&s[32], strlen(&s[32]));
-
-                               MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16));
-                               mu->last_t = strtoul(&s[11], NULL, 16);
-                               mu->usages = strtoul(&s[20], NULL, 16);
-                               mu->flags = strtoul(&s[29], NULL, 16);
-                               debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
-                               break;
-
-                       default:
-                               error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
-                               break;
-               }
-       }
-       fclose(fp);
-
-       return line;
+    char *s, buf[4096 + 1];
+    PERSON *p = NULL;
+    MACHINE *m = NULL;
+    URL *u = NULL;
+    size_t line = 0;
+
+    debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename);
+    FILE *fp = fopen(registry.db_filename, "r");
+    if(!fp) {
+        error("Registry: cannot open registry file: '%s'", registry.db_filename);
+        return 0;
+    }
+
+    size_t len = 0;
+    buf[4096] = '\0';
+    while((s = fgets_trim_len(buf, 4096, fp, &len))) {
+        line++;
+
+        debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s);
+        switch(*s) {
+            case 'T': // totals
+                if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
+                    error("Registry totals line %zu is wrong (len = %zu).", line, len);
+                    continue;
+                }
+                registry.persons_count = strtoull(&s[2], NULL, 16);
+                registry.machines_count = strtoull(&s[19], NULL, 16);
+                registry.usages_count = strtoull(&s[36], NULL, 16);
+                registry.urls_count = strtoull(&s[53], NULL, 16);
+                registry.persons_urls_count = strtoull(&s[70], NULL, 16);
+                registry.machines_urls_count = strtoull(&s[87], NULL, 16);
+                break;
+
+            case 'P': // person
+                m = NULL;
+                // verify it is valid
+                if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
+                    error("Registry person line %zu is wrong (len = %zu).", line, len);
+                    continue;
+                }
+
+                s[1] = s[10] = s[19] = s[28] = '\0';
+                p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16));
+                p->last_t = strtoul(&s[11], NULL, 16);
+                p->usages = strtoul(&s[20], NULL, 16);
+                debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
+                break;
+
+            case 'M': // machine
+                p = NULL;
+                // verify it is valid
+                if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
+                    error("Registry person line %zu is wrong (len = %zu).", line, len);
+                    continue;
+                }
+
+                s[1] = s[10] = s[19] = s[28] = '\0';
+                m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16));
+                m->last_t = strtoul(&s[11], NULL, 16);
+                m->usages = strtoul(&s[20], NULL, 16);
+                debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
+                break;
+
+            case 'U': // person URL
+                if(unlikely(!p)) {
+                    error("Registry: ignoring line %zu, no person loaded: %s", line, s);
+                    continue;
+                }
+
+                // verify it is valid
+                if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') {
+                    error("Registry person URL line %zu is wrong (len = %zu).", line, len);
+                    continue;
+                }
+
+                s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0';
+
+                // skip the name to find the url
+                char *url = &s[69];
+                while(*url && *url != '\t') url++;
+                if(!*url) {
+                    error("Registry person URL line %zu does not have a url.", line);
+                    continue;
+                }
+                *url++ = '\0';
+
+                u = registry_url_allocate_nolock(url, strlen(url));
+
+                time_t first_t = strtoul(&s[2], NULL, 16);
+
+                m = registry_machine_find(&s[32]);
+                if(!m) m = registry_machine_allocate(&s[32], first_t);
+
+                PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
+                pu->last_t = strtoul(&s[11], NULL, 16);
+                pu->usages = strtoul(&s[20], NULL, 16);
+                pu->flags = strtoul(&s[29], NULL, 16);
+                debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
+                break;
+
+            case 'V': // machine URL
+                if(unlikely(!m)) {
+                    error("Registry: ignoring line %zu, no machine loaded: %s", line, s);
+                    continue;
+                }
+
+                // verify it is valid
+                if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') {
+                    error("Registry person URL line %zu is wrong (len = %zu).", line, len);
+                    continue;
+                }
+
+                s[1] = s[10] = s[19] = s[28] = s[31] = '\0';
+                u = registry_url_allocate_nolock(&s[32], strlen(&s[32]));
+
+                MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16));
+                mu->last_t = strtoul(&s[11], NULL, 16);
+                mu->usages = strtoul(&s[20], NULL, 16);
+                mu->flags = strtoul(&s[29], NULL, 16);
+                debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
+                break;
+
+            default:
+                error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
+                break;
+        }
+    }
+    fclose(fp);
+
+    return line;
 }
 
 // ----------------------------------------------------------------------------
 // REGISTRY
 
 int registry_init(void) {
-       char filename[FILENAME_MAX + 1];
-
-       // registry enabled?
-       registry.enabled = config_get_boolean("registry", "enabled", 0);
-
-       if(mkdir(VARLIB_DIR, 0755) == -1 && errno != EEXIST)
-               error("Cannot create directory '" VARLIB_DIR "'");
-
-       // pathnames
-       registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
-       if(mkdir(registry.pathname, 0755) == -1 && errno != EEXIST) {
-               error("Cannot create directory '%s'. Registry disabled.", registry.pathname);
-               registry.enabled = 0;
-               return -1;
-       }
-
-       // filenames
-       snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
-       registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
-       registry_get_this_machine_guid();
-
-       snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
-       registry.db_filename = config_get("registry", "registry db file", filename);
-
-       snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
-       registry.log_filename = config_get("registry", "registry log file", filename);
-
-       // configuration options
-       registry.save_registry_every_entries = config_get_number("registry", "registry save db every new entries", 1000000);
-       registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
-       registry.registry_domain = config_get("registry", "registry domain", "");
-       registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
-       registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", hostname));
-       registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
-
-       registry.max_url_length = config_get_number("registry", "max URL length", 1024);
-       if(registry.max_url_length < 10) {
-               registry.max_url_length = 10;
-               config_set_number("registry", "max URL length", registry.max_url_length);
-       }
-
-       registry.max_name_length = config_get_number("registry", "max URL name length", 50);
-       if(registry.max_name_length < 10) {
-               registry.max_name_length = 10;
-               config_set_number("registry", "max URL name length", registry.max_name_length);
-       }
-
-       // initialize entries counters
-       registry.persons_count = 0;
-       registry.machines_count = 0;
-       registry.usages_count = 0;
-       registry.urls_count = 0;
-       registry.persons_urls_count = 0;
-       registry.machines_urls_count = 0;
-
-       // initialize memory counters
-       registry.persons_memory = 0;
-       registry.machines_memory = 0;
-       registry.urls_memory = 0;
-       registry.persons_urls_memory = 0;
-       registry.machines_urls_memory = 0;
-
-       // initialize locks
-       pthread_mutex_init(&registry.persons_lock, NULL);
-       pthread_mutex_init(&registry.machines_lock, NULL);
-       pthread_mutex_init(&registry.urls_lock, NULL);
-       pthread_mutex_init(&registry.person_urls_lock, NULL);
-       pthread_mutex_init(&registry.machine_urls_lock, NULL);
-
-       // create dictionaries
-       registry.persons = dictionary_create(DICTIONARY_FLAGS);
-       registry.machines = dictionary_create(DICTIONARY_FLAGS);
-       registry.urls = dictionary_create(DICTIONARY_FLAGS);
-
-       // load the registry database
-       if(registry.enabled) {
-               registry_log_open_nolock();
-               registry_load();
-               registry_log_load();
-       }
-
-       return 0;
+    char filename[FILENAME_MAX + 1];
+
+    // registry enabled?
+    registry.enabled = config_get_boolean("registry", "enabled", 0);
+
+    if(mkdir(VARLIB_DIR, 0755) == -1 && errno != EEXIST)
+        error("Cannot create directory '" VARLIB_DIR "'");
+
+    // pathnames
+    registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
+    if(mkdir(registry.pathname, 0755) == -1 && errno != EEXIST) {
+        error("Cannot create directory '%s'. Registry disabled.", registry.pathname);
+        registry.enabled = 0;
+        return -1;
+    }
+
+    // filenames
+    snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
+    registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
+    registry_get_this_machine_guid();
+
+    snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
+    registry.db_filename = config_get("registry", "registry db file", filename);
+
+    snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
+    registry.log_filename = config_get("registry", "registry log file", filename);
+
+    // configuration options
+    registry.save_registry_every_entries = config_get_number("registry", "registry save db every new entries", 1000000);
+    registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
+    registry.registry_domain = config_get("registry", "registry domain", "");
+    registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
+    registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", hostname));
+    registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
+
+    registry.max_url_length = config_get_number("registry", "max URL length", 1024);
+    if(registry.max_url_length < 10) {
+        registry.max_url_length = 10;
+        config_set_number("registry", "max URL length", registry.max_url_length);
+    }
+
+    registry.max_name_length = config_get_number("registry", "max URL name length", 50);
+    if(registry.max_name_length < 10) {
+        registry.max_name_length = 10;
+        config_set_number("registry", "max URL name length", registry.max_name_length);
+    }
+
+    // initialize entries counters
+    registry.persons_count = 0;
+    registry.machines_count = 0;
+    registry.usages_count = 0;
+    registry.urls_count = 0;
+    registry.persons_urls_count = 0;
+    registry.machines_urls_count = 0;
+
+    // initialize memory counters
+    registry.persons_memory = 0;
+    registry.machines_memory = 0;
+    registry.urls_memory = 0;
+    registry.persons_urls_memory = 0;
+    registry.machines_urls_memory = 0;
+
+    // initialize locks
+    pthread_mutex_init(&registry.persons_lock, NULL);
+    pthread_mutex_init(&registry.machines_lock, NULL);
+    pthread_mutex_init(&registry.urls_lock, NULL);
+    pthread_mutex_init(&registry.person_urls_lock, NULL);
+    pthread_mutex_init(&registry.machine_urls_lock, NULL);
+
+    // create dictionaries
+    registry.persons = dictionary_create(DICTIONARY_FLAGS);
+    registry.machines = dictionary_create(DICTIONARY_FLAGS);
+    registry.urls = dictionary_create(DICTIONARY_FLAGS);
+
+    // load the registry database
+    if(registry.enabled) {
+        registry_log_open_nolock();
+        registry_load();
+        registry_log_load();
+    }
+
+    return 0;
 }
 
 void registry_free(void) {
-       if(!registry.enabled) return;
+    if(!registry.enabled) return;
 
-       // we need to destroy the dictionaries ourselves
-       // since the dictionaries use memory we allocated
+    // we need to destroy the dictionaries ourselves
+    // since the dictionaries use memory we allocated
 
-       while(registry.persons->values_index.root) {
-               PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value;
+    while(registry.persons->values_index.root) {
+        PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value;
 
-               // fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages);
+        // fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages);
 
-               while(p->urls->values_index.root) {
-                       PERSON_URL *pu = ((NAME_VALUE *)p->urls->values_index.root)->value;
+        while(p->urls->values_index.root) {
+            PERSON_URL *pu = ((NAME_VALUE *)p->urls->values_index.root)->value;
 
-                       // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags);
+            // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags);
 
-                       debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", pu->url->url, p->guid);
-                       dictionary_del(p->urls, pu->url->url);
+            debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", pu->url->url, p->guid);
+            dictionary_del(p->urls, pu->url->url);
 
-                       debug(D_REGISTRY, "Registry: unlinking url '%s' from person", pu->url->url);
-                       registry_url_unlink_nolock(pu->url);
+            debug(D_REGISTRY, "Registry: unlinking url '%s' from person", pu->url->url);
+            registry_url_unlink_nolock(pu->url);
 
-                       debug(D_REGISTRY, "Registry: freeing person url");
-                       freez(pu);
-               }
+            debug(D_REGISTRY, "Registry: freeing person url");
+            freez(pu);
+        }
 
-               debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
-               dictionary_del(registry.persons, p->guid);
+        debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
+        dictionary_del(registry.persons, p->guid);
 
-               debug(D_REGISTRY, "Registry: destroying URL dictionary of person '%s'", p->guid);
-               dictionary_destroy(p->urls);
+        debug(D_REGISTRY, "Registry: destroying URL dictionary of person '%s'", p->guid);
+        dictionary_destroy(p->urls);
 
-               debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
-               freez(p);
-       }
+        debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
+        freez(p);
+    }
 
-       while(registry.machines->values_index.root) {
-               MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value;
+    while(registry.machines->values_index.root) {
+        MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value;
 
-               // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages);
+        // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages);
 
-               while(m->urls->values_index.root) {
-                       MACHINE_URL *mu = ((NAME_VALUE *)m->urls->values_index.root)->value;
+        while(m->urls->values_index.root) {
+            MACHINE_URL *mu = ((NAME_VALUE *)m->urls->values_index.root)->value;
 
-                       // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags);
+            // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags);
 
-                       //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url);
-                       //dictionary_destroy(mu->persons);
+            //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url);
+            //dictionary_destroy(mu->persons);
 
-                       debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid);
-                       dictionary_del(m->urls, mu->url->url);
+            debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid);
+            dictionary_del(m->urls, mu->url->url);
 
-                       debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url);
-                       registry_url_unlink_nolock(mu->url);
+            debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url);
+            registry_url_unlink_nolock(mu->url);
 
-                       debug(D_REGISTRY, "Registry: freeing machine url");
-                       freez(mu);
-               }
+            debug(D_REGISTRY, "Registry: freeing machine url");
+            freez(mu);
+        }
 
-               debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid);
-               dictionary_del(registry.machines, m->guid);
+        debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid);
+        dictionary_del(registry.machines, m->guid);
 
-               debug(D_REGISTRY, "Registry: destroying URL dictionary of machine '%s'", m->guid);
-               dictionary_destroy(m->urls);
+        debug(D_REGISTRY, "Registry: destroying URL dictionary of machine '%s'", m->guid);
+        dictionary_destroy(m->urls);
 
-               debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid);
-               freez(m);
-       }
+        debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid);
+        freez(m);
+    }
 
-       // and free the memory of remaining dictionary structures
+    // and free the memory of remaining dictionary structures
 
-       debug(D_REGISTRY, "Registry: destroying persons dictionary");
-       dictionary_destroy(registry.persons);
+    debug(D_REGISTRY, "Registry: destroying persons dictionary");
+    dictionary_destroy(registry.persons);
 
-       debug(D_REGISTRY, "Registry: destroying machines dictionary");
-       dictionary_destroy(registry.machines);
+    debug(D_REGISTRY, "Registry: destroying machines dictionary");
+    dictionary_destroy(registry.machines);
 
-       debug(D_REGISTRY, "Registry: destroying urls dictionary");
-       dictionary_destroy(registry.urls);
+    debug(D_REGISTRY, "Registry: destroying urls dictionary");
+    dictionary_destroy(registry.urls);
 }
 
 // ----------------------------------------------------------------------------
 // STATISTICS
 
 void registry_statistics(void) {
-       if(!registry.enabled) return;
-
-       static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
-
-       if(!sts) sts = rrdset_find("netdata.registry_sessions");
-       if(!sts) {
-               sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
-
-               rrddim_add(sts, "sessions",  NULL,  1, 1, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(sts);
-
-       rrddim_set(sts, "sessions", registry.usages_count);
-       rrdset_done(sts);
-
-       // ------------------------------------------------------------------------
-
-       if(!stc) stc = rrdset_find("netdata.registry_entries");
-       if(!stc) {
-               stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
-
-               rrddim_add(stc, "persons",        NULL,  1, 1, RRDDIM_ABSOLUTE);
-               rrddim_add(stc, "machines",       NULL,  1, 1, RRDDIM_ABSOLUTE);
-               rrddim_add(stc, "urls",           NULL,  1, 1, RRDDIM_ABSOLUTE);
-               rrddim_add(stc, "persons_urls",   NULL,  1, 1, RRDDIM_ABSOLUTE);
-               rrddim_add(stc, "machines_urls",  NULL,  1, 1, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(stc);
-
-       rrddim_set(stc, "persons",       registry.persons_count);
-       rrddim_set(stc, "machines",      registry.machines_count);
-       rrddim_set(stc, "urls",          registry.urls_count);
-       rrddim_set(stc, "persons_urls",  registry.persons_urls_count);
-       rrddim_set(stc, "machines_urls", registry.machines_urls_count);
-       rrdset_done(stc);
-
-       // ------------------------------------------------------------------------
-
-       if(!stm) stm = rrdset_find("netdata.registry_mem");
-       if(!stm) {
-               stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
-
-               rrddim_add(stm, "persons",        NULL,  1, 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(stm, "machines",       NULL,  1, 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(stm, "urls",           NULL,  1, 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(stm, "persons_urls",   NULL,  1, 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(stm, "machines_urls",  NULL,  1, 1024, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(stm);
-
-       rrddim_set(stm, "persons",       registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
-       rrddim_set(stm, "machines",      registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
-       rrddim_set(stm, "urls",          registry.urls_memory + registry.urls_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
-       rrddim_set(stm, "persons_urls",  registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
-       rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
-       rrdset_done(stm);
+    if(!registry.enabled) return;
+
+    static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
+
+    if(!sts) sts = rrdset_find("netdata.registry_sessions");
+    if(!sts) {
+        sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
+
+        rrddim_add(sts, "sessions",  NULL,  1, 1, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(sts);
+
+    rrddim_set(sts, "sessions", registry.usages_count);
+    rrdset_done(sts);
+
+    // ------------------------------------------------------------------------
+
+    if(!stc) stc = rrdset_find("netdata.registry_entries");
+    if(!stc) {
+        stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
+
+        rrddim_add(stc, "persons",        NULL,  1, 1, RRDDIM_ABSOLUTE);
+        rrddim_add(stc, "machines",       NULL,  1, 1, RRDDIM_ABSOLUTE);
+        rrddim_add(stc, "urls",           NULL,  1, 1, RRDDIM_ABSOLUTE);
+        rrddim_add(stc, "persons_urls",   NULL,  1, 1, RRDDIM_ABSOLUTE);
+        rrddim_add(stc, "machines_urls",  NULL,  1, 1, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(stc);
+
+    rrddim_set(stc, "persons",       registry.persons_count);
+    rrddim_set(stc, "machines",      registry.machines_count);
+    rrddim_set(stc, "urls",          registry.urls_count);
+    rrddim_set(stc, "persons_urls",  registry.persons_urls_count);
+    rrddim_set(stc, "machines_urls", registry.machines_urls_count);
+    rrdset_done(stc);
+
+    // ------------------------------------------------------------------------
+
+    if(!stm) stm = rrdset_find("netdata.registry_mem");
+    if(!stm) {
+        stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
+
+        rrddim_add(stm, "persons",        NULL,  1, 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(stm, "machines",       NULL,  1, 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(stm, "urls",           NULL,  1, 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(stm, "persons_urls",   NULL,  1, 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(stm, "machines_urls",  NULL,  1, 1024, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(stm);
+
+    rrddim_set(stm, "persons",       registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
+    rrddim_set(stm, "machines",      registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
+    rrddim_set(stm, "urls",          registry.urls_memory + registry.urls_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
+    rrddim_set(stm, "persons_urls",  registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
+    rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
+    rrdset_done(stm);
 }
index f3c6f260ecbee02c504da21a8bc3c997300becf4..b24da252b98376e3b6b8d929f1cc7f70083ebf76 100644 (file)
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -22,9 +22,9 @@ static int rrdcontext_compare(void* a, void* b);
 // RRDHOST
 
 RRDHOST localhost = {
-               .hostname = "localhost",
-               .rrdset_root = NULL,
-               .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
+        .hostname = "localhost",
+        .rrdset_root = NULL,
+        .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
         .rrdset_root_index = {
             { NULL, rrdset_compare },
             AVL_LOCK_INITIALIZER
@@ -44,21 +44,21 @@ RRDHOST localhost = {
 };
 
 void rrdhost_rwlock(RRDHOST *host) {
-       pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
+    pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
 }
 
 void rrdhost_rdlock(RRDHOST *host) {
-       pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
+    pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
 }
 
 void rrdhost_unlock(RRDHOST *host) {
-       pthread_rwlock_unlock(&host->rrdset_root_rwlock);
+    pthread_rwlock_unlock(&host->rrdset_root_rwlock);
 }
 
 void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
-       if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
-               fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
-       }
+    if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
+        fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -142,20 +142,20 @@ static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
 #define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
 
 static int rrdset_compare_name(void* a, void* b) {
-       RRDSET *A = rrdset_from_avlname(a);
-       RRDSET *B = rrdset_from_avlname(b);
+    RRDSET *A = rrdset_from_avlname(a);
+    RRDSET *B = rrdset_from_avlname(b);
 
-       // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
+    // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
 
-       if(A->hash_name < B->hash_name) return -1;
-       else if(A->hash_name > B->hash_name) return 1;
-       else return strcmp(A->name, B->name);
+    if(A->hash_name < B->hash_name) return -1;
+    else if(A->hash_name > B->hash_name) return 1;
+    else return strcmp(A->name, B->name);
 }
 
 RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
     void *result;
-       // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
-       result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
+    // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
+    result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
     if(result) return rrdset_from_avlname(result);
     return NULL;
 }
@@ -169,23 +169,23 @@ RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
 }
 
 static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
-       void *result = NULL;
-       RRDSET tmp;
-       tmp.name = name;
-       tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
-
-       // fprintf(stderr, "SEARCHING: %s\n", name);
-       result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
-       if(result) {
-               RRDSET *st = rrdset_from_avlname(result);
-               if(strcmp(st->magic, RRDSET_MAGIC))
-                       error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
-
-               // fprintf(stderr, "FOUND: %s\n", name);
-               return rrdset_from_avlname(result);
-       }
-       // fprintf(stderr, "NOT FOUND: %s\n", name);
-       return NULL;
+    void *result = NULL;
+    RRDSET tmp;
+    tmp.name = name;
+    tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
+
+    // fprintf(stderr, "SEARCHING: %s\n", name);
+    result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
+    if(result) {
+        RRDSET *st = rrdset_from_avlname(result);
+        if(strcmp(st->magic, RRDSET_MAGIC))
+            error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
+
+        // fprintf(stderr, "FOUND: %s\n", name);
+        return rrdset_from_avlname(result);
+    }
+    // fprintf(stderr, "NOT FOUND: %s\n", name);
+    return NULL;
 }
 
 
@@ -193,20 +193,20 @@ static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t
 // RRDDIM index
 
 static int rrddim_compare(void* a, void* b) {
-       if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
-       else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
-       else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
+    if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
+    else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
+    else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
 }
 
 #define rrddim_index_add(st, rd) avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
 #define rrddim_index_del(st,rd ) avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
 
 static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
-       RRDDIM tmp;
-       strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
-       tmp.hash = (hash)?hash:simple_hash(tmp.id);
+    RRDDIM tmp;
+    strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
+    tmp.hash = (hash)?hash:simple_hash(tmp.id);
 
-       return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
+    return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
 }
 
 // ----------------------------------------------------------------------------
@@ -214,29 +214,29 @@ static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
 
 int rrdset_type_id(const char *name)
 {
-       if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
-       else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
-       else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
-       return RRDSET_TYPE_LINE;
+    if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
+    else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
+    else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
+    return RRDSET_TYPE_LINE;
 }
 
 const char *rrdset_type_name(int chart_type)
 {
-       static char line[] = RRDSET_TYPE_LINE_NAME;
-       static char area[] = RRDSET_TYPE_AREA_NAME;
-       static char stacked[] = RRDSET_TYPE_STACKED_NAME;
+    static char line[] = RRDSET_TYPE_LINE_NAME;
+    static char area[] = RRDSET_TYPE_AREA_NAME;
+    static char stacked[] = RRDSET_TYPE_STACKED_NAME;
 
-       switch(chart_type) {
-               case RRDSET_TYPE_LINE:
-                       return line;
+    switch(chart_type) {
+        case RRDSET_TYPE_LINE:
+            return line;
 
-               case RRDSET_TYPE_AREA:
-                       return area;
+        case RRDSET_TYPE_AREA:
+            return area;
 
-               case RRDSET_TYPE_STACKED:
-                       return stacked;
-       }
-       return line;
+        case RRDSET_TYPE_STACKED:
+            return stacked;
+    }
+    return line;
 }
 
 // ----------------------------------------------------------------------------
@@ -244,33 +244,33 @@ const char *rrdset_type_name(int chart_type)
 
 const char *rrd_memory_mode_name(int id)
 {
-       static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
-       static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
-       static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
+    static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
+    static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
+    static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
 
-       switch(id) {
-               case RRD_MEMORY_MODE_RAM:
-                       return ram;
+    switch(id) {
+        case RRD_MEMORY_MODE_RAM:
+            return ram;
 
-               case RRD_MEMORY_MODE_MAP:
-                       return map;
+        case RRD_MEMORY_MODE_MAP:
+            return map;
 
-               case RRD_MEMORY_MODE_SAVE:
-               default:
-                       return save;
-       }
+        case RRD_MEMORY_MODE_SAVE:
+        default:
+            return save;
+    }
 
-       return save;
+    return save;
 }
 
 int rrd_memory_mode_id(const char *name)
 {
-       if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
-               return RRD_MEMORY_MODE_RAM;
-       else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
-               return RRD_MEMORY_MODE_MAP;
+    if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
+        return RRD_MEMORY_MODE_RAM;
+    else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
+        return RRD_MEMORY_MODE_MAP;
 
-       return RRD_MEMORY_MODE_SAVE;
+    return RRD_MEMORY_MODE_SAVE;
 }
 
 // ----------------------------------------------------------------------------
@@ -278,34 +278,34 @@ int rrd_memory_mode_id(const char *name)
 
 int rrddim_algorithm_id(const char *name)
 {
-       if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0)                  return RRDDIM_INCREMENTAL;
-       if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0)                     return RRDDIM_ABSOLUTE;
-       if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0)                 return RRDDIM_PCENT_OVER_ROW_TOTAL;
-       if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0)        return RRDDIM_PCENT_OVER_DIFF_TOTAL;
-       return RRDDIM_ABSOLUTE;
+    if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0)          return RRDDIM_INCREMENTAL;
+    if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0)             return RRDDIM_ABSOLUTE;
+    if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0)         return RRDDIM_PCENT_OVER_ROW_TOTAL;
+    if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0)    return RRDDIM_PCENT_OVER_DIFF_TOTAL;
+    return RRDDIM_ABSOLUTE;
 }
 
 const char *rrddim_algorithm_name(int chart_type)
 {
-       static char absolute[] = RRDDIM_ABSOLUTE_NAME;
-       static char incremental[] = RRDDIM_INCREMENTAL_NAME;
-       static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
-       static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
+    static char absolute[] = RRDDIM_ABSOLUTE_NAME;
+    static char incremental[] = RRDDIM_INCREMENTAL_NAME;
+    static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
+    static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
 
-       switch(chart_type) {
-               case RRDDIM_ABSOLUTE:
-                       return absolute;
+    switch(chart_type) {
+        case RRDDIM_ABSOLUTE:
+            return absolute;
 
-               case RRDDIM_INCREMENTAL:
-                       return incremental;
+        case RRDDIM_INCREMENTAL:
+            return incremental;
 
-               case RRDDIM_PCENT_OVER_ROW_TOTAL:
-                       return percentage_of_absolute_row;
+        case RRDDIM_PCENT_OVER_ROW_TOTAL:
+            return percentage_of_absolute_row;
 
-               case RRDDIM_PCENT_OVER_DIFF_TOTAL:
-                       return percentage_of_incremental_row;
-       }
-       return absolute;
+        case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+            return percentage_of_incremental_row;
+    }
+    return absolute;
 }
 
 // ----------------------------------------------------------------------------
@@ -313,38 +313,38 @@ const char *rrddim_algorithm_name(int chart_type)
 
 char *rrdset_strncpyz_name(char *to, const char *from, size_t length)
 {
-       char c, *p = to;
+    char c, *p = to;
 
-       while (length-- && (c = *from++)) {
-               if(c != '.' && !isalnum(c))
-                       c = '_';
+    while (length-- && (c = *from++)) {
+        if(c != '.' && !isalnum(c))
+            c = '_';
 
-               *p++ = c;
-       }
+        *p++ = c;
+    }
 
-       *p = '\0';
+    *p = '\0';
 
-       return to;
+    return to;
 }
 
 void rrdset_set_name(RRDSET *st, const char *name)
 {
-       debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
+    debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
 
-       if(st->name) {
+    if(st->name) {
         rrdset_index_del_name(&localhost, st);
         rrdsetvar_rename_all(st);
     }
 
-       char b[CONFIG_MAX_VALUE + 1];
-       char n[RRD_ID_LENGTH_MAX + 1];
+    char b[CONFIG_MAX_VALUE + 1];
+    char n[RRD_ID_LENGTH_MAX + 1];
 
-       snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
-       rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
-       st->name = config_get(st->id, "name", b);
-       st->hash_name = simple_hash(st->name);
+    snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
+    rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
+    st->name = config_get(st->id, "name", b);
+    st->hash_name = simple_hash(st->name);
 
-       rrdset_index_add_name(&localhost, st);
+    rrdset_index_add_name(&localhost, st);
 }
 
 // ----------------------------------------------------------------------------
@@ -352,30 +352,30 @@ void rrdset_set_name(RRDSET *st, const char *name)
 
 char *rrdset_cache_dir(const char *id)
 {
-       char *ret = NULL;
-
-       static char *cache_dir = NULL;
-       if(!cache_dir) {
-               cache_dir = config_get("global", "cache directory", CACHE_DIR);
-               int r = mkdir(cache_dir, 0755);
-               if(r != 0 && errno != EEXIST)
-                       error("Cannot create directory '%s'", cache_dir);
-       }
-
-       char b[FILENAME_MAX + 1];
-       char n[FILENAME_MAX + 1];
-       rrdset_strncpyz_name(b, id, FILENAME_MAX);
-
-       snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
-       ret = config_get(id, "cache directory", n);
-
-       if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
-               int r = mkdir(ret, 0775);
-               if(r != 0 && errno != EEXIST)
-                       error("Cannot create directory '%s'", ret);
-       }
-
-       return ret;
+    char *ret = NULL;
+
+    static char *cache_dir = NULL;
+    if(!cache_dir) {
+        cache_dir = config_get("global", "cache directory", CACHE_DIR);
+        int r = mkdir(cache_dir, 0755);
+        if(r != 0 && errno != EEXIST)
+            error("Cannot create directory '%s'", cache_dir);
+    }
+
+    char b[FILENAME_MAX + 1];
+    char n[FILENAME_MAX + 1];
+    rrdset_strncpyz_name(b, id, FILENAME_MAX);
+
+    snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
+    ret = config_get(id, "cache directory", n);
+
+    if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+        int r = mkdir(ret, 0775);
+        if(r != 0 && errno != EEXIST)
+            error("Cannot create directory '%s'", ret);
+    }
+
+    return ret;
 }
 
 // ----------------------------------------------------------------------------
@@ -383,156 +383,156 @@ char *rrdset_cache_dir(const char *id)
 
 void rrdset_reset(RRDSET *st)
 {
-       debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
-
-       st->last_collected_time.tv_sec = 0;
-       st->last_collected_time.tv_usec = 0;
-       st->last_updated.tv_sec = 0;
-       st->last_updated.tv_usec = 0;
-       st->current_entry = 0;
-       st->counter = 0;
-       st->counter_done = 0;
-
-       RRDDIM *rd;
-       for(rd = st->dimensions; rd ; rd = rd->next) {
-               rd->last_collected_time.tv_sec = 0;
-               rd->last_collected_time.tv_usec = 0;
-               rd->counter = 0;
-               bzero(rd->values, rd->entries * sizeof(storage_number));
-       }
+    debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
+
+    st->last_collected_time.tv_sec = 0;
+    st->last_collected_time.tv_usec = 0;
+    st->last_updated.tv_sec = 0;
+    st->last_updated.tv_usec = 0;
+    st->current_entry = 0;
+    st->counter = 0;
+    st->counter_done = 0;
+
+    RRDDIM *rd;
+    for(rd = st->dimensions; rd ; rd = rd->next) {
+        rd->last_collected_time.tv_sec = 0;
+        rd->last_collected_time.tv_usec = 0;
+        rd->counter = 0;
+        bzero(rd->values, rd->entries * sizeof(storage_number));
+    }
 }
 
 RRDSET *rrdset_create(const char *type, const char *id, const char *name, const char *family, const char *context, const char *title, const char *units, long priority, int update_every, int chart_type)
 {
-       if(!type || !type[0]) {
-               fatal("Cannot create rrd stats without a type.");
-               return NULL;
-       }
-
-       if(!id || !id[0]) {
-               fatal("Cannot create rrd stats without an id.");
-               return NULL;
-       }
-
-       char fullid[RRD_ID_LENGTH_MAX + 1];
-       char fullfilename[FILENAME_MAX + 1];
-       RRDSET *st = NULL;
-
-       snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
-
-       st = rrdset_find(fullid);
-       if(st) {
-               error("Cannot create rrd stats for '%s', it already exists.", fullid);
-               return st;
-       }
-
-       long entries = config_get_number(fullid, "history", rrd_default_history_entries);
-       if(entries < 5) entries = config_set_number(fullid, "history", 5);
-       if(entries > RRD_HISTORY_ENTRIES_MAX) entries = config_set_number(fullid, "history", RRD_HISTORY_ENTRIES_MAX);
-
-       int enabled = config_get_boolean(fullid, "enabled", 1);
-       if(!enabled) entries = 5;
-
-       unsigned long size = sizeof(RRDSET);
-       char *cache_dir = rrdset_cache_dir(fullid);
-
-       debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
-
-       snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
-       if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
-       if(st) {
-               if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
-                       errno = 0;
-                       info("Initializing file %s.", fullfilename);
-                       bzero(st, size);
-               }
-               else if(strcmp(st->id, fullid) != 0) {
-                       errno = 0;
-                       error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
-                       // munmap(st, size);
-                       // st = NULL;
-                       bzero(st, size);
-               }
-               else if(st->memsize != size || st->entries != entries) {
-                       errno = 0;
-                       error("File %s does not have the desired size. Clearing it.", fullfilename);
-                       bzero(st, size);
-               }
-               else if(st->update_every != update_every) {
-                       errno = 0;
-                       error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
-                       bzero(st, size);
-               }
-               else if((time(NULL) - st->last_updated.tv_sec) > update_every * entries) {
-                       errno = 0;
-                       error("File %s is too old. Clearing it.", fullfilename);
-                       bzero(st, size);
-               }
-       }
-
-       if(st) {
-               st->name = NULL;
-               st->type = NULL;
-               st->family = NULL;
-               st->context = NULL;
-               st->title = NULL;
-               st->units = NULL;
-               st->dimensions = NULL;
-               st->next = NULL;
-               st->mapped = rrd_memory_mode;
+    if(!type || !type[0]) {
+        fatal("Cannot create rrd stats without a type.");
+        return NULL;
+    }
+
+    if(!id || !id[0]) {
+        fatal("Cannot create rrd stats without an id.");
+        return NULL;
+    }
+
+    char fullid[RRD_ID_LENGTH_MAX + 1];
+    char fullfilename[FILENAME_MAX + 1];
+    RRDSET *st = NULL;
+
+    snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
+
+    st = rrdset_find(fullid);
+    if(st) {
+        error("Cannot create rrd stats for '%s', it already exists.", fullid);
+        return st;
+    }
+
+    long entries = config_get_number(fullid, "history", rrd_default_history_entries);
+    if(entries < 5) entries = config_set_number(fullid, "history", 5);
+    if(entries > RRD_HISTORY_ENTRIES_MAX) entries = config_set_number(fullid, "history", RRD_HISTORY_ENTRIES_MAX);
+
+    int enabled = config_get_boolean(fullid, "enabled", 1);
+    if(!enabled) entries = 5;
+
+    unsigned long size = sizeof(RRDSET);
+    char *cache_dir = rrdset_cache_dir(fullid);
+
+    debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
+
+    snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
+    if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
+    if(st) {
+        if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
+            errno = 0;
+            info("Initializing file %s.", fullfilename);
+            bzero(st, size);
+        }
+        else if(strcmp(st->id, fullid) != 0) {
+            errno = 0;
+            error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
+            // munmap(st, size);
+            // st = NULL;
+            bzero(st, size);
+        }
+        else if(st->memsize != size || st->entries != entries) {
+            errno = 0;
+            error("File %s does not have the desired size. Clearing it.", fullfilename);
+            bzero(st, size);
+        }
+        else if(st->update_every != update_every) {
+            errno = 0;
+            error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
+            bzero(st, size);
+        }
+        else if((time(NULL) - st->last_updated.tv_sec) > update_every * entries) {
+            errno = 0;
+            error("File %s is too old. Clearing it.", fullfilename);
+            bzero(st, size);
+        }
+    }
+
+    if(st) {
+        st->name = NULL;
+        st->type = NULL;
+        st->family = NULL;
+        st->context = NULL;
+        st->title = NULL;
+        st->units = NULL;
+        st->dimensions = NULL;
+        st->next = NULL;
+        st->mapped = rrd_memory_mode;
         st->variables = NULL;
-       }
-       else {
-               st = callocz(1, size);
-               st->mapped = RRD_MEMORY_MODE_RAM;
-       }
-       st->memsize = size;
-       st->entries = entries;
-       st->update_every = update_every;
+    }
+    else {
+        st = callocz(1, size);
+        st->mapped = RRD_MEMORY_MODE_RAM;
+    }
+    st->memsize = size;
+    st->entries = entries;
+    st->update_every = update_every;
 
-       if(st->current_entry >= st->entries) st->current_entry = 0;
+    if(st->current_entry >= st->entries) st->current_entry = 0;
 
-       strcpy(st->cache_filename, fullfilename);
-       strcpy(st->magic, RRDSET_MAGIC);
+    strcpy(st->cache_filename, fullfilename);
+    strcpy(st->magic, RRDSET_MAGIC);
 
-       strcpy(st->id, fullid);
-       st->hash = simple_hash(st->id);
+    strcpy(st->id, fullid);
+    st->hash = simple_hash(st->id);
 
-       st->cache_dir = cache_dir;
+    st->cache_dir = cache_dir;
 
-       st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
-       st->type       = config_get(st->id, "type", type);
-       st->family     = config_get(st->id, "family", family?family:st->type);
-       st->context    = config_get(st->id, "context", context?context:st->id);
-       st->units      = config_get(st->id, "units", units?units:"");
+    st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
+    st->type       = config_get(st->id, "type", type);
+    st->family     = config_get(st->id, "family", family?family:st->type);
+    st->context    = config_get(st->id, "context", context?context:st->id);
+    st->units      = config_get(st->id, "units", units?units:"");
 
-       st->priority = config_get_number(st->id, "priority", priority);
-       st->enabled = enabled;
+    st->priority = config_get_number(st->id, "priority", priority);
+    st->enabled = enabled;
 
-       st->isdetail = 0;
-       st->debug = 0;
+    st->isdetail = 0;
+    st->debug = 0;
 
-       st->last_collected_time.tv_sec = 0;
-       st->last_collected_time.tv_usec = 0;
-       st->counter_done = 0;
+    st->last_collected_time.tv_sec = 0;
+    st->last_collected_time.tv_usec = 0;
+    st->counter_done = 0;
 
-       st->gap_when_lost_iterations_above = (int) (
-                       config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
+    st->gap_when_lost_iterations_above = (int) (
+            config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
 
-       avl_init_lock(&st->dimensions_index, rrddim_compare);
+    avl_init_lock(&st->dimensions_index, rrddim_compare);
     avl_init_lock(&st->variables_root_index, rrdvar_compare);
 
-       pthread_rwlock_init(&st->rwlock, NULL);
-       pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
+    pthread_rwlock_init(&st->rwlock, NULL);
+    pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
 
-       if(name && *name) rrdset_set_name(st, name);
-       else rrdset_set_name(st, id);
+    if(name && *name) rrdset_set_name(st, name);
+    else rrdset_set_name(st, id);
 
-       {
-               char varvalue[CONFIG_MAX_VALUE + 1];
-               snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
-               st->title = config_get(st->id, "title", varvalue);
-       }
+    {
+        char varvalue[CONFIG_MAX_VALUE + 1];
+        snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
+        st->title = config_get(st->id, "title", varvalue);
+    }
 
     st->rrdcontext = rrdcontext_create(st->context);
     st->rrdhost = &localhost;
@@ -547,204 +547,204 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
 
     rrdsetcalc_link_matching(st);
 
-       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+    pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
-       return(st);
+    return(st);
 }
 
 RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm)
 {
-       char filename[FILENAME_MAX + 1];
-       char fullfilename[FILENAME_MAX + 1];
-
-       char varname[CONFIG_MAX_NAME + 1];
-       RRDDIM *rd = NULL;
-       unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
-
-       debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
-
-       rrdset_strncpyz_name(filename, id, FILENAME_MAX);
-       snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
-       if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
-       if(rd) {
-               struct timeval now;
-               gettimeofday(&now, NULL);
-
-               if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
-                       errno = 0;
-                       info("Initializing file %s.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(rd->memsize != size) {
-                       errno = 0;
-                       error("File %s does not have the desired size. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(rd->multiplier != multiplier) {
-                       errno = 0;
-                       error("File %s does not have the same multiplier. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(rd->divisor != divisor) {
-                       errno = 0;
-                       error("File %s does not have the same divisor. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(rd->algorithm != algorithm) {
-                       errno = 0;
-                       error("File %s does not have the same algorithm. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(rd->update_every != st->update_every) {
-                       errno = 0;
-                       error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(usec_dt(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * 1000000ULL)) {
-                       errno = 0;
-                       error("File %s is too old. Clearing it.", fullfilename);
-                       bzero(rd, size);
-               }
-               else if(strcmp(rd->id, id) != 0) {
-                       errno = 0;
-                       error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
-                       // munmap(rd, size);
-                       // rd = NULL;
-                       bzero(rd, size);
-               }
-       }
-
-       if(rd) {
-               // we have a file mapped for rd
-               rd->mapped = rrd_memory_mode;
-               rd->flags = 0x00000000;
+    char filename[FILENAME_MAX + 1];
+    char fullfilename[FILENAME_MAX + 1];
+
+    char varname[CONFIG_MAX_NAME + 1];
+    RRDDIM *rd = NULL;
+    unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
+
+    debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
+
+    rrdset_strncpyz_name(filename, id, FILENAME_MAX);
+    snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
+    if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
+    if(rd) {
+        struct timeval now;
+        gettimeofday(&now, NULL);
+
+        if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
+            errno = 0;
+            info("Initializing file %s.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(rd->memsize != size) {
+            errno = 0;
+            error("File %s does not have the desired size. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(rd->multiplier != multiplier) {
+            errno = 0;
+            error("File %s does not have the same multiplier. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(rd->divisor != divisor) {
+            errno = 0;
+            error("File %s does not have the same divisor. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(rd->algorithm != algorithm) {
+            errno = 0;
+            error("File %s does not have the same algorithm. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(rd->update_every != st->update_every) {
+            errno = 0;
+            error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(usec_dt(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * 1000000ULL)) {
+            errno = 0;
+            error("File %s is too old. Clearing it.", fullfilename);
+            bzero(rd, size);
+        }
+        else if(strcmp(rd->id, id) != 0) {
+            errno = 0;
+            error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
+            // munmap(rd, size);
+            // rd = NULL;
+            bzero(rd, size);
+        }
+    }
+
+    if(rd) {
+        // we have a file mapped for rd
+        rd->mapped = rrd_memory_mode;
+        rd->flags = 0x00000000;
         rd->variables = NULL;
-               rd->next = NULL;
-               rd->name = NULL;
-       }
-       else {
-               // if we didn't manage to get a mmap'd dimension, just create one
-
-               rd = callocz(1, size);
-               rd->mapped = RRD_MEMORY_MODE_RAM;
-       }
-       rd->memsize = size;
-
-       strcpy(rd->magic, RRDDIMENSION_MAGIC);
-       strcpy(rd->cache_filename, fullfilename);
-       strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
-       rd->hash = simple_hash(rd->id);
-
-       snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
-       rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
-
-       snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
-       rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
-
-       snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
-       rd->multiplier = config_get_number(st->id, varname, multiplier);
-
-       snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
-       rd->divisor = config_get_number(st->id, varname, divisor);
-       if(!rd->divisor) rd->divisor = 1;
-
-       rd->entries = st->entries;
-       rd->update_every = st->update_every;
-
-       // prevent incremental calculation spikes
-       rd->counter = 0;
-       rd->updated = 0;
-       rd->calculated_value = 0;
-       rd->last_calculated_value = 0;
-       rd->collected_value = 0;
-       rd->last_collected_value = 0;
-       rd->collected_volume = 0;
-       rd->stored_volume = 0;
-       rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
-       rd->last_collected_time.tv_sec = 0;
-       rd->last_collected_time.tv_usec = 0;
+        rd->next = NULL;
+        rd->name = NULL;
+    }
+    else {
+        // if we didn't manage to get a mmap'd dimension, just create one
+
+        rd = callocz(1, size);
+        rd->mapped = RRD_MEMORY_MODE_RAM;
+    }
+    rd->memsize = size;
+
+    strcpy(rd->magic, RRDDIMENSION_MAGIC);
+    strcpy(rd->cache_filename, fullfilename);
+    strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
+    rd->hash = simple_hash(rd->id);
+
+    snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+    rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
+
+    snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
+    rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
+
+    snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
+    rd->multiplier = config_get_number(st->id, varname, multiplier);
+
+    snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
+    rd->divisor = config_get_number(st->id, varname, divisor);
+    if(!rd->divisor) rd->divisor = 1;
+
+    rd->entries = st->entries;
+    rd->update_every = st->update_every;
+
+    // prevent incremental calculation spikes
+    rd->counter = 0;
+    rd->updated = 0;
+    rd->calculated_value = 0;
+    rd->last_calculated_value = 0;
+    rd->collected_value = 0;
+    rd->last_collected_value = 0;
+    rd->collected_volume = 0;
+    rd->stored_volume = 0;
+    rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+    rd->last_collected_time.tv_sec = 0;
+    rd->last_collected_time.tv_usec = 0;
     rd->rrdset = st;
 
     // append this dimension
-       pthread_rwlock_wrlock(&st->rwlock);
-       if(!st->dimensions)
-               st->dimensions = rd;
-       else {
-               RRDDIM *td = st->dimensions;
-               for(; td->next; td = td->next) ;
-               td->next = rd;
-       }
+    pthread_rwlock_wrlock(&st->rwlock);
+    if(!st->dimensions)
+        st->dimensions = rd;
+    else {
+        RRDDIM *td = st->dimensions;
+        for(; td->next; td = td->next) ;
+        td->next = rd;
+    }
 
     rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->calculated_value, 0);
     rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->collected_value, 0);
     rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected", &rd->last_collected_time.tv_sec, 0);
 
-       pthread_rwlock_unlock(&st->rwlock);
+    pthread_rwlock_unlock(&st->rwlock);
 
-       rrddim_index_add(st, rd);
+    rrddim_index_add(st, rd);
 
-       return(rd);
+    return(rd);
 }
 
 void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
 {
-       debug(D_RRD_CALLS, "rrddim_set_name() %s.%s", st->name, rd->name);
+    debug(D_RRD_CALLS, "rrddim_set_name() %s.%s", st->name, rd->name);
 
-       char varname[CONFIG_MAX_NAME + 1];
-       snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
-       config_set_default(st->id, varname, name);
+    char varname[CONFIG_MAX_NAME + 1];
+    snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
+    config_set_default(st->id, varname, name);
 
     rrddimvar_rename_all(rd);
 }
 
 void rrddim_free(RRDSET *st, RRDDIM *rd)
 {
-       debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
+    debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
 
-       RRDDIM *i, *last = NULL;
-       for(i = st->dimensions; i && i != rd ; i = i->next) last = i;
+    RRDDIM *i, *last = NULL;
+    for(i = st->dimensions; i && i != rd ; i = i->next) last = i;
 
-       if(!i) {
-               error("Request to free dimension %s.%s but it is not linked.", st->id, rd->name);
-               return;
-       }
+    if(!i) {
+        error("Request to free dimension %s.%s but it is not linked.", st->id, rd->name);
+        return;
+    }
 
-       if(last) last->next = rd->next;
-       else st->dimensions = rd->next;
-       rd->next = NULL;
+    if(last) last->next = rd->next;
+    else st->dimensions = rd->next;
+    rd->next = NULL;
 
     while(rd->variables)
         rrddimvar_free(rd->variables);
 
     rrddim_index_del(st, rd);
 
-       // free(rd->annotations);
-       if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
-               debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
-               savememory(rd->cache_filename, rd, rd->memsize);
-
-               debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
-               munmap(rd, rd->memsize);
-       }
-       else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
-               debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
-               munmap(rd, rd->memsize);
-       }
-       else {
-               debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
-               freez(rd);
-       }
+    // free(rd->annotations);
+    if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
+        debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+        savememory(rd->cache_filename, rd, rd->memsize);
+
+        debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
+        munmap(rd, rd->memsize);
+    }
+    else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
+        debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
+        munmap(rd, rd->memsize);
+    }
+    else {
+        debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
+        freez(rd);
+    }
 }
 
 void rrdset_free_all(void)
 {
-       info("Freeing all memory...");
+    info("Freeing all memory...");
 
     pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
 
-       RRDSET *st;
-       for(st = localhost.rrdset_root; st ;) {
-               RRDSET *next = st->next;
+    RRDSET *st;
+    for(st = localhost.rrdset_root; st ;) {
+        RRDSET *next = st->next;
 
         pthread_rwlock_wrlock(&st->rwlock);
 
@@ -755,7 +755,7 @@ void rrdset_free_all(void)
             rrdsetcalc_unlink(st->calculations);
 
         while(st->dimensions)
-                       rrddim_free(st, st->dimensions);
+            rrddim_free(st, st->dimensions);
 
         rrdset_index_del(&localhost, st);
 
@@ -765,704 +765,704 @@ void rrdset_free_all(void)
 
         pthread_rwlock_unlock(&st->rwlock);
 
-               if(st->mapped == RRD_MEMORY_MODE_SAVE) {
-                       debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
-                       savememory(st->cache_filename, st, st->memsize);
-
-                       debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
-                       munmap(st, st->memsize);
-               }
-               else if(st->mapped == RRD_MEMORY_MODE_MAP) {
-                       debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
-                       munmap(st, st->memsize);
-               }
-               else
-                       freez(st);
-
-               st = next;
-       }
+        if(st->mapped == RRD_MEMORY_MODE_SAVE) {
+            debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
+            savememory(st->cache_filename, st, st->memsize);
+
+            debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
+            munmap(st, st->memsize);
+        }
+        else if(st->mapped == RRD_MEMORY_MODE_MAP) {
+            debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
+            munmap(st, st->memsize);
+        }
+        else
+            freez(st);
+
+        st = next;
+    }
     localhost.rrdset_root = NULL;
 
     pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
-       info("Memory cleanup completed...");
+    info("Memory cleanup completed...");
 }
 
 void rrdset_save_all(void) {
-       info("Saving database...");
-
-       RRDSET *st;
-       RRDDIM *rd;
-
-       pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
-       for(st = localhost.rrdset_root; st ; st = st->next) {
-               pthread_rwlock_wrlock(&st->rwlock);
-
-               if(st->mapped == RRD_MEMORY_MODE_SAVE) {
-                       debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
-                       savememory(st->cache_filename, st, st->memsize);
-               }
-
-               for(rd = st->dimensions; rd ; rd = rd->next) {
-                       if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
-                               debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
-                               savememory(rd->cache_filename, rd, rd->memsize);
-                       }
-               }
-
-               pthread_rwlock_unlock(&st->rwlock);
-       }
-       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+    info("Saving database...");
+
+    RRDSET *st;
+    RRDDIM *rd;
+
+    pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
+    for(st = localhost.rrdset_root; st ; st = st->next) {
+        pthread_rwlock_wrlock(&st->rwlock);
+
+        if(st->mapped == RRD_MEMORY_MODE_SAVE) {
+            debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
+            savememory(st->cache_filename, st, st->memsize);
+        }
+
+        for(rd = st->dimensions; rd ; rd = rd->next) {
+            if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
+                debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+                savememory(rd->cache_filename, rd, rd->memsize);
+            }
+        }
+
+        pthread_rwlock_unlock(&st->rwlock);
+    }
+    pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 }
 
 
 RRDSET *rrdset_find(const char *id)
 {
-       debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
+    debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
 
-       RRDSET *st = rrdset_index_find(&localhost, id, 0);
-       return(st);
+    RRDSET *st = rrdset_index_find(&localhost, id, 0);
+    return(st);
 }
 
 RRDSET *rrdset_find_bytype(const char *type, const char *id)
 {
-       debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
+    debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
 
-       char buf[RRD_ID_LENGTH_MAX + 1];
+    char buf[RRD_ID_LENGTH_MAX + 1];
 
-       strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
-       strcat(buf, ".");
-       int len = (int) strlen(buf);
-       strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
+    strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
+    strcat(buf, ".");
+    int len = (int) strlen(buf);
+    strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
 
-       return(rrdset_find(buf));
+    return(rrdset_find(buf));
 }
 
 RRDSET *rrdset_find_byname(const char *name)
 {
-       debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
+    debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
 
-       RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
-       return(st);
+    RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
+    return(st);
 }
 
 RRDDIM *rrddim_find(RRDSET *st, const char *id)
 {
-       debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
+    debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
 
-       return rrddim_index_find(st, id, 0);
+    return rrddim_index_find(st, id, 0);
 }
 
 int rrddim_hide(RRDSET *st, const char *id)
 {
-       debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
+    debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
 
-       RRDDIM *rd = rrddim_find(st, id);
-       if(unlikely(!rd)) {
-               error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
-               return 1;
-       }
+    RRDDIM *rd = rrddim_find(st, id);
+    if(unlikely(!rd)) {
+        error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+        return 1;
+    }
 
-       rd->flags |= RRDDIM_FLAG_HIDDEN;
-       return 0;
+    rd->flags |= RRDDIM_FLAG_HIDDEN;
+    return 0;
 }
 
 int rrddim_unhide(RRDSET *st, const char *id)
 {
-       debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
+    debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
 
-       RRDDIM *rd = rrddim_find(st, id);
-       if(unlikely(!rd)) {
-               error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
-               return 1;
-       }
+    RRDDIM *rd = rrddim_find(st, id);
+    if(unlikely(!rd)) {
+        error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+        return 1;
+    }
 
-       if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
-       return 0;
+    if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
+    return 0;
 }
 
 collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
 {
-       debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
+    debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
 
-       gettimeofday(&rd->last_collected_time, NULL);
-       rd->collected_value = value;
-       rd->updated = 1;
-       rd->counter++;
+    gettimeofday(&rd->last_collected_time, NULL);
+    rd->collected_value = value;
+    rd->updated = 1;
+    rd->counter++;
 
-       return rd->last_collected_value;
+    return rd->last_collected_value;
 }
 
 collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
 {
-       RRDDIM *rd = rrddim_find(st, id);
-       if(unlikely(!rd)) {
-               error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
-               return 0;
-       }
+    RRDDIM *rd = rrddim_find(st, id);
+    if(unlikely(!rd)) {
+        error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
+        return 0;
+    }
 
-       return rrddim_set_by_pointer(st, rd, value);
+    return rrddim_set_by_pointer(st, rd, value);
 }
 
 void rrdset_next_usec(RRDSET *st, unsigned long long microseconds)
 {
-       if(!microseconds) rrdset_next(st);
-       else {
-               debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
+    if(!microseconds) rrdset_next(st);
+    else {
+        debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
 
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
-               st->usec_since_last_update = microseconds;
-       }
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
+        st->usec_since_last_update = microseconds;
+    }
 }
 
 void rrdset_next(RRDSET *st)
 {
-       unsigned long long microseconds = 0;
+    unsigned long long microseconds = 0;
 
-       if(likely(st->last_collected_time.tv_sec)) {
-               struct timeval now;
-               gettimeofday(&now, NULL);
-               microseconds = usec_dt(&now, &st->last_collected_time);
-       }
-       // prevent infinite loop
-       else microseconds = st->update_every * 1000000ULL;
+    if(likely(st->last_collected_time.tv_sec)) {
+        struct timeval now;
+        gettimeofday(&now, NULL);
+        microseconds = usec_dt(&now, &st->last_collected_time);
+    }
+    // prevent infinite loop
+    else microseconds = st->update_every * 1000000ULL;
 
-       rrdset_next_usec(st, microseconds);
+    rrdset_next_usec(st, microseconds);
 }
 
 void rrdset_next_plugins(RRDSET *st)
 {
-       rrdset_next(st);
+    rrdset_next(st);
 }
 
 unsigned long long rrdset_done(RRDSET *st)
 {
-       if(unlikely(netdata_exit)) return 0;
-
-       debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
-
-       RRDDIM *rd, *last;
-       int oldstate, store_this_entry = 1, first_entry = 0;
-       unsigned long long last_ut, now_ut, next_ut, stored_entries = 0;
-
-       if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
-               error("Cannot set pthread cancel state to DISABLE.");
-
-       // a read lock is OK here
-       pthread_rwlock_rdlock(&st->rwlock);
-
-       // enable the chart, if it was disabled
-       if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
-               st->enabled = 1;
-
-       // check if the chart has a long time to be updated
-       if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
-               info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
-               rrdset_reset(st);
-               st->usec_since_last_update = st->update_every * 1000000ULL;
-               first_entry = 1;
-       }
-       if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
-
-       // set last_collected_time
-       if(unlikely(!st->last_collected_time.tv_sec)) {
-               // it is the first entry
-               // set the last_collected_time to now
-               gettimeofday(&st->last_collected_time, NULL);
-
-               // the first entry should not be stored
-               store_this_entry = 0;
-               first_entry = 1;
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
-       }
-       else {
-               // it is not the first entry
-               // calculate the proper last_collected_time, using usec_since_last_update
-               unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
-               st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
-               st->last_collected_time.tv_usec = (suseconds_t) (ut % 1000000ULL);
-       }
-
-       // if this set has not been updated in the past
-       // we fake the last_update time to be = now - usec_since_last_update
-       if(unlikely(!st->last_updated.tv_sec)) {
-               // it has never been updated before
-               // set a fake last_updated, in the past using usec_since_last_update
-               unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
-               st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
-               st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
-
-               // the first entry should not be stored
-               store_this_entry = 0;
-               first_entry = 1;
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
-       }
-
-       // check if we will re-write the entire data set
-       if(unlikely(usec_dt(&st->last_collected_time, &st->last_updated) > st->update_every * st->entries * 1000000ULL)) {
-               info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Reseting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
-               rrdset_reset(st);
-
-               st->usec_since_last_update = st->update_every * 1000000ULL;
-
-               gettimeofday(&st->last_collected_time, NULL);
-
-               unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
-               st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
-               st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
-
-               // the first entry should not be stored
-               store_this_entry = 0;
-               first_entry = 1;
-       }
-
-       // these are the 3 variables that will help us in interpolation
-       // last_ut = the last time we added a value to the storage
-       //  now_ut = the time the current value is taken at
-       // next_ut = the time of the next interpolation point
-       last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
-       now_ut  = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
-       next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
-
-       if(unlikely(!first_entry && now_ut < next_ut)) {
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
-       }
-
-       if(unlikely(st->debug)) {
-               debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
-               debug(D_RRD_STATS, "%s: now  ut = %0.3Lf (current update time)", st->name, (long double)now_ut/1000000.0);
-               debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
-       }
-
-       if(unlikely(!st->counter_done)) {
-               store_this_entry = 0;
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
-       }
-       st->counter_done++;
-
-       // calculate totals and count the dimensions
-       int dimensions;
-       st->collected_total = 0;
-       for( rd = st->dimensions, dimensions = 0 ; likely(rd) ; rd = rd->next, dimensions++ )
-               if(likely(rd->updated)) st->collected_total += rd->collected_value;
-
-       uint32_t storage_flags = SN_EXISTS;
-
-       // process all dimensions to calculate their values
-       // based on the collected figures only
-       // at this stage we do not interpolate anything
-       for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
-
-               if(unlikely(!rd->updated)) {
-                       rd->calculated_value = 0;
-                       continue;
-               }
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
-                       " last_collected_value = " COLLECTED_NUMBER_FORMAT
-                       " collected_value = " COLLECTED_NUMBER_FORMAT
-                       " last_calculated_value = " CALCULATED_NUMBER_FORMAT
-                       " calculated_value = " CALCULATED_NUMBER_FORMAT
-                       , st->id, rd->name
-                       , rd->last_collected_value
-                       , rd->collected_value
-                       , rd->last_calculated_value
-                       , rd->calculated_value
-                       );
-
-               switch(rd->algorithm) {
-                       case RRDDIM_ABSOLUTE:
-                               rd->calculated_value = (calculated_number)rd->collected_value
-                                       * (calculated_number)rd->multiplier
-                                       / (calculated_number)rd->divisor;
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
-                                               CALCULATED_NUMBER_FORMAT " = "
-                                               COLLECTED_NUMBER_FORMAT
-                                               " * " CALCULATED_NUMBER_FORMAT
-                                               " / " CALCULATED_NUMBER_FORMAT
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               , rd->collected_value
-                                               , (calculated_number)rd->multiplier
-                                               , (calculated_number)rd->divisor
-                                               );
-                               break;
-
-                       case RRDDIM_PCENT_OVER_ROW_TOTAL:
-                               if(unlikely(!st->collected_total))
-                                       rd->calculated_value = 0;
-                               else
-                                       // the percentage of the current value
-                                       // over the total of all dimensions
-                                       rd->calculated_value =
-                                             (calculated_number)100
-                                           * (calculated_number)rd->collected_value
-                                           / (calculated_number)st->collected_total;
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
-                                               CALCULATED_NUMBER_FORMAT " = 100"
-                                               " * " COLLECTED_NUMBER_FORMAT
-                                               " / " COLLECTED_NUMBER_FORMAT
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               , rd->collected_value
-                                               , st->collected_total
-                                               );
-                               break;
-
-                       case RRDDIM_INCREMENTAL:
-                               if(unlikely(rd->counter <= 1)) {
-                                       rd->calculated_value = 0;
-                                       continue;
-                               }
-
-                               // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
-                               // to reset the calculation (it will give zero as the calculation for this second)
-                               if(unlikely(rd->last_collected_value > rd->collected_value)) {
-                                       debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
-                                                       , st->name, rd->name
-                                                       , rd->last_collected_value
-                                                       , rd->collected_value);
-                                       if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
-                                       rd->last_collected_value = rd->collected_value;
-                               }
-
-                               rd->calculated_value =
-                                     (calculated_number)(rd->collected_value - rd->last_collected_value)
-                                   * (calculated_number)rd->multiplier
-                                   / (calculated_number)rd->divisor;
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
-                                               CALCULATED_NUMBER_FORMAT " = ("
-                                               COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
-                                               ")"
-                                               " * " CALCULATED_NUMBER_FORMAT
-                                               " / " CALCULATED_NUMBER_FORMAT
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               , rd->collected_value, rd->last_collected_value
-                                               , (calculated_number)rd->multiplier
-                                               , (calculated_number)rd->divisor
-                                               );
-                               break;
-
-                       case RRDDIM_PCENT_OVER_DIFF_TOTAL:
-                               if(unlikely(rd->counter <= 1)) {
-                                       rd->calculated_value = 0;
-                                       continue;
-                               }
-
-                               // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
-                               // to reset the calculation (it will give zero as the calculation for this second)
-                               if(unlikely(rd->last_collected_value > rd->collected_value)) {
-                                       debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
-                                       , st->name, rd->name
-                                       , rd->last_collected_value
-                                       , rd->collected_value);
-                                       if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
-                                       rd->last_collected_value = rd->collected_value;
-                               }
-
-                               // the percentage of the current increment
-                               // over the increment of all dimensions together
-                               if(unlikely(st->collected_total == st->last_collected_total))
-                                       rd->calculated_value = 0;
-                               else
-                                       rd->calculated_value =
-                                                 (calculated_number)100
-                                               * (calculated_number)(rd->collected_value - rd->last_collected_value)
-                                               / (calculated_number)(st->collected_total - st->last_collected_total);
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
-                                               CALCULATED_NUMBER_FORMAT " = 100"
-                                               " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
-                                               " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               , rd->collected_value, rd->last_collected_value
-                                               , st->collected_total, st->last_collected_total
-                                               );
-                               break;
-
-                       default:
-                               // make the default zero, to make sure
-                               // it gets noticed when we add new types
-                               rd->calculated_value = 0;
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC "
-                                               CALCULATED_NUMBER_FORMAT " = 0"
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               );
-                               break;
-               }
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
-                       " last_collected_value = " COLLECTED_NUMBER_FORMAT
-                       " collected_value = " COLLECTED_NUMBER_FORMAT
-                       " last_calculated_value = " CALCULATED_NUMBER_FORMAT
-                       " calculated_value = " CALCULATED_NUMBER_FORMAT
-                       , st->id, rd->name
-                       , rd->last_collected_value
-                       , rd->collected_value
-                       , rd->last_calculated_value
-                       , rd->calculated_value
-                       );
-
-       }
-
-       // at this point we have all the calculated values ready
-       // it is now time to interpolate values on a second boundary
-
-       unsigned long long first_ut = last_ut;
-       long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
-       if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
-
-       for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
+    if(unlikely(netdata_exit)) return 0;
+
+    debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
+
+    RRDDIM *rd, *last;
+    int oldstate, store_this_entry = 1, first_entry = 0;
+    unsigned long long last_ut, now_ut, next_ut, stored_entries = 0;
+
+    if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
+        error("Cannot set pthread cancel state to DISABLE.");
+
+    // a read lock is OK here
+    pthread_rwlock_rdlock(&st->rwlock);
+
+    // enable the chart, if it was disabled
+    if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
+        st->enabled = 1;
+
+    // check if the chart has a long time to be updated
+    if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
+        info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
+        rrdset_reset(st);
+        st->usec_since_last_update = st->update_every * 1000000ULL;
+        first_entry = 1;
+    }
+    if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
+
+    // set last_collected_time
+    if(unlikely(!st->last_collected_time.tv_sec)) {
+        // it is the first entry
+        // set the last_collected_time to now
+        gettimeofday(&st->last_collected_time, NULL);
+
+        // the first entry should not be stored
+        store_this_entry = 0;
+        first_entry = 1;
+
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
+    }
+    else {
+        // it is not the first entry
+        // calculate the proper last_collected_time, using usec_since_last_update
+        unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
+        st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
+        st->last_collected_time.tv_usec = (suseconds_t) (ut % 1000000ULL);
+    }
+
+    // if this set has not been updated in the past
+    // we fake the last_update time to be = now - usec_since_last_update
+    if(unlikely(!st->last_updated.tv_sec)) {
+        // it has never been updated before
+        // set a fake last_updated, in the past using usec_since_last_update
+        unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
+        st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
+        st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
+
+        // the first entry should not be stored
+        store_this_entry = 0;
+        first_entry = 1;
+
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
+    }
+
+    // check if we will re-write the entire data set
+    if(unlikely(usec_dt(&st->last_collected_time, &st->last_updated) > st->update_every * st->entries * 1000000ULL)) {
+        info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Reseting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
+        rrdset_reset(st);
+
+        st->usec_since_last_update = st->update_every * 1000000ULL;
+
+        gettimeofday(&st->last_collected_time, NULL);
+
+        unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
+        st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
+        st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
+
+        // the first entry should not be stored
+        store_this_entry = 0;
+        first_entry = 1;
+    }
+
+    // these are the 3 variables that will help us in interpolation
+    // last_ut = the last time we added a value to the storage
+    //  now_ut = the time the current value is taken at
+    // next_ut = the time of the next interpolation point
+    last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
+    now_ut  = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
+    next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
+
+    if(unlikely(!first_entry && now_ut < next_ut)) {
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
+    }
+
+    if(unlikely(st->debug)) {
+        debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
+        debug(D_RRD_STATS, "%s: now  ut = %0.3Lf (current update time)", st->name, (long double)now_ut/1000000.0);
+        debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
+    }
+
+    if(unlikely(!st->counter_done)) {
+        store_this_entry = 0;
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
+    }
+    st->counter_done++;
+
+    // calculate totals and count the dimensions
+    int dimensions;
+    st->collected_total = 0;
+    for( rd = st->dimensions, dimensions = 0 ; likely(rd) ; rd = rd->next, dimensions++ )
+        if(likely(rd->updated)) st->collected_total += rd->collected_value;
+
+    uint32_t storage_flags = SN_EXISTS;
+
+    // process all dimensions to calculate their values
+    // based on the collected figures only
+    // at this stage we do not interpolate anything
+    for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
+
+        if(unlikely(!rd->updated)) {
+            rd->calculated_value = 0;
+            continue;
+        }
+
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
+            " last_collected_value = " COLLECTED_NUMBER_FORMAT
+            " collected_value = " COLLECTED_NUMBER_FORMAT
+            " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+            " calculated_value = " CALCULATED_NUMBER_FORMAT
+            , st->id, rd->name
+            , rd->last_collected_value
+            , rd->collected_value
+            , rd->last_calculated_value
+            , rd->calculated_value
+            );
+
+        switch(rd->algorithm) {
+            case RRDDIM_ABSOLUTE:
+                rd->calculated_value = (calculated_number)rd->collected_value
+                    * (calculated_number)rd->multiplier
+                    / (calculated_number)rd->divisor;
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
+                        CALCULATED_NUMBER_FORMAT " = "
+                        COLLECTED_NUMBER_FORMAT
+                        " * " CALCULATED_NUMBER_FORMAT
+                        " / " CALCULATED_NUMBER_FORMAT
+                        , st->id, rd->name
+                        , rd->calculated_value
+                        , rd->collected_value
+                        , (calculated_number)rd->multiplier
+                        , (calculated_number)rd->divisor
+                        );
+                break;
+
+            case RRDDIM_PCENT_OVER_ROW_TOTAL:
+                if(unlikely(!st->collected_total))
+                    rd->calculated_value = 0;
+                else
+                    // the percentage of the current value
+                    // over the total of all dimensions
+                    rd->calculated_value =
+                          (calculated_number)100
+                        * (calculated_number)rd->collected_value
+                        / (calculated_number)st->collected_total;
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
+                        CALCULATED_NUMBER_FORMAT " = 100"
+                        " * " COLLECTED_NUMBER_FORMAT
+                        " / " COLLECTED_NUMBER_FORMAT
+                        , st->id, rd->name
+                        , rd->calculated_value
+                        , rd->collected_value
+                        , st->collected_total
+                        );
+                break;
+
+            case RRDDIM_INCREMENTAL:
+                if(unlikely(rd->counter <= 1)) {
+                    rd->calculated_value = 0;
+                    continue;
+                }
+
+                // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+                // to reset the calculation (it will give zero as the calculation for this second)
+                if(unlikely(rd->last_collected_value > rd->collected_value)) {
+                    debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+                            , st->name, rd->name
+                            , rd->last_collected_value
+                            , rd->collected_value);
+                    if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
+                    rd->last_collected_value = rd->collected_value;
+                }
+
+                rd->calculated_value =
+                      (calculated_number)(rd->collected_value - rd->last_collected_value)
+                    * (calculated_number)rd->multiplier
+                    / (calculated_number)rd->divisor;
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
+                        CALCULATED_NUMBER_FORMAT " = ("
+                        COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
+                        ")"
+                        " * " CALCULATED_NUMBER_FORMAT
+                        " / " CALCULATED_NUMBER_FORMAT
+                        , st->id, rd->name
+                        , rd->calculated_value
+                        , rd->collected_value, rd->last_collected_value
+                        , (calculated_number)rd->multiplier
+                        , (calculated_number)rd->divisor
+                        );
+                break;
+
+            case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+                if(unlikely(rd->counter <= 1)) {
+                    rd->calculated_value = 0;
+                    continue;
+                }
+
+                // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
+                // to reset the calculation (it will give zero as the calculation for this second)
+                if(unlikely(rd->last_collected_value > rd->collected_value)) {
+                    debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+                    , st->name, rd->name
+                    , rd->last_collected_value
+                    , rd->collected_value);
+                    if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
+                    rd->last_collected_value = rd->collected_value;
+                }
+
+                // the percentage of the current increment
+                // over the increment of all dimensions together
+                if(unlikely(st->collected_total == st->last_collected_total))
+                    rd->calculated_value = 0;
+                else
+                    rd->calculated_value =
+                          (calculated_number)100
+                        * (calculated_number)(rd->collected_value - rd->last_collected_value)
+                        / (calculated_number)(st->collected_total - st->last_collected_total);
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
+                        CALCULATED_NUMBER_FORMAT " = 100"
+                        " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+                        " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+                        , st->id, rd->name
+                        , rd->calculated_value
+                        , rd->collected_value, rd->last_collected_value
+                        , st->collected_total, st->last_collected_total
+                        );
+                break;
+
+            default:
+                // make the default zero, to make sure
+                // it gets noticed when we add new types
+                rd->calculated_value = 0;
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: CALC "
+                        CALCULATED_NUMBER_FORMAT " = 0"
+                        , st->id, rd->name
+                        , rd->calculated_value
+                        );
+                break;
+        }
+
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
+            " last_collected_value = " COLLECTED_NUMBER_FORMAT
+            " collected_value = " COLLECTED_NUMBER_FORMAT
+            " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+            " calculated_value = " CALCULATED_NUMBER_FORMAT
+            , st->id, rd->name
+            , rd->last_collected_value
+            , rd->collected_value
+            , rd->last_calculated_value
+            , rd->calculated_value
+            );
+
+    }
+
+    // at this point we have all the calculated values ready
+    // it is now time to interpolate values on a second boundary
+
+    unsigned long long first_ut = last_ut;
+    long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
+    if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
+
+    for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
 #ifdef NETDATA_INTERNAL_CHECKS
-               if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_ut = %llu, next_ut = %llu, now_ut = %llu", st->name, first_ut, last_ut, next_ut, now_ut); }
+        if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_ut = %llu, next_ut = %llu, now_ut = %llu", st->name, first_ut, last_ut, next_ut, now_ut); }
 #endif
 
-               if(unlikely(st->debug)) {
-                       debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
-                       debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
-               }
-
-               st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
-               st->last_updated.tv_usec = 0;
-
-               for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
-                       calculated_number new_value;
-
-                       switch(rd->algorithm) {
-                               case RRDDIM_INCREMENTAL:
-                                       new_value = (calculated_number)
-                                               (          rd->calculated_value
-                                                       * (calculated_number)(next_ut - last_ut)
-                                                       / (calculated_number)(now_ut - last_ut)
-                                               );
-
-                                       if(unlikely(st->debug))
-                                               debug(D_RRD_STATS, "%s/%s: CALC2 INC "
-                                                       CALCULATED_NUMBER_FORMAT " = "
-                                                       CALCULATED_NUMBER_FORMAT
-                                                       " * %llu"
-                                                       " / %llu"
-                                                       , st->id, rd->name
-                                                       , new_value
-                                                       , rd->calculated_value
-                                                       , (next_ut - last_ut)
-                                                       , (now_ut - last_ut)
-                                                       );
-
-                                       rd->calculated_value -= new_value;
-                                       new_value += rd->last_calculated_value;
-                                       rd->last_calculated_value = 0;
-                                       new_value /= (calculated_number)st->update_every;
-                                       break;
-
-                               case RRDDIM_ABSOLUTE:
-                               case RRDDIM_PCENT_OVER_ROW_TOTAL:
-                               case RRDDIM_PCENT_OVER_DIFF_TOTAL:
-                               default:
-                                       if(iterations == 1) {
-                                               // this is the last iteration
-                                               // do not interpolate
-                                               // just show the calculated value
-
-                                               new_value = rd->calculated_value;
-                                       }
-                                       else {
-                                               // we have missed an update
-                                               // interpolate in the middle values
-
-                                               new_value = (calculated_number)
-                                                       (       (         (rd->calculated_value - rd->last_calculated_value)
-                                                                       * (calculated_number)(next_ut - first_ut)
-                                                                       / (calculated_number)(now_ut - first_ut)
-                                                               )
-                                                               +  rd->last_calculated_value
-                                                       );
-
-                                               if(unlikely(st->debug))
-                                                       debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
-                                                               CALCULATED_NUMBER_FORMAT " = ((("
-                                                               "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
-                                                               " * %llu"
-                                                               " / %llu) + " CALCULATED_NUMBER_FORMAT
-                                                               , st->id, rd->name
-                                                               , new_value
-                                                               , rd->calculated_value, rd->last_calculated_value
-                                                               , (next_ut - first_ut)
-                                                               , (now_ut - first_ut), rd->last_calculated_value
-                                                               );
-
-                                               // this is wrong
-                                               // it fades the value towards the target
-                                               // while we know the calculated value is different
-                                               // if(likely(next_ut + st->update_every * 1000000ULL > now_ut)) rd->calculated_value = new_value;
-                                       }
-                                       break;
-                       }
-
-                       if(unlikely(!store_this_entry)) {
-                               store_this_entry = 1;
-                               continue;
-                       }
-
-                       if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
-                               rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
-                                               CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
-                                               , st->id, rd->name
-                                               , st->current_entry
-                                               , unpack_storage_number(rd->values[st->current_entry]), new_value
-                                               );
-                       }
-                       else {
-                               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
-                                               , st->id, rd->name
-                                               , st->current_entry
-                                               );
-                               rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
-                       }
-
-                       stored_entries++;
-
-                       if(unlikely(st->debug)) {
-                               calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
-                               calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
-                               calculated_number accuracy = accuracy_loss(t1, t2);
-                               debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
-                                               , st->id, rd->name
-                                               , st->current_entry
-                                               , t2
-                                               , get_storage_number_flags(rd->values[st->current_entry])
-                                               , t1
-                                               , accuracy
-                                               , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
-                                               );
-
-                               rd->collected_volume += t1;
-                               rd->stored_volume += t2;
-                               accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
-                               debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated  = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
-                                               , st->id, rd->name
-                                               , st->current_entry
-                                               , rd->stored_volume
-                                               , rd->collected_volume
-                                               , accuracy
-                                               , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
-                                               );
-
-                       }
-               }
-               // reset the storage flags for the next point, if any;
-               storage_flags = SN_EXISTS;
-
-               st->counter++;
-               st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
-               last_ut = next_ut;
-       }
-
-       // align next interpolation to last collection point
-       if(likely(stored_entries || !store_this_entry)) {
-               st->last_updated.tv_sec = st->last_collected_time.tv_sec;
-               st->last_updated.tv_usec = st->last_collected_time.tv_usec;
-               st->last_collected_total  = st->collected_total;
-       }
-
-       for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
-               if(unlikely(!rd->updated)) continue;
-
-               if(likely(stored_entries || !store_this_entry)) {
-                       if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
-                       rd->last_collected_value = rd->collected_value;
-
-                       if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
-                       rd->last_calculated_value = rd->calculated_value;
-               }
-
-               rd->calculated_value = 0;
-               rd->collected_value = 0;
-               rd->updated = 0;
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
-                       " last_collected_value = " COLLECTED_NUMBER_FORMAT
-                       " collected_value = " COLLECTED_NUMBER_FORMAT
-                       " last_calculated_value = " CALCULATED_NUMBER_FORMAT
-                       " calculated_value = " CALCULATED_NUMBER_FORMAT
-                       , st->id, rd->name
-                       , rd->last_collected_value
-                       , rd->collected_value
-                       , rd->last_calculated_value
-                       , rd->calculated_value
-                       );
-       }
-
-       // ALL DONE ABOUT THE DATA UPDATE
-       // --------------------------------------------------------------------
-
-       // find if there are any obsolete dimensions (not updated recently)
-       if(unlikely(rrd_delete_unupdated_dimensions)) {
-
-               for( rd = st->dimensions; likely(rd) ; rd = rd->next )
-                       if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
-                               break;
-
-               if(unlikely(rd)) {
-                       // there is dimension to free
-                       // upgrade our read lock to a write lock
-                       pthread_rwlock_unlock(&st->rwlock);
-                       pthread_rwlock_wrlock(&st->rwlock);
-
-                       for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
-                               // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
-
-                               if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
-                                       info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
-
-                                       if(unlikely(!last)) {
-                                               st->dimensions = rd->next;
-                                               rd->next = NULL;
-                                               rrddim_free(st, rd);
-                                               rd = st->dimensions;
-                                               continue;
-                                       }
-                                       else {
-                                               last->next = rd->next;
-                                               rd->next = NULL;
-                                               rrddim_free(st, rd);
-                                               rd = last->next;
-                                               continue;
-                                       }
-                               }
-
-                               last = rd;
-                               rd = rd->next;
-                       }
-
-                       if(unlikely(!st->dimensions)) {
-                               info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
-                               st->enabled = 0;
-                       }
-               }
-       }
-
-       pthread_rwlock_unlock(&st->rwlock);
-
-       if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
-               error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
-
-       return(st->usec_since_last_update);
+        if(unlikely(st->debug)) {
+            debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
+            debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
+        }
+
+        st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
+        st->last_updated.tv_usec = 0;
+
+        for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
+            calculated_number new_value;
+
+            switch(rd->algorithm) {
+                case RRDDIM_INCREMENTAL:
+                    new_value = (calculated_number)
+                        (      rd->calculated_value
+                            * (calculated_number)(next_ut - last_ut)
+                            / (calculated_number)(now_ut - last_ut)
+                        );
+
+                    if(unlikely(st->debug))
+                        debug(D_RRD_STATS, "%s/%s: CALC2 INC "
+                            CALCULATED_NUMBER_FORMAT " = "
+                            CALCULATED_NUMBER_FORMAT
+                            " * %llu"
+                            " / %llu"
+                            , st->id, rd->name
+                            , new_value
+                            , rd->calculated_value
+                            , (next_ut - last_ut)
+                            , (now_ut - last_ut)
+                            );
+
+                    rd->calculated_value -= new_value;
+                    new_value += rd->last_calculated_value;
+                    rd->last_calculated_value = 0;
+                    new_value /= (calculated_number)st->update_every;
+                    break;
+
+                case RRDDIM_ABSOLUTE:
+                case RRDDIM_PCENT_OVER_ROW_TOTAL:
+                case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+                default:
+                    if(iterations == 1) {
+                        // this is the last iteration
+                        // do not interpolate
+                        // just show the calculated value
+
+                        new_value = rd->calculated_value;
+                    }
+                    else {
+                        // we have missed an update
+                        // interpolate in the middle values
+
+                        new_value = (calculated_number)
+                            (   (     (rd->calculated_value - rd->last_calculated_value)
+                                    * (calculated_number)(next_ut - first_ut)
+                                    / (calculated_number)(now_ut - first_ut)
+                                )
+                                +  rd->last_calculated_value
+                            );
+
+                        if(unlikely(st->debug))
+                            debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
+                                CALCULATED_NUMBER_FORMAT " = ((("
+                                "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
+                                " * %llu"
+                                " / %llu) + " CALCULATED_NUMBER_FORMAT
+                                , st->id, rd->name
+                                , new_value
+                                , rd->calculated_value, rd->last_calculated_value
+                                , (next_ut - first_ut)
+                                , (now_ut - first_ut), rd->last_calculated_value
+                                );
+
+                        // this is wrong
+                        // it fades the value towards the target
+                        // while we know the calculated value is different
+                        // if(likely(next_ut + st->update_every * 1000000ULL > now_ut)) rd->calculated_value = new_value;
+                    }
+                    break;
+            }
+
+            if(unlikely(!store_this_entry)) {
+                store_this_entry = 1;
+                continue;
+            }
+
+            if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
+                rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
+
+                if(unlikely(st->debug))
+                    debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
+                        CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
+                        , st->id, rd->name
+                        , st->current_entry
+                        , unpack_storage_number(rd->values[st->current_entry]), new_value
+                        );
+            }
+            else {
+                if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
+                        , st->id, rd->name
+                        , st->current_entry
+                        );
+                rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
+            }
+
+            stored_entries++;
+
+            if(unlikely(st->debug)) {
+                calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
+                calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
+                calculated_number accuracy = accuracy_loss(t1, t2);
+                debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
+                        , st->id, rd->name
+                        , st->current_entry
+                        , t2
+                        , get_storage_number_flags(rd->values[st->current_entry])
+                        , t1
+                        , accuracy
+                        , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+                        );
+
+                rd->collected_volume += t1;
+                rd->stored_volume += t2;
+                accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
+                debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated  = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
+                        , st->id, rd->name
+                        , st->current_entry
+                        , rd->stored_volume
+                        , rd->collected_volume
+                        , accuracy
+                        , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
+                        );
+
+            }
+        }
+        // reset the storage flags for the next point, if any;
+        storage_flags = SN_EXISTS;
+
+        st->counter++;
+        st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
+        last_ut = next_ut;
+    }
+
+    // align next interpolation to last collection point
+    if(likely(stored_entries || !store_this_entry)) {
+        st->last_updated.tv_sec = st->last_collected_time.tv_sec;
+        st->last_updated.tv_usec = st->last_collected_time.tv_usec;
+        st->last_collected_total  = st->collected_total;
+    }
+
+    for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
+        if(unlikely(!rd->updated)) continue;
+
+        if(likely(stored_entries || !store_this_entry)) {
+            if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
+            rd->last_collected_value = rd->collected_value;
+
+            if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
+            rd->last_calculated_value = rd->calculated_value;
+        }
+
+        rd->calculated_value = 0;
+        rd->collected_value = 0;
+        rd->updated = 0;
+
+        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
+            " last_collected_value = " COLLECTED_NUMBER_FORMAT
+            " collected_value = " COLLECTED_NUMBER_FORMAT
+            " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+            " calculated_value = " CALCULATED_NUMBER_FORMAT
+            , st->id, rd->name
+            , rd->last_collected_value
+            , rd->collected_value
+            , rd->last_calculated_value
+            , rd->calculated_value
+            );
+    }
+
+    // ALL DONE ABOUT THE DATA UPDATE
+    // --------------------------------------------------------------------
+
+    // find if there are any obsolete dimensions (not updated recently)
+    if(unlikely(rrd_delete_unupdated_dimensions)) {
+
+        for( rd = st->dimensions; likely(rd) ; rd = rd->next )
+            if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
+                break;
+
+        if(unlikely(rd)) {
+            // there is dimension to free
+            // upgrade our read lock to a write lock
+            pthread_rwlock_unlock(&st->rwlock);
+            pthread_rwlock_wrlock(&st->rwlock);
+
+            for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
+                // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
+
+                if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
+                    info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
+
+                    if(unlikely(!last)) {
+                        st->dimensions = rd->next;
+                        rd->next = NULL;
+                        rrddim_free(st, rd);
+                        rd = st->dimensions;
+                        continue;
+                    }
+                    else {
+                        last->next = rd->next;
+                        rd->next = NULL;
+                        rrddim_free(st, rd);
+                        rd = last->next;
+                        continue;
+                    }
+                }
+
+                last = rd;
+                rd = rd->next;
+            }
+
+            if(unlikely(!st->dimensions)) {
+                info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
+                st->enabled = 0;
+            }
+        }
+    }
+
+    pthread_rwlock_unlock(&st->rwlock);
+
+    if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
+        error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
+
+    return(st->usec_since_last_update);
 }
index e05c4ed493d4d68bb0a4f66dbf7c7c779a0434f5..d0e3584fe67857a0258825c0936b9580cd4c9bbd 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -15,8 +15,8 @@ extern int rrd_delete_unupdated_dimensions;
 
 #define RRD_ID_LENGTH_MAX 1024
 
-#define RRDSET_MAGIC           "NETDATA RRD SET FILE V018"
-#define RRDDIMENSION_MAGIC     "NETDATA RRD DIMENSION FILE V018"
+#define RRDSET_MAGIC        "NETDATA RRD SET FILE V018"
+#define RRDDIMENSION_MAGIC  "NETDATA RRD DIMENSION FILE V018"
 
 typedef long long total_number;
 #define TOTAL_NUMBER_FORMAT "%lld"
@@ -28,8 +28,8 @@ typedef long long total_number;
 #define RRDSET_TYPE_AREA_NAME "area"
 #define RRDSET_TYPE_STACKED_NAME "stacked"
 
-#define RRDSET_TYPE_LINE       0
-#define RRDSET_TYPE_AREA       1
+#define RRDSET_TYPE_LINE    0
+#define RRDSET_TYPE_AREA    1
 #define RRDSET_TYPE_STACKED 2
 
 int rrdset_type_id(const char *name);
@@ -56,15 +56,15 @@ extern int rrd_memory_mode_id(const char *name);
 // ----------------------------------------------------------------------------
 // algorithms types
 
-#define RRDDIM_ABSOLUTE_NAME                           "absolute"
-#define RRDDIM_INCREMENTAL_NAME                        "incremental"
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME      "percentage-of-incremental-row"
-#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME       "percentage-of-absolute-row"
+#define RRDDIM_ABSOLUTE_NAME                "absolute"
+#define RRDDIM_INCREMENTAL_NAME             "incremental"
+#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME   "percentage-of-incremental-row"
+#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME    "percentage-of-absolute-row"
 
-#define RRDDIM_ABSOLUTE                                        0
-#define RRDDIM_INCREMENTAL                             1
-#define RRDDIM_PCENT_OVER_DIFF_TOTAL   2
-#define RRDDIM_PCENT_OVER_ROW_TOTAL            3
+#define RRDDIM_ABSOLUTE                 0
+#define RRDDIM_INCREMENTAL              1
+#define RRDDIM_PCENT_OVER_DIFF_TOTAL    2
+#define RRDDIM_PCENT_OVER_ROW_TOTAL     3
 
 extern int rrddim_algorithm_id(const char *name);
 extern const char *rrddim_algorithm_name(int chart_type);
@@ -94,83 +94,83 @@ typedef struct rrdcontext RRDCONTEXT;
 // RRD DIMENSION
 
 struct rrddim {
-       // ------------------------------------------------------------------------
-       // binary indexing structures
+    // ------------------------------------------------------------------------
+    // binary indexing structures
 
-       avl avl;                                                                                // the binary index - this has to be first member!
+    avl avl;                                        // the binary index - this has to be first member!
 
-       // ------------------------------------------------------------------------
-       // the dimension definition
+    // ------------------------------------------------------------------------
+    // the dimension definition
 
-       char id[RRD_ID_LENGTH_MAX + 1];                                 // the id of this dimension (for internal identification)
+    char id[RRD_ID_LENGTH_MAX + 1];                 // the id of this dimension (for internal identification)
 
-       const char *name;                                                               // the name of this dimension (as presented to user)
-                                                                                                       // this is a pointer to the config structure
-                                                                                                       // since the config always has a higher priority
-                                                                                                       // (the user overwrites the name of the charts)
+    const char *name;                               // the name of this dimension (as presented to user)
+                                                    // this is a pointer to the config structure
+                                                    // since the config always has a higher priority
+                                                    // (the user overwrites the name of the charts)
 
-       int algorithm;                                                                  // the algorithm that is applied to add new collected values
-       long multiplier;                                                                // the multiplier of the collected values
-       long divisor;                                                                   // the divider of the collected values
+    int algorithm;                                  // the algorithm that is applied to add new collected values
+    long multiplier;                                // the multiplier of the collected values
+    long divisor;                                   // the divider of the collected values
 
-       int mapped;                                                                             // if set to non zero, this dimension is mapped to a file
+    int mapped;                                     // if set to non zero, this dimension is mapped to a file
 
-       // ------------------------------------------------------------------------
-       // members for temporary data we need for calculations
+    // ------------------------------------------------------------------------
+    // members for temporary data we need for calculations
 
-       uint32_t hash;                                                                  // a simple hash of the id, to speed up searching / indexing
-                                                                                                       // instead of strcmp() every item in the binary index
-                                                                                                       // we first compare the hashes
+    uint32_t hash;                                  // a simple hash of the id, to speed up searching / indexing
+                                                    // instead of strcmp() every item in the binary index
+                                                    // we first compare the hashes
 
-       // FIXME
-       // we need the hash_name too!
+    // FIXME
+    // we need the hash_name too!
 
-       uint32_t flags;
+    uint32_t flags;
 
-       char cache_filename[FILENAME_MAX+1];                    // the filename we load/save from/to this set
+    char cache_filename[FILENAME_MAX+1];            // the filename we load/save from/to this set
 
-       unsigned long counter;                                                  // the number of times we added values to this rrdim
+    unsigned long counter;                          // the number of times we added values to this rrdim
 
-       int updated;                                                                    // set to 0 after each calculation, to 1 after each collected value
-                                                                                                       // we use this to detect that a dimension is not updated
+    int updated;                                    // set to 0 after each calculation, to 1 after each collected value
+                                                    // we use this to detect that a dimension is not updated
 
-       struct timeval last_collected_time;                             // when was this dimension last updated
-                                                                                                       // this is actual date time we updated the last_collected_value
-                                                                                                       // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET
+    struct timeval last_collected_time;             // when was this dimension last updated
+                                                    // this is actual date time we updated the last_collected_value
+                                                    // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET
 
-       calculated_number calculated_value;                             // the current calculated value, after applying the algorithm
-       calculated_number last_calculated_value;                // the last calculated value
+    calculated_number calculated_value;             // the current calculated value, after applying the algorithm
+    calculated_number last_calculated_value;        // the last calculated value
 
-       collected_number collected_value;                               // the current value, as collected
-       collected_number last_collected_value;                  // the last value that was collected
+    collected_number collected_value;               // the current value, as collected
+    collected_number last_collected_value;          // the last value that was collected
 
-       // the *_volume members are used to calculate the accuracy of the rounding done by the
-       // storage number - they are printed to debug.log when debug is enabled for a set.
-       calculated_number collected_volume;                             // the sum of all collected values so far
-       calculated_number stored_volume;                                // the sum of all stored values so far
+    // the *_volume members are used to calculate the accuracy of the rounding done by the
+    // storage number - they are printed to debug.log when debug is enabled for a set.
+    calculated_number collected_volume;             // the sum of all collected values so far
+    calculated_number stored_volume;                // the sum of all stored values so far
 
-       struct rrddim *next;                                                    // linking of dimensions within the same data set
+    struct rrddim *next;                            // linking of dimensions within the same data set
     struct rrdset *rrdset;
 
-       // ------------------------------------------------------------------------
-       // members for checking the data when loading from disk
+    // ------------------------------------------------------------------------
+    // members for checking the data when loading from disk
 
-       long entries;                                                                   // how many entries this dimension has in ram
-                                                                                                       // this is the same to the entries of the data set
-                                                                                                       // we set it here, to check the data when we load it from disk.
+    long entries;                                   // how many entries this dimension has in ram
+                                                    // this is the same to the entries of the data set
+                                                    // we set it here, to check the data when we load it from disk.
 
-       int update_every;                                                               // every how many seconds is this updated
+    int update_every;                               // every how many seconds is this updated
 
-       unsigned long memsize;                                                  // the memory allocated for this dimension
+    unsigned long memsize;                          // the memory allocated for this dimension
 
-       char magic[sizeof(RRDDIMENSION_MAGIC) + 1];             // a string to be saved, used to identify our data file
+    char magic[sizeof(RRDDIMENSION_MAGIC) + 1];     // a string to be saved, used to identify our data file
 
     struct rrddimvar *variables;
 
-       // ------------------------------------------------------------------------
-       // the values stored in this dimension, using our floating point numbers
+    // ------------------------------------------------------------------------
+    // the values stored in this dimension, using our floating point numbers
 
-       storage_number values[];                                                // the array of values - THIS HAS TO BE THE LAST MEMBER
+    storage_number values[];                        // the array of values - THIS HAS TO BE THE LAST MEMBER
 };
 typedef struct rrddim RRDDIM;
 
@@ -179,99 +179,99 @@ typedef struct rrddim RRDDIM;
 // RRDSET
 
 struct rrdset {
-       // ------------------------------------------------------------------------
-       // binary indexing structures
+    // ------------------------------------------------------------------------
+    // binary indexing structures
 
-       avl avl;                                                                                // the index, with key the id - this has to be first!
-       avl avlname;                                                                    // the index, with key the name
+    avl avl;                                        // the index, with key the id - this has to be first!
+    avl avlname;                                    // the index, with key the name
 
-       // ------------------------------------------------------------------------
-       // the set configuration
+    // ------------------------------------------------------------------------
+    // the set configuration
 
-       char id[RRD_ID_LENGTH_MAX + 1];                                 // id of the data set
+    char id[RRD_ID_LENGTH_MAX + 1];                 // id of the data set
 
-       const char *name;                                                               // the name of this dimension (as presented to user)
-                                                                                                       // this is a pointer to the config structure
-                                                                                                       // since the config always has a higher priority
-                                                                                                       // (the user overwrites the name of the charts)
+    const char *name;                               // the name of this dimension (as presented to user)
+                                                    // this is a pointer to the config structure
+                                                    // since the config always has a higher priority
+                                                    // (the user overwrites the name of the charts)
 
-       char *type;                                                                             // the type of graph RRD_TYPE_* (a category, for determining graphing options)
-       char *family;                                                                   // grouping sets under the same family
-       char *context;                                                                  // the template of this data set
-       char *title;                                                                    // title shown to user
-       char *units;                                                                    // units of measurement
+    char *type;                                     // the type of graph RRD_TYPE_* (a category, for determining graphing options)
+    char *family;                                   // grouping sets under the same family
+    char *context;                                  // the template of this data set
+    char *title;                                    // title shown to user
+    char *units;                                    // units of measurement
 
-       int chart_type;
+    int chart_type;
 
-       int update_every;                                                               // every how many seconds is this updated?
+    int update_every;                               // every how many seconds is this updated?
 
-       long entries;                                                                   // total number of entries in the data set
+    long entries;                                   // total number of entries in the data set
 
-       long current_entry;                                                             // the entry that is currently being updated
-                                                                                                       // it goes around in a round-robin fashion
+    long current_entry;                             // the entry that is currently being updated
+                                                    // it goes around in a round-robin fashion
 
-       int enabled;
+    int enabled;
 
-       int gap_when_lost_iterations_above;                             // after how many lost iterations a gap should be stored
-                                                                                                       // netdata will interpolate values for gaps lower than this
+    int gap_when_lost_iterations_above;             // after how many lost iterations a gap should be stored
+                                                    // netdata will interpolate values for gaps lower than this
 
-       long priority;
+    long priority;
 
-       int isdetail;                                                                   // if set, the data set should be considered as a detail of another
-                                                                                                       // (the master data set should be the one that has the same family and is not detail)
+    int isdetail;                                   // if set, the data set should be considered as a detail of another
+                                                    // (the master data set should be the one that has the same family and is not detail)
 
-       // ------------------------------------------------------------------------
-       // members for temporary data we need for calculations
+    // ------------------------------------------------------------------------
+    // members for temporary data we need for calculations
 
-       int mapped;                                                                             // if set to 1, this is memory mapped
+    int mapped;                                     // if set to 1, this is memory mapped
 
-       int debug;
+    int debug;
 
-       char *cache_dir;                                                                // the directory to store dimensions
-       char cache_filename[FILENAME_MAX+1];                    // the filename to store this set
+    char *cache_dir;                                // the directory to store dimensions
+    char cache_filename[FILENAME_MAX+1];            // the filename to store this set
 
-       pthread_rwlock_t rwlock;
+    pthread_rwlock_t rwlock;
 
-       unsigned long counter;                                                  // the number of times we added values to this rrd
-       unsigned long counter_done;                                             // the number of times we added values to this rrd
+    unsigned long counter;                          // the number of times we added values to this rrd
+    unsigned long counter_done;                     // the number of times we added values to this rrd
 
-       uint32_t hash;                                                                  // a simple hash on the id, to speed up searching
-                                                                                                       // we first compare hashes, and only if the hashes are equal we do string comparisons
+    uint32_t hash;                                  // a simple hash on the id, to speed up searching
+                                                    // we first compare hashes, and only if the hashes are equal we do string comparisons
 
-       uint32_t hash_name;                                                             // a simple hash on the name
+    uint32_t hash_name;                             // a simple hash on the name
 
-       unsigned long long usec_since_last_update;              // the time in microseconds since the last collection of data
+    unsigned long long usec_since_last_update;      // the time in microseconds since the last collection of data
 
-       struct timeval last_updated;                                    // when this data set was last updated (updated every time the rrd_stats_done() function)
-       struct timeval last_collected_time;                             // when did this data set last collected values
+    struct timeval last_updated;                    // when this data set was last updated (updated every time the rrd_stats_done() function)
+    struct timeval last_collected_time;             // when did this data set last collected values
 
-       total_number collected_total;                                   // used internally to calculate percentages
-       total_number last_collected_total;                              // used internally to calculate percentages
+    total_number collected_total;                   // used internally to calculate percentages
+    total_number last_collected_total;              // used internally to calculate percentages
 
     RRDCONTEXT *rrdcontext;
     struct rrdhost *rrdhost;
 
-       struct rrdset *next;                                                    // linking of rrdsets
+    struct rrdset *next;                            // linking of rrdsets
 
-       // ------------------------------------------------------------------------
-       // local variables
+    // ------------------------------------------------------------------------
+    // local variables
 
-       avl_tree_lock variables_root_index;
-       RRDSETVAR *variables;
-       RRDCALC *calculations;
+    avl_tree_lock variables_root_index;
+    RRDSETVAR *variables;
+    RRDCALC *calculations;
 
-       // ------------------------------------------------------------------------
-       // members for checking the data when loading from disk
+    // ------------------------------------------------------------------------
+    // members for checking the data when loading from disk
 
-       unsigned long memsize;                                                  // how much mem we have allocated for this (without dimensions)
+    unsigned long memsize;                          // how much mem we have allocated for this (without dimensions)
 
-       char magic[sizeof(RRDSET_MAGIC) + 1];                   // our magic
+    char magic[sizeof(RRDSET_MAGIC) + 1];           // our magic
 
-       // ------------------------------------------------------------------------
-       // the dimensions
+    // ------------------------------------------------------------------------
+    // the dimensions
 
-       avl_tree_lock dimensions_index;                                         // the root of the dimensions index
-       RRDDIM *dimensions;                                                             // the actual data for every dimension
+    avl_tree_lock dimensions_index;                     // the root of the dimensions index
+    RRDDIM *dimensions;                             // the actual data for every dimension
 
 };
 typedef struct rrdset RRDSET;
@@ -293,10 +293,10 @@ struct rrdhost {
     avl_tree_lock rrdcontext_root_index;
     avl_tree_lock variables_root_index;
 
-       // all RRDCALCs are primarily allocated and linked here
-       // RRDCALCs may be linked to charts at any point
-       // (charts may or may not exist when these are loaded)
-       RRDCALC *calculations;
+    // all RRDCALCs are primarily allocated and linked here
+    // RRDCALCs may be linked to charts at any point
+    // (charts may or may not exist when these are loaded)
+    RRDCALC *calculations;
 
     // all variable references are linked here
     // RRDVARs may be free'd, so every time this happens
@@ -324,15 +324,15 @@ extern char *rrdset_cache_dir(const char *id);
 extern void rrdset_reset(RRDSET *st);
 
 extern RRDSET *rrdset_create(const char *type
-               , const char *id
-               , const char *name
-               , const char *family
-               , const char *context
-               , const char *title
-               , const char *units
-               , long priority
-               , int update_every
-               , int chart_type);
+        , const char *id
+        , const char *name
+        , const char *family
+        , const char *context
+        , const char *title
+        , const char *units
+        , long priority
+        , int update_every
+        , int chart_type);
 
 extern void rrdset_free_all(void);
 extern void rrdset_save_all(void);
@@ -365,20 +365,20 @@ extern unsigned long long rrdset_done(RRDSET *st);
 // get the slot of the round robin database, for the given timestamp (t)
 // it always returns a valid slot, although may not be for the time requested if the time is outside the round robin database
 #define rrdset_time2slot(st, t) ( \
-               (  (time_t)(t) >= rrdset_last_entry_t(st))  ? ( rrdset_last_slot(st) ) : \
-               ( ((time_t)(t) <= rrdset_first_entry_t(st)) ?   rrdset_first_slot(st) : \
-               ( (rrdset_last_slot(st) >= (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) ? \
-                 (rrdset_last_slot(st) -  (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) : \
-                 (rrdset_last_slot(st) -  (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) + (unsigned long)(st)->entries ) \
-               )))
+        (  (time_t)(t) >= rrdset_last_entry_t(st))  ? ( rrdset_last_slot(st) ) : \
+        ( ((time_t)(t) <= rrdset_first_entry_t(st)) ?   rrdset_first_slot(st) : \
+        ( (rrdset_last_slot(st) >= (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) ? \
+          (rrdset_last_slot(st) -  (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) : \
+          (rrdset_last_slot(st) -  (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) + (unsigned long)(st)->entries ) \
+        )))
 
 // get the timestamp of a specific slot in the round robin database
 #define rrdset_slot2time(st, slot) ( rrdset_last_entry_t(st) - \
-               ((unsigned long)(st)->update_every * ( \
-                               ( (unsigned long)(slot) > rrdset_last_slot(st)) ? \
-                               ( (rrdset_last_slot(st) - (unsigned long)(slot) + (unsigned long)(st)->entries) ) : \
-                               ( (rrdset_last_slot(st) - (unsigned long)(slot)) )) \
-               ))
+        ((unsigned long)(st)->update_every * ( \
+                ( (unsigned long)(slot) > rrdset_last_slot(st)) ? \
+                ( (rrdset_last_slot(st) - (unsigned long)(slot) + (unsigned long)(st)->entries) ) : \
+                ( (rrdset_last_slot(st) - (unsigned long)(slot)) )) \
+        ))
 
 // ----------------------------------------------------------------------------
 // RRD DIMENSION functions
index 7958bca2ea2dd8cf6b4fc9a18588b89cf0350ed5..bbf48a2965c44e06bb0fa34a779a5c59439fa2c1 100644 (file)
@@ -5,207 +5,207 @@ char *hostname = "unknown";
 
 void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
 {
-       pthread_rwlock_rdlock(&st->rwlock);
-
-       buffer_sprintf(wb,
-               "\t\t{\n"
-               "\t\t\t\"id\": \"%s\",\n"
-               "\t\t\t\"name\": \"%s\",\n"
-               "\t\t\t\"type\": \"%s\",\n"
-               "\t\t\t\"family\": \"%s\",\n"
-               "\t\t\t\"context\": \"%s\",\n"
-               "\t\t\t\"title\": \"%s\",\n"
-               "\t\t\t\"priority\": %ld,\n"
-               "\t\t\t\"enabled\": %s,\n"
-               "\t\t\t\"units\": \"%s\",\n"
-               "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
-               "\t\t\t\"chart_type\": \"%s\",\n"
-               "\t\t\t\"duration\": %ld,\n"
-               "\t\t\t\"first_entry\": %ld,\n"
-               "\t\t\t\"last_entry\": %ld,\n"
-               "\t\t\t\"update_every\": %d,\n"
-               "\t\t\t\"dimensions\": {\n"
-               , st->id
-               , st->name
-               , st->type
-               , st->family
-               , st->context
-               , st->title
-               , st->priority
-               , st->enabled?"true":"false"
-               , st->units
-               , st->name
-               , rrdset_type_name(st->chart_type)
-               , st->entries * st->update_every
-               , rrdset_first_entry_t(st)
-               , rrdset_last_entry_t(st)
-               , st->update_every
-               );
-
-       unsigned long memory = st->memsize;
-
-       int c = 0;
-       RRDDIM *rd;
-       for(rd = st->dimensions; rd ; rd = rd->next) {
-               if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
-
-               memory += rd->memsize;
-
-               buffer_sprintf(wb,
-                       "%s"
-                       "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
-                       , c?",\n":""
-                       , rd->id
-                       , rd->name
-                       );
-
-               c++;
-       }
-
-       buffer_sprintf(wb,
-               "\n\t\t\t}\n"
-               "\t\t}"
-               );
-
-       pthread_rwlock_unlock(&st->rwlock);
+    pthread_rwlock_rdlock(&st->rwlock);
+
+    buffer_sprintf(wb,
+        "\t\t{\n"
+        "\t\t\t\"id\": \"%s\",\n"
+        "\t\t\t\"name\": \"%s\",\n"
+        "\t\t\t\"type\": \"%s\",\n"
+        "\t\t\t\"family\": \"%s\",\n"
+        "\t\t\t\"context\": \"%s\",\n"
+        "\t\t\t\"title\": \"%s\",\n"
+        "\t\t\t\"priority\": %ld,\n"
+        "\t\t\t\"enabled\": %s,\n"
+        "\t\t\t\"units\": \"%s\",\n"
+        "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
+        "\t\t\t\"chart_type\": \"%s\",\n"
+        "\t\t\t\"duration\": %ld,\n"
+        "\t\t\t\"first_entry\": %ld,\n"
+        "\t\t\t\"last_entry\": %ld,\n"
+        "\t\t\t\"update_every\": %d,\n"
+        "\t\t\t\"dimensions\": {\n"
+        , st->id
+        , st->name
+        , st->type
+        , st->family
+        , st->context
+        , st->title
+        , st->priority
+        , st->enabled?"true":"false"
+        , st->units
+        , st->name
+        , rrdset_type_name(st->chart_type)
+        , st->entries * st->update_every
+        , rrdset_first_entry_t(st)
+        , rrdset_last_entry_t(st)
+        , st->update_every
+        );
+
+    unsigned long memory = st->memsize;
+
+    int c = 0;
+    RRDDIM *rd;
+    for(rd = st->dimensions; rd ; rd = rd->next) {
+        if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
+
+        memory += rd->memsize;
+
+        buffer_sprintf(wb,
+            "%s"
+            "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
+            , c?",\n":""
+            , rd->id
+            , rd->name
+            );
+
+        c++;
+    }
+
+    buffer_sprintf(wb,
+        "\n\t\t\t}\n"
+        "\t\t}"
+        );
+
+    pthread_rwlock_unlock(&st->rwlock);
 }
 
 void rrd_stats_api_v1_charts(BUFFER *wb)
 {
-       long c;
-       RRDSET *st;
-
-       buffer_sprintf(wb, "{\n"
-                  "\t\"hostname\": \"%s\""
-               ",\n\t\"update_every\": %d"
-               ",\n\t\"history\": %d"
-               ",\n\t\"charts\": {"
-               , hostname
-               , rrd_update_every
-               , rrd_default_history_entries
-               );
-
-       pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
-       for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
-               if(st->enabled && st->dimensions) {
-                       if(c) buffer_strcat(wb, ",");
-                       buffer_strcat(wb, "\n\t\t\"");
-                       buffer_strcat(wb, st->id);
-                       buffer_strcat(wb, "\": ");
-                       rrd_stats_api_v1_chart(st, wb);
-                       c++;
-               }
-       }
-       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
-
-       buffer_strcat(wb, "\n\t}\n}\n");
+    long c;
+    RRDSET *st;
+
+    buffer_sprintf(wb, "{\n"
+           "\t\"hostname\": \"%s\""
+        ",\n\t\"update_every\": %d"
+        ",\n\t\"history\": %d"
+        ",\n\t\"charts\": {"
+        , hostname
+        , rrd_update_every
+        , rrd_default_history_entries
+        );
+
+    pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+    for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
+        if(st->enabled && st->dimensions) {
+            if(c) buffer_strcat(wb, ",");
+            buffer_strcat(wb, "\n\t\t\"");
+            buffer_strcat(wb, st->id);
+            buffer_strcat(wb, "\": ");
+            rrd_stats_api_v1_chart(st, wb);
+            c++;
+        }
+    }
+    pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+
+    buffer_strcat(wb, "\n\t}\n}\n");
 }
 
 
 unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
 {
-       time_t now = time(NULL);
-
-       pthread_rwlock_rdlock(&st->rwlock);
-
-       buffer_sprintf(wb,
-               "\t\t{\n"
-               "\t\t\t\"id\": \"%s\",\n"
-               "\t\t\t\"name\": \"%s\",\n"
-               "\t\t\t\"type\": \"%s\",\n"
-               "\t\t\t\"family\": \"%s\",\n"
-               "\t\t\t\"context\": \"%s\",\n"
-               "\t\t\t\"title\": \"%s\",\n"
-               "\t\t\t\"priority\": %ld,\n"
-               "\t\t\t\"enabled\": %d,\n"
-               "\t\t\t\"units\": \"%s\",\n"
-               "\t\t\t\"url\": \"/data/%s/%s\",\n"
-               "\t\t\t\"chart_type\": \"%s\",\n"
-               "\t\t\t\"counter\": %lu,\n"
-               "\t\t\t\"entries\": %ld,\n"
-               "\t\t\t\"first_entry_t\": %ld,\n"
-               "\t\t\t\"last_entry\": %lu,\n"
-               "\t\t\t\"last_entry_t\": %ld,\n"
-               "\t\t\t\"last_entry_secs_ago\": %ld,\n"
-               "\t\t\t\"update_every\": %d,\n"
-               "\t\t\t\"isdetail\": %d,\n"
-               "\t\t\t\"usec_since_last_update\": %llu,\n"
-               "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
-               "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
-               "\t\t\t\"dimensions\": [\n"
-               , st->id
-               , st->name
-               , st->type
-               , st->family
-               , st->context
-               , st->title
-               , st->priority
-               , st->enabled
-               , st->units
-               , st->name, options?options:""
-               , rrdset_type_name(st->chart_type)
-               , st->counter
-               , st->entries
-               , rrdset_first_entry_t(st)
-               , rrdset_last_slot(st)
-               , rrdset_last_entry_t(st)
-               , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
-               , st->update_every
-               , st->isdetail
-               , st->usec_since_last_update
-               , st->collected_total
-               , st->last_collected_total
-               );
-
-       unsigned long memory = st->memsize;
-
-       RRDDIM *rd;
-       for(rd = st->dimensions; rd ; rd = rd->next) {
-
-               memory += rd->memsize;
-
-               buffer_sprintf(wb,
-                       "\t\t\t\t{\n"
-                       "\t\t\t\t\t\"id\": \"%s\",\n"
-                       "\t\t\t\t\t\"name\": \"%s\",\n"
-                       "\t\t\t\t\t\"entries\": %ld,\n"
-                       "\t\t\t\t\t\"isHidden\": %d,\n"
-                       "\t\t\t\t\t\"algorithm\": \"%s\",\n"
-                       "\t\t\t\t\t\"multiplier\": %ld,\n"
-                       "\t\t\t\t\t\"divisor\": %ld,\n"
-                       "\t\t\t\t\t\"last_entry_t\": %ld,\n"
-                       "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
-                       "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
-                       "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
-                       "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
-                       "\t\t\t\t\t\"memory\": %lu\n"
-                       "\t\t\t\t}%s\n"
-                       , rd->id
-                       , rd->name
-                       , rd->entries
-                       , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
-                       , rrddim_algorithm_name(rd->algorithm)
-                       , rd->multiplier
-                       , rd->divisor
-                       , rd->last_collected_time.tv_sec
-                       , rd->collected_value
-                       , rd->calculated_value
-                       , rd->last_collected_value
-                       , rd->last_calculated_value
-                       , rd->memsize
-                       , rd->next?",":""
-                       );
-       }
-
-       buffer_sprintf(wb,
-               "\t\t\t],\n"
-               "\t\t\t\"memory\" : %lu\n"
-               "\t\t}"
-               , memory
-               );
-
-       pthread_rwlock_unlock(&st->rwlock);
-       return memory;
+    time_t now = time(NULL);
+
+    pthread_rwlock_rdlock(&st->rwlock);
+
+    buffer_sprintf(wb,
+        "\t\t{\n"
+        "\t\t\t\"id\": \"%s\",\n"
+        "\t\t\t\"name\": \"%s\",\n"
+        "\t\t\t\"type\": \"%s\",\n"
+        "\t\t\t\"family\": \"%s\",\n"
+        "\t\t\t\"context\": \"%s\",\n"
+        "\t\t\t\"title\": \"%s\",\n"
+        "\t\t\t\"priority\": %ld,\n"
+        "\t\t\t\"enabled\": %d,\n"
+        "\t\t\t\"units\": \"%s\",\n"
+        "\t\t\t\"url\": \"/data/%s/%s\",\n"
+        "\t\t\t\"chart_type\": \"%s\",\n"
+        "\t\t\t\"counter\": %lu,\n"
+        "\t\t\t\"entries\": %ld,\n"
+        "\t\t\t\"first_entry_t\": %ld,\n"
+        "\t\t\t\"last_entry\": %lu,\n"
+        "\t\t\t\"last_entry_t\": %ld,\n"
+        "\t\t\t\"last_entry_secs_ago\": %ld,\n"
+        "\t\t\t\"update_every\": %d,\n"
+        "\t\t\t\"isdetail\": %d,\n"
+        "\t\t\t\"usec_since_last_update\": %llu,\n"
+        "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+        "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
+        "\t\t\t\"dimensions\": [\n"
+        , st->id
+        , st->name
+        , st->type
+        , st->family
+        , st->context
+        , st->title
+        , st->priority
+        , st->enabled
+        , st->units
+        , st->name, options?options:""
+        , rrdset_type_name(st->chart_type)
+        , st->counter
+        , st->entries
+        , rrdset_first_entry_t(st)
+        , rrdset_last_slot(st)
+        , rrdset_last_entry_t(st)
+        , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
+        , st->update_every
+        , st->isdetail
+        , st->usec_since_last_update
+        , st->collected_total
+        , st->last_collected_total
+        );
+
+    unsigned long memory = st->memsize;
+
+    RRDDIM *rd;
+    for(rd = st->dimensions; rd ; rd = rd->next) {
+
+        memory += rd->memsize;
+
+        buffer_sprintf(wb,
+            "\t\t\t\t{\n"
+            "\t\t\t\t\t\"id\": \"%s\",\n"
+            "\t\t\t\t\t\"name\": \"%s\",\n"
+            "\t\t\t\t\t\"entries\": %ld,\n"
+            "\t\t\t\t\t\"isHidden\": %d,\n"
+            "\t\t\t\t\t\"algorithm\": \"%s\",\n"
+            "\t\t\t\t\t\"multiplier\": %ld,\n"
+            "\t\t\t\t\t\"divisor\": %ld,\n"
+            "\t\t\t\t\t\"last_entry_t\": %ld,\n"
+            "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+            "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+            "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
+            "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
+            "\t\t\t\t\t\"memory\": %lu\n"
+            "\t\t\t\t}%s\n"
+            , rd->id
+            , rd->name
+            , rd->entries
+            , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
+            , rrddim_algorithm_name(rd->algorithm)
+            , rd->multiplier
+            , rd->divisor
+            , rd->last_collected_time.tv_sec
+            , rd->collected_value
+            , rd->calculated_value
+            , rd->last_collected_value
+            , rd->last_calculated_value
+            , rd->memsize
+            , rd->next?",":""
+            );
+    }
+
+    buffer_sprintf(wb,
+        "\t\t\t],\n"
+        "\t\t\t\"memory\" : %lu\n"
+        "\t\t}"
+        , memory
+        );
+
+    pthread_rwlock_unlock(&st->rwlock);
+    return memory;
 }
 
 #define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
@@ -213,40 +213,40 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
 
 void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb)
 {
-       buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
-       rrd_stats_one_json(st, options, wb);
-       buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
+    buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+    rrd_stats_one_json(st, options, wb);
+    buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
 }
 
 void rrd_stats_all_json(BUFFER *wb)
 {
-       unsigned long memory = 0;
-       long c;
-       RRDSET *st;
-
-       buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
-
-       pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
-       for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
-               if(st->enabled && st->dimensions) {
-                       if(c) buffer_strcat(wb, ",\n");
-                       memory += rrd_stats_one_json(st, NULL, wb);
-                       c++;
-               }
-       }
-       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
-
-       buffer_sprintf(wb, "\n\t],\n"
-               "\t\"hostname\": \"%s\",\n"
-               "\t\"update_every\": %d,\n"
-               "\t\"history\": %d,\n"
-               "\t\"memory\": %lu\n"
-               "}\n"
-               , hostname
-               , rrd_update_every
-               , rrd_default_history_entries
-               , memory
-               );
+    unsigned long memory = 0;
+    long c;
+    RRDSET *st;
+
+    buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
+
+    pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+    for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
+        if(st->enabled && st->dimensions) {
+            if(c) buffer_strcat(wb, ",\n");
+            memory += rrd_stats_one_json(st, NULL, wb);
+            c++;
+        }
+    }
+    pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
+
+    buffer_sprintf(wb, "\n\t],\n"
+        "\t\"hostname\": \"%s\",\n"
+        "\t\"update_every\": %d,\n"
+        "\t\"history\": %d,\n"
+        "\t\"memory\": %lu\n"
+        "}\n"
+        , hostname
+        , rrd_update_every
+        , rrd_default_history_entries
+        , memory
+        );
 }
 
 
@@ -254,42 +254,42 @@ void rrd_stats_all_json(BUFFER *wb)
 // ----------------------------------------------------------------------------
 
 // RRDR dimension options
-#define RRDR_EMPTY     0x01 // the dimension contains / the value is empty (null)
-#define RRDR_RESET     0x02 // the dimension contains / the value is reset
-#define RRDR_HIDDEN    0x04 // the dimension contains / the value is hidden
-#define RRDR_NONZERO   0x08 // the dimension contains / the value is non-zero
+#define RRDR_EMPTY      0x01 // the dimension contains / the value is empty (null)
+#define RRDR_RESET      0x02 // the dimension contains / the value is reset
+#define RRDR_HIDDEN     0x04 // the dimension contains / the value is hidden
+#define RRDR_NONZERO    0x08 // the dimension contains / the value is non-zero
 
 // RRDR result options
 #define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
 #define RRDR_RESULT_OPTION_RELATIVE 0x00000002
 
 typedef struct rrdresult {
-       RRDSET *st;                     // the chart this result refers to
+    RRDSET *st;         // the chart this result refers to
 
-       uint32_t result_options;        // RRDR_RESULT_OPTION_*
+    uint32_t result_options;    // RRDR_RESULT_OPTION_*
 
-       int d;                                  // the number of dimensions
-       long n;                                 // the number of values in the arrays
-       long rows;                          // the number of rows used
+    int d;                  // the number of dimensions
+    long n;                 // the number of values in the arrays
+    long rows;              // the number of rows used
 
-       uint8_t *od;                    // the options for the dimensions
+    uint8_t *od;            // the options for the dimensions
 
-       time_t *t;                              // array of n timestamps
-       calculated_number *v;   // array n x d values
-       uint8_t *o;                             // array n x d options
+    time_t *t;              // array of n timestamps
+    calculated_number *v;   // array n x d values
+    uint8_t *o;             // array n x d options
 
-       long c;                                 // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
+    long c;                 // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
 
-       long group;                             // how many collected values were grouped for each row
-       int update_every;               // what is the suggested update frequency in seconds
+    long group;             // how many collected values were grouped for each row
+    int update_every;       // what is the suggested update frequency in seconds
 
-       calculated_number min;
-       calculated_number max;
+    calculated_number min;
+    calculated_number max;
 
-       time_t before;
-       time_t after;
+    time_t before;
+    time_t after;
 
-       int has_st_lock;                // if st is read locked by us
+    int has_st_lock;        // if st is read locked by us
 } RRDR;
 
 #define rrdr_rows(r) ((r)->rows)
@@ -297,347 +297,347 @@ typedef struct rrdresult {
 /*
 static void rrdr_dump(RRDR *r)
 {
-       long c, i;
-       RRDDIM *d;
-
-       fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
-
-       for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
-               fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
-                               , d->id
-                               , d->name
-                               , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
-                               , (r->od[c] & RRDR_RESET)?"RESET ":""
-                               , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
-                               , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
-                               );
-       }
-
-       if(r->rows <= 0) {
-               fprintf(stderr, "RRDR does not have any values in it.\n");
-               return;
-       }
-
-       fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
-
-       // for each line in the array
-       for(i = 0; i < r->rows ;i++) {
-               calculated_number *cn = &r->v[ i * r->d ];
-               uint8_t *co = &r->o[ i * r->d ];
-
-               // print the id and the timestamp of the line
-               fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
-
-               // for each dimension
-               for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
-                       if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-                       if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
-
-                       if(co[c] & RRDR_EMPTY)
-                               fprintf(stderr, "null ");
-                       else
-                               fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
-                                       , cn[c]
-                                       , (co[c] & RRDR_EMPTY)?"E":" "
-                                       , (co[c] & RRDR_RESET)?"R":" "
-                                       , (co[c] & RRDR_HIDDEN)?"H":" "
-                                       , (co[c] & RRDR_NONZERO)?"N":" "
-                                       );
-               }
-
-               fprintf(stderr, "\n");
-       }
+    long c, i;
+    RRDDIM *d;
+
+    fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
+
+    for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
+        fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
+                , d->id
+                , d->name
+                , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
+                , (r->od[c] & RRDR_RESET)?"RESET ":""
+                , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
+                , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
+                );
+    }
+
+    if(r->rows <= 0) {
+        fprintf(stderr, "RRDR does not have any values in it.\n");
+        return;
+    }
+
+    fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
+
+    // for each line in the array
+    for(i = 0; i < r->rows ;i++) {
+        calculated_number *cn = &r->v[ i * r->d ];
+        uint8_t *co = &r->o[ i * r->d ];
+
+        // print the id and the timestamp of the line
+        fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
+
+        // for each dimension
+        for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
+            if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+            if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
+
+            if(co[c] & RRDR_EMPTY)
+                fprintf(stderr, "null ");
+            else
+                fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
+                    , cn[c]
+                    , (co[c] & RRDR_EMPTY)?"E":" "
+                    , (co[c] & RRDR_RESET)?"R":" "
+                    , (co[c] & RRDR_HIDDEN)?"H":" "
+                    , (co[c] & RRDR_NONZERO)?"N":" "
+                    );
+        }
+
+        fprintf(stderr, "\n");
+    }
 }
 */
 
 void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
 {
-       char b[strlen(dims) + 1];
-       char *o = b, *tok;
-       strcpy(o, dims);
-
-       long c;
-       RRDDIM *d;
-
-       // disable all of them
-       for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
-               r->od[c] |= RRDR_HIDDEN;
-
-       while(o && *o && (tok = mystrsep(&o, ",|"))) {
-               if(!*tok) continue;
-               
-               uint32_t hash = simple_hash(tok);
-
-               // find it and enable it
-               for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
-                       if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
-                               r->od[c] &= ~RRDR_HIDDEN;
-
-                               // since the user needs this dimension
-                               // make it appear as NONZERO, to return it
-                               // even if the dimension has only zeros
-                               r->od[c] |= RRDR_NONZERO;
-                       }
-               }
-       }
+    char b[strlen(dims) + 1];
+    char *o = b, *tok;
+    strcpy(o, dims);
+
+    long c;
+    RRDDIM *d;
+
+    // disable all of them
+    for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
+        r->od[c] |= RRDR_HIDDEN;
+
+    while(o && *o && (tok = mystrsep(&o, ",|"))) {
+        if(!*tok) continue;
+        
+        uint32_t hash = simple_hash(tok);
+
+        // find it and enable it
+        for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
+            if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
+                r->od[c] &= ~RRDR_HIDDEN;
+
+                // since the user needs this dimension
+                // make it appear as NONZERO, to return it
+                // even if the dimension has only zeros
+                r->od[c] |= RRDR_NONZERO;
+            }
+        }
+    }
 }
 
 void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
 {
-       switch(format) {
-       case DATASOURCE_JSON:
-               buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
-               break;
-
-       case DATASOURCE_DATATABLE_JSON:
-               buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
-               break;
-
-       case DATASOURCE_DATATABLE_JSONP:
-               buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
-               break;
-
-       case DATASOURCE_JSONP:
-               buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
-               break;
-
-       case DATASOURCE_SSV:
-               buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
-               break;
-
-       case DATASOURCE_CSV:
-               buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
-               break;
-
-       case DATASOURCE_TSV:
-               buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
-               break;
-
-       case DATASOURCE_HTML:
-               buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
-               break;
-
-       case DATASOURCE_JS_ARRAY:
-               buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
-               break;
-
-       case DATASOURCE_SSV_COMMA:
-               buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
-               break;
-
-       default:
-               buffer_strcat(wb, "unknown");
-               break;
-       }
+    switch(format) {
+    case DATASOURCE_JSON:
+        buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
+        break;
+
+    case DATASOURCE_DATATABLE_JSON:
+        buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
+        break;
+
+    case DATASOURCE_DATATABLE_JSONP:
+        buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
+        break;
+
+    case DATASOURCE_JSONP:
+        buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
+        break;
+
+    case DATASOURCE_SSV:
+        buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
+        break;
+
+    case DATASOURCE_CSV:
+        buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
+        break;
+
+    case DATASOURCE_TSV:
+        buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
+        break;
+
+    case DATASOURCE_HTML:
+        buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
+        break;
+
+    case DATASOURCE_JS_ARRAY:
+        buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
+        break;
+
+    case DATASOURCE_SSV_COMMA:
+        buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
+        break;
+
+    default:
+        buffer_strcat(wb, "unknown");
+        break;
+    }
 }
 
 uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
 {
-       if(options & RRDR_OPTION_NONZERO) {
-               long i;
-
-               if(dims && *dims) {
-                       // the caller wants specific dimensions
-                       // disable NONZERO option
-                       // to make sure we don't accidentally prevent
-                       // the specific dimensions from being returned
-                       i = 0;
-               }
-               else {
-                       // find how many dimensions are not zero
-                       long c;
-                       RRDDIM *rd;
-                       for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
-                               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-                               if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
-                               i++;
-                       }
-               }
-
-               // if with nonzero we get i = 0 (no dimensions will be returned)
-               // disable nonzero to show all dimensions
-               if(!i) options &= ~RRDR_OPTION_NONZERO;
-       }
-
-       return options;
+    if(options & RRDR_OPTION_NONZERO) {
+        long i;
+
+        if(dims && *dims) {
+            // the caller wants specific dimensions
+            // disable NONZERO option
+            // to make sure we don't accidentally prevent
+            // the specific dimensions from being returned
+            i = 0;
+        }
+        else {
+            // find how many dimensions are not zero
+            long c;
+            RRDDIM *rd;
+            for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
+                if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+                if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
+                i++;
+            }
+        }
+
+        // if with nonzero we get i = 0 (no dimensions will be returned)
+        // disable nonzero to show all dimensions
+        if(!i) options &= ~RRDR_OPTION_NONZERO;
+    }
+
+    return options;
 }
 
 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
 {
-       long rows = rrdr_rows(r);
-       long c, i;
-       RRDDIM *rd;
-
-       //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
-       char kq[2] = "",                                        // key quote
-               sq[2] = "";                                             // string quote
-
-       if( options & RRDR_OPTION_GOOGLE_JSON ) {
-               kq[0] = '\0';
-               sq[0] = '\'';
-       }
-       else {
-               kq[0] = '"';
-               sq[0] = '"';
-       }
-
-       buffer_sprintf(wb, "{\n"
-                       "       %sapi%s: 1,\n"
-                       "       %sid%s: %s%s%s,\n"
-                       "       %sname%s: %s%s%s,\n"
-                       "       %sview_update_every%s: %d,\n"
-                       "       %supdate_every%s: %d,\n"
-                       "       %sfirst_entry%s: %u,\n"
-                       "       %slast_entry%s: %u,\n"
-                       "       %sbefore%s: %u,\n"
-                       "       %safter%s: %u,\n"
-                       "       %sdimension_names%s: ["
-                       , kq, kq
-                       , kq, kq, sq, r->st->id, sq
-                       , kq, kq, sq, r->st->name, sq
-                       , kq, kq, r->update_every
-                       , kq, kq, r->st->update_every
-                       , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
-                       , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
-                       , kq, kq, (uint32_t)r->before
-                       , kq, kq, (uint32_t)r->after
-                       , kq, kq);
-
-       for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               if(i) buffer_strcat(wb, ", ");
-               buffer_strcat(wb, sq);
-               buffer_strcat(wb, rd->name);
-               buffer_strcat(wb, sq);
-               i++;
-       }
-       if(!i) {
+    long rows = rrdr_rows(r);
+    long c, i;
+    RRDDIM *rd;
+
+    //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
+    char kq[2] = "",                    // key quote
+        sq[2] = "";                     // string quote
+
+    if( options & RRDR_OPTION_GOOGLE_JSON ) {
+        kq[0] = '\0';
+        sq[0] = '\'';
+    }
+    else {
+        kq[0] = '"';
+        sq[0] = '"';
+    }
+
+    buffer_sprintf(wb, "{\n"
+            "   %sapi%s: 1,\n"
+            "   %sid%s: %s%s%s,\n"
+            "   %sname%s: %s%s%s,\n"
+            "   %sview_update_every%s: %d,\n"
+            "   %supdate_every%s: %d,\n"
+            "   %sfirst_entry%s: %u,\n"
+            "   %slast_entry%s: %u,\n"
+            "   %sbefore%s: %u,\n"
+            "   %safter%s: %u,\n"
+            "   %sdimension_names%s: ["
+            , kq, kq
+            , kq, kq, sq, r->st->id, sq
+            , kq, kq, sq, r->st->name, sq
+            , kq, kq, r->update_every
+            , kq, kq, r->st->update_every
+            , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
+            , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
+            , kq, kq, (uint32_t)r->before
+            , kq, kq, (uint32_t)r->after
+            , kq, kq);
+
+    for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        if(i) buffer_strcat(wb, ", ");
+        buffer_strcat(wb, sq);
+        buffer_strcat(wb, rd->name);
+        buffer_strcat(wb, sq);
+        i++;
+    }
+    if(!i) {
 #ifdef NETDATA_INTERNAL_CHECKS
-               error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
+        error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
 #endif
-               rows = 0;
-               buffer_strcat(wb, sq);
-               buffer_strcat(wb, "no data");
-               buffer_strcat(wb, sq);
-       }
-
-       buffer_sprintf(wb, "],\n"
-                       "       %sdimension_ids%s: ["
-                       , kq, kq);
-
-       for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               if(i) buffer_strcat(wb, ", ");
-               buffer_strcat(wb, sq);
-               buffer_strcat(wb, rd->id);
-               buffer_strcat(wb, sq);
-               i++;
-       }
-       if(!i) {
-               rows = 0;
-               buffer_strcat(wb, sq);
-               buffer_strcat(wb, "no data");
-               buffer_strcat(wb, sq);
-       }
-
-       buffer_sprintf(wb, "],\n"
-                       "       %slatest_values%s: ["
-                       , kq, kq);
-
-       for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               if(i) buffer_strcat(wb, ", ");
-               i++;
-
-               storage_number n = rd->values[rrdset_last_slot(r->st)];
-
-               if(!does_storage_number_exist(n))
-                       buffer_strcat(wb, "null");
-               else
-                       buffer_rrd_value(wb, unpack_storage_number(n));
-       }
-       if(!i) {
-               rows = 0;
-               buffer_strcat(wb, "null");
-       }
-
-       buffer_sprintf(wb, "],\n"
-                       "       %sview_latest_values%s: ["
-                       , kq, kq);
-
-       i = 0;
-       if(rows) {
-               for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-                       if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-                       if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-                       if(i) buffer_strcat(wb, ", ");
-                       i++;
-
-                       calculated_number *cn = &r->v[ (0) * r->d ];
-                       uint8_t *co = &r->o[ (0) * r->d ];
-
-                       if(co[c] & RRDR_EMPTY)
-                               buffer_strcat(wb, "null");
-                       else
-                               buffer_rrd_value(wb, cn[c]);
-               }
-       }
-       if(!i) {
-               rows = 0;
-               buffer_strcat(wb, "null");
-       }
-
-       buffer_sprintf(wb, "],\n"
-                       "       %sdimensions%s: %ld,\n"
-                       "       %spoints%s: %ld,\n"
-                       "       %sformat%s: %s"
-                       , kq, kq, i
-                       , kq, kq, rows
-                       , kq, kq, sq
-                       );
-
-       rrdr_buffer_print_format(wb, format);
-
-       buffer_sprintf(wb, "%s,\n"
-                       "       %sresult%s: "
-                       , sq
-                       , kq, kq
-                       );
-
-       if(string_value) buffer_strcat(wb, sq);
-       //info("JSONWRAPPER(): %s: END", r->st->id);
+        rows = 0;
+        buffer_strcat(wb, sq);
+        buffer_strcat(wb, "no data");
+        buffer_strcat(wb, sq);
+    }
+
+    buffer_sprintf(wb, "],\n"
+            "   %sdimension_ids%s: ["
+            , kq, kq);
+
+    for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        if(i) buffer_strcat(wb, ", ");
+        buffer_strcat(wb, sq);
+        buffer_strcat(wb, rd->id);
+        buffer_strcat(wb, sq);
+        i++;
+    }
+    if(!i) {
+        rows = 0;
+        buffer_strcat(wb, sq);
+        buffer_strcat(wb, "no data");
+        buffer_strcat(wb, sq);
+    }
+
+    buffer_sprintf(wb, "],\n"
+            "   %slatest_values%s: ["
+            , kq, kq);
+
+    for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        if(i) buffer_strcat(wb, ", ");
+        i++;
+
+        storage_number n = rd->values[rrdset_last_slot(r->st)];
+
+        if(!does_storage_number_exist(n))
+            buffer_strcat(wb, "null");
+        else
+            buffer_rrd_value(wb, unpack_storage_number(n));
+    }
+    if(!i) {
+        rows = 0;
+        buffer_strcat(wb, "null");
+    }
+
+    buffer_sprintf(wb, "],\n"
+            "   %sview_latest_values%s: ["
+            , kq, kq);
+
+    i = 0;
+    if(rows) {
+        for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+            if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+            if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+            if(i) buffer_strcat(wb, ", ");
+            i++;
+
+            calculated_number *cn = &r->v[ (0) * r->d ];
+            uint8_t *co = &r->o[ (0) * r->d ];
+
+            if(co[c] & RRDR_EMPTY)
+                buffer_strcat(wb, "null");
+            else
+                buffer_rrd_value(wb, cn[c]);
+        }
+    }
+    if(!i) {
+        rows = 0;
+        buffer_strcat(wb, "null");
+    }
+
+    buffer_sprintf(wb, "],\n"
+            "   %sdimensions%s: %ld,\n"
+            "   %spoints%s: %ld,\n"
+            "   %sformat%s: %s"
+            , kq, kq, i
+            , kq, kq, rows
+            , kq, kq, sq
+            );
+
+    rrdr_buffer_print_format(wb, format);
+
+    buffer_sprintf(wb, "%s,\n"
+            "   %sresult%s: "
+            , sq
+            , kq, kq
+            );
+
+    if(string_value) buffer_strcat(wb, sq);
+    //info("JSONWRAPPER(): %s: END", r->st->id);
 }
 
 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
 {
-       (void)format;
-
-       char kq[2] = "",                                        // key quote
-               sq[2] = "";                                             // string quote
-
-       if( options & RRDR_OPTION_GOOGLE_JSON ) {
-               kq[0] = '\0';
-               sq[0] = '\'';
-       }
-       else {
-               kq[0] = '"';
-               sq[0] = '"';
-       }
-
-       if(string_value) buffer_strcat(wb, sq);
-
-       buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
-       buffer_rrd_value(wb, r->min);
-       buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
-       buffer_rrd_value(wb, r->max);
-       buffer_strcat(wb, "\n}\n");
+    (void)format;
+
+    char kq[2] = "",                    // key quote
+        sq[2] = "";                     // string quote
+
+    if( options & RRDR_OPTION_GOOGLE_JSON ) {
+        kq[0] = '\0';
+        sq[0] = '\'';
+    }
+    else {
+        kq[0] = '"';
+        sq[0] = '"';
+    }
+
+    if(string_value) buffer_strcat(wb, sq);
+
+    buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
+    buffer_rrd_value(wb, r->min);
+    buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
+    buffer_rrd_value(wb, r->max);
+    buffer_strcat(wb, "\n}\n");
 }
 
 #define JSON_DATES_JS 1
@@ -645,1407 +645,1407 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t option
 
 static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
 {
-       //info("RRD2JSON(): %s: BEGIN", r->st->id);
-       int row_annotations = 0, dates, dates_with_new = 0;
-       char kq[2] = "",                                        // key quote
-               sq[2] = "",                                             // string quote
-               pre_label[101] = "",                    // before each label
-               post_label[101] = "",                   // after each label
-               pre_date[101] = "",                             // the beginning of line, to the date
-               post_date[101] = "",                    // closing the date
-               pre_value[101] = "",                    // before each value
-               post_value[101] = "",                   // after each value
-               post_line[101] = "",                    // at the end of each row
-               normal_annotation[201] = "",    // default row annotation
-               overflow_annotation[201] = "",  // overflow row annotation
-               data_begin[101] = "",                   // between labels and values
-               finish[101] = "";                               // at the end of everything
-
-       if(datatable) {
-               dates = JSON_DATES_JS;
-               if( options & RRDR_OPTION_GOOGLE_JSON ) {
-                       kq[0] = '\0';
-                       sq[0] = '\'';
-               }
-               else {
-                       kq[0] = '"';
-                       sq[0] = '"';
-               }
-               row_annotations = 1;
-               snprintfz(pre_date,   100, "            {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
-               snprintfz(post_date,  100, "%s}", sq);
-               snprintfz(pre_label,  100, ",\n         {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
-               snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
-               snprintfz(pre_value,  100, ",{%sv%s:", kq, kq);
-               strcpy(post_value,         "}");
-               strcpy(post_line,          "]}");
-               snprintfz(data_begin, 100, "\n  ],\n    %srows%s:\n     [\n", kq, kq);
-               strcpy(finish,             "\n  ]\n}");
-
-               snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
-               snprintfz(normal_annotation,   200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
-
-               buffer_sprintf(wb, "{\n %scols%s:\n     [\n", kq, kq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-
-               // remove the valueobjects flag
-               // google wants its own keys
-               if(options & RRDR_OPTION_OBJECTSROWS)
-                       options &= ~RRDR_OPTION_OBJECTSROWS;
-       }
-       else {
-               kq[0] = '"';
-               sq[0] = '"';
-               if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
-                       dates = JSON_DATES_TIMESTAMP;
-                       dates_with_new = 0;
-               }
-               else {
-                       dates = JSON_DATES_JS;
-                       dates_with_new = 1;
-               }
-               if( options & RRDR_OPTION_OBJECTSROWS )
-                       strcpy(pre_date, "              { ");
-               else
-                       strcpy(pre_date, "              [ ");
-               strcpy(pre_label,  ", \"");
-               strcpy(post_label, "\"");
-               strcpy(pre_value,  ", ");
-               if( options & RRDR_OPTION_OBJECTSROWS )
-                       strcpy(post_line, "}");
-               else
-                       strcpy(post_line, "]");
-               snprintfz(data_begin, 100, "],\n        %sdata%s:\n     [\n", kq, kq);
-               strcpy(finish,             "\n  ]\n}");
-
-               buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
-               buffer_sprintf(wb, "%stime%s", sq, sq);
-       }
-
-       // -------------------------------------------------------------------------
-       // print the JSON header
-
-       long c, i;
-       RRDDIM *rd;
-
-       // print the header lines
-       for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               buffer_strcat(wb, pre_label);
-               buffer_strcat(wb, rd->name);
-               buffer_strcat(wb, post_label);
-               i++;
-       }
-       if(!i) {
-               buffer_strcat(wb, pre_label);
-               buffer_strcat(wb, "no data");
-               buffer_strcat(wb, post_label);
-       }
-
-       // print the begin of row data
-       buffer_strcat(wb, data_begin);
-
-       // if all dimensions are hidden, print a null
-       if(!i) {
-               buffer_strcat(wb, finish);
-               return;
-       }
-
-       long start = 0, end = rrdr_rows(r), step = 1;
-       if((options & RRDR_OPTION_REVERSED)) {
-               start = rrdr_rows(r) - 1;
-               end = -1;
-               step = -1;
-       }
-
-       // for each line in the array
-       calculated_number total = 1;
-       for(i = start; i != end ;i += step) {
-               calculated_number *cn = &r->v[ i * r->d ];
-               uint8_t *co = &r->o[ i * r->d ];
-
-               time_t now = r->t[i];
-
-               if(dates == JSON_DATES_JS) {
-                       // generate the local date time
-                       struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
-                       if(!tm) { error("localtime_r() failed."); continue; }
-
-                       if(likely(i != start)) buffer_strcat(wb, ",\n");
-                       buffer_strcat(wb, pre_date);
-
-                       if( options & RRDR_OPTION_OBJECTSROWS )
-                               buffer_sprintf(wb, "%stime%s: ", kq, kq);
-
-                       if(dates_with_new)
-                               buffer_strcat(wb, "new ");
-
-                       buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-
-                       buffer_strcat(wb, post_date);
-
-                       if(row_annotations) {
-                               // google supports one annotation per row
-                               int annotation_found = 0;
-                               for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
-                                       if(co[c] & RRDR_RESET) {
-                                               buffer_strcat(wb, overflow_annotation);
-                                               annotation_found = 1;
-                                               break;
-                                       }
-                               }
-                               if(!annotation_found)
-                                       buffer_strcat(wb, normal_annotation);
-                       }
-               }
-               else {
-                       // print the timestamp of the line
-                       if(likely(i != start)) buffer_strcat(wb, ",\n");
-                       buffer_strcat(wb, pre_date);
-
-                       if( options & RRDR_OPTION_OBJECTSROWS )
-                               buffer_sprintf(wb, "%stime%s: ", kq, kq);
-
-                       buffer_rrd_value(wb, (calculated_number)r->t[i]);
-                       // in ms
-                       if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
-
-                       buffer_strcat(wb, post_date);
-               }
-
-               if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
-                       total = 0;
-                       for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-                               calculated_number n = cn[c];
-
-                               if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                                       n = -n;
-
-                               total += n;
-                       }
-                       // prevent a division by zero
-                       if(total == 0) total = 1;
-               }
-
-               // for each dimension
-               for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
-                       if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-                       if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-                       calculated_number n = cn[c];
-
-                       buffer_strcat(wb, pre_value);
-
-                       if( options & RRDR_OPTION_OBJECTSROWS )
-                               buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
-
-                       if(co[c] & RRDR_EMPTY) {
-                               if(options & RRDR_OPTION_NULL2ZERO)
-                                       buffer_strcat(wb, "0");
-                               else
-                                       buffer_strcat(wb, "null");
-                       }
-                       else {
-                               if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                                       n = -n;
-
-                               if(unlikely(options & RRDR_OPTION_PERCENTAGE))
-                                       n = n * 100 / total;
-
-                               buffer_rrd_value(wb, n);
-                       }
-
-                       buffer_strcat(wb, post_value);
-               }
-
-               buffer_strcat(wb, post_line);
-       }
-
-       buffer_strcat(wb, finish);
-       //info("RRD2JSON(): %s: END", r->st->id);
+    //info("RRD2JSON(): %s: BEGIN", r->st->id);
+    int row_annotations = 0, dates, dates_with_new = 0;
+    char kq[2] = "",                    // key quote
+        sq[2] = "",                     // string quote
+        pre_label[101] = "",            // before each label
+        post_label[101] = "",           // after each label
+        pre_date[101] = "",             // the beginning of line, to the date
+        post_date[101] = "",            // closing the date
+        pre_value[101] = "",            // before each value
+        post_value[101] = "",           // after each value
+        post_line[101] = "",            // at the end of each row
+        normal_annotation[201] = "",    // default row annotation
+        overflow_annotation[201] = "",  // overflow row annotation
+        data_begin[101] = "",           // between labels and values
+        finish[101] = "";               // at the end of everything
+
+    if(datatable) {
+        dates = JSON_DATES_JS;
+        if( options & RRDR_OPTION_GOOGLE_JSON ) {
+            kq[0] = '\0';
+            sq[0] = '\'';
+        }
+        else {
+            kq[0] = '"';
+            sq[0] = '"';
+        }
+        row_annotations = 1;
+        snprintfz(pre_date,   100, "        {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
+        snprintfz(post_date,  100, "%s}", sq);
+        snprintfz(pre_label,  100, ",\n     {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
+        snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
+        snprintfz(pre_value,  100, ",{%sv%s:", kq, kq);
+        strcpy(post_value,         "}");
+        strcpy(post_line,          "]}");
+        snprintfz(data_begin, 100, "\n  ],\n    %srows%s:\n [\n", kq, kq);
+        strcpy(finish,             "\n  ]\n}");
+
+        snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
+        snprintfz(normal_annotation,   200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
+
+        buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+
+        // remove the valueobjects flag
+        // google wants its own keys
+        if(options & RRDR_OPTION_OBJECTSROWS)
+            options &= ~RRDR_OPTION_OBJECTSROWS;
+    }
+    else {
+        kq[0] = '"';
+        sq[0] = '"';
+        if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
+            dates = JSON_DATES_TIMESTAMP;
+            dates_with_new = 0;
+        }
+        else {
+            dates = JSON_DATES_JS;
+            dates_with_new = 1;
+        }
+        if( options & RRDR_OPTION_OBJECTSROWS )
+            strcpy(pre_date, "      { ");
+        else
+            strcpy(pre_date, "      [ ");
+        strcpy(pre_label,  ", \"");
+        strcpy(post_label, "\"");
+        strcpy(pre_value,  ", ");
+        if( options & RRDR_OPTION_OBJECTSROWS )
+            strcpy(post_line, "}");
+        else
+            strcpy(post_line, "]");
+        snprintfz(data_begin, 100, "],\n    %sdata%s:\n [\n", kq, kq);
+        strcpy(finish,             "\n  ]\n}");
+
+        buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
+        buffer_sprintf(wb, "%stime%s", sq, sq);
+    }
+
+    // -------------------------------------------------------------------------
+    // print the JSON header
+
+    long c, i;
+    RRDDIM *rd;
+
+    // print the header lines
+    for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        buffer_strcat(wb, pre_label);
+        buffer_strcat(wb, rd->name);
+        buffer_strcat(wb, post_label);
+        i++;
+    }
+    if(!i) {
+        buffer_strcat(wb, pre_label);
+        buffer_strcat(wb, "no data");
+        buffer_strcat(wb, post_label);
+    }
+
+    // print the begin of row data
+    buffer_strcat(wb, data_begin);
+
+    // if all dimensions are hidden, print a null
+    if(!i) {
+        buffer_strcat(wb, finish);
+        return;
+    }
+
+    long start = 0, end = rrdr_rows(r), step = 1;
+    if((options & RRDR_OPTION_REVERSED)) {
+        start = rrdr_rows(r) - 1;
+        end = -1;
+        step = -1;
+    }
+
+    // for each line in the array
+    calculated_number total = 1;
+    for(i = start; i != end ;i += step) {
+        calculated_number *cn = &r->v[ i * r->d ];
+        uint8_t *co = &r->o[ i * r->d ];
+
+        time_t now = r->t[i];
+
+        if(dates == JSON_DATES_JS) {
+            // generate the local date time
+            struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
+            if(!tm) { error("localtime_r() failed."); continue; }
+
+            if(likely(i != start)) buffer_strcat(wb, ",\n");
+            buffer_strcat(wb, pre_date);
+
+            if( options & RRDR_OPTION_OBJECTSROWS )
+                buffer_sprintf(wb, "%stime%s: ", kq, kq);
+
+            if(dates_with_new)
+                buffer_strcat(wb, "new ");
+
+            buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+            buffer_strcat(wb, post_date);
+
+            if(row_annotations) {
+                // google supports one annotation per row
+                int annotation_found = 0;
+                for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
+                    if(co[c] & RRDR_RESET) {
+                        buffer_strcat(wb, overflow_annotation);
+                        annotation_found = 1;
+                        break;
+                    }
+                }
+                if(!annotation_found)
+                    buffer_strcat(wb, normal_annotation);
+            }
+        }
+        else {
+            // print the timestamp of the line
+            if(likely(i != start)) buffer_strcat(wb, ",\n");
+            buffer_strcat(wb, pre_date);
+
+            if( options & RRDR_OPTION_OBJECTSROWS )
+                buffer_sprintf(wb, "%stime%s: ", kq, kq);
+
+            buffer_rrd_value(wb, (calculated_number)r->t[i]);
+            // in ms
+            if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
+
+            buffer_strcat(wb, post_date);
+        }
+
+        if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
+            total = 0;
+            for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+                calculated_number n = cn[c];
+
+                if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+                    n = -n;
+
+                total += n;
+            }
+            // prevent a division by zero
+            if(total == 0) total = 1;
+        }
+
+        // for each dimension
+        for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
+            if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+            if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+            calculated_number n = cn[c];
+
+            buffer_strcat(wb, pre_value);
+
+            if( options & RRDR_OPTION_OBJECTSROWS )
+                buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
+
+            if(co[c] & RRDR_EMPTY) {
+                if(options & RRDR_OPTION_NULL2ZERO)
+                    buffer_strcat(wb, "0");
+                else
+                    buffer_strcat(wb, "null");
+            }
+            else {
+                if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+                    n = -n;
+
+                if(unlikely(options & RRDR_OPTION_PERCENTAGE))
+                    n = n * 100 / total;
+
+                buffer_rrd_value(wb, n);
+            }
+
+            buffer_strcat(wb, post_value);
+        }
+
+        buffer_strcat(wb, post_line);
+    }
+
+    buffer_strcat(wb, finish);
+    //info("RRD2JSON(): %s: END", r->st->id);
 }
 
 static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
 {
-       //info("RRD2CSV(): %s: BEGIN", r->st->id);
-       long c, i;
-       RRDDIM *d;
-
-       // print the csv header
-       for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               if(!i) {
-                       buffer_strcat(wb, startline);
-                       if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
-                       buffer_strcat(wb, "time");
-                       if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
-               }
-               buffer_strcat(wb, separator);
-               if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
-               buffer_strcat(wb, d->name);
-               if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
-               i++;
-       }
-       buffer_strcat(wb, endline);
-
-       if(!i) {
-               // no dimensions present
-               return;
-       }
-
-       long start = 0, end = rrdr_rows(r), step = 1;
-       if((options & RRDR_OPTION_REVERSED)) {
-               start = rrdr_rows(r) - 1;
-               end = -1;
-               step = -1;
-       }
-
-       // for each line in the array
-       calculated_number total = 1;
-       for(i = start; i != end ;i += step) {
-               calculated_number *cn = &r->v[ i * r->d ];
-               uint8_t *co = &r->o[ i * r->d ];
-
-               buffer_strcat(wb, betweenlines);
-               buffer_strcat(wb, startline);
-
-               time_t now = r->t[i];
-
-               if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
-                       // print the timestamp of the line
-                       buffer_rrd_value(wb, (calculated_number)now);
-                       // in ms
-                       if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
-               }
-               else {
-                       // generate the local date time
-                       struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
-                       if(!tm) { error("localtime() failed."); continue; }
-                       buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-               }
-
-               if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
-                       total = 0;
-                       for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
-                               calculated_number n = cn[c];
-
-                               if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                                       n = -n;
-
-                               total += n;
-                       }
-                       // prevent a division by zero
-                       if(total == 0) total = 1;
-               }
-
-               // for each dimension
-               for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
-                       if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-                       if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-                       buffer_strcat(wb, separator);
-
-                       calculated_number n = cn[c];
-
-                       if(co[c] & RRDR_EMPTY) {
-                               if(options & RRDR_OPTION_NULL2ZERO)
-                                       buffer_strcat(wb, "0");
-                               else
-                                       buffer_strcat(wb, "null");
-                       }
-                       else {
-                               if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                                       n = -n;
-
-                               if(unlikely(options & RRDR_OPTION_PERCENTAGE))
-                                       n = n * 100 / total;
-
-                               buffer_rrd_value(wb, n);
-                       }
-               }
-
-               buffer_strcat(wb, endline);
-       }
-       //info("RRD2CSV(): %s: END", r->st->id);
+    //info("RRD2CSV(): %s: BEGIN", r->st->id);
+    long c, i;
+    RRDDIM *d;
+
+    // print the csv header
+    for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        if(!i) {
+            buffer_strcat(wb, startline);
+            if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
+            buffer_strcat(wb, "time");
+            if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
+        }
+        buffer_strcat(wb, separator);
+        if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
+        buffer_strcat(wb, d->name);
+        if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
+        i++;
+    }
+    buffer_strcat(wb, endline);
+
+    if(!i) {
+        // no dimensions present
+        return;
+    }
+
+    long start = 0, end = rrdr_rows(r), step = 1;
+    if((options & RRDR_OPTION_REVERSED)) {
+        start = rrdr_rows(r) - 1;
+        end = -1;
+        step = -1;
+    }
+
+    // for each line in the array
+    calculated_number total = 1;
+    for(i = start; i != end ;i += step) {
+        calculated_number *cn = &r->v[ i * r->d ];
+        uint8_t *co = &r->o[ i * r->d ];
+
+        buffer_strcat(wb, betweenlines);
+        buffer_strcat(wb, startline);
+
+        time_t now = r->t[i];
+
+        if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
+            // print the timestamp of the line
+            buffer_rrd_value(wb, (calculated_number)now);
+            // in ms
+            if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
+        }
+        else {
+            // generate the local date time
+            struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
+            if(!tm) { error("localtime() failed."); continue; }
+            buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+        }
+
+        if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
+            total = 0;
+            for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+                calculated_number n = cn[c];
+
+                if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+                    n = -n;
+
+                total += n;
+            }
+            // prevent a division by zero
+            if(total == 0) total = 1;
+        }
+
+        // for each dimension
+        for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+            if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+            if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+            buffer_strcat(wb, separator);
+
+            calculated_number n = cn[c];
+
+            if(co[c] & RRDR_EMPTY) {
+                if(options & RRDR_OPTION_NULL2ZERO)
+                    buffer_strcat(wb, "0");
+                else
+                    buffer_strcat(wb, "null");
+            }
+            else {
+                if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+                    n = -n;
+
+                if(unlikely(options & RRDR_OPTION_PERCENTAGE))
+                    n = n * 100 / total;
+
+                buffer_rrd_value(wb, n);
+            }
+        }
+
+        buffer_strcat(wb, endline);
+    }
+    //info("RRD2CSV(): %s: END", r->st->id);
 }
 
 inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
-       long c;
-       RRDDIM *d;
-
-       calculated_number *cn = &r->v[ i * r->d ];
-       uint8_t *co = &r->o[ i * r->d ];
-
-       calculated_number sum = 0, min = 0, max = 0, v;
-       int all_null = 1, init = 1;
-
-       calculated_number total = 1;
-       if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
-               total = 0;
-               for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
-                       calculated_number n = cn[c];
-
-                       if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                               n = -n;
-
-                       total += n;
-               }
-               // prevent a division by zero
-               if(total == 0) total = 1;
-       }
-
-       // for each dimension
-       for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
-               if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
-               if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
-
-               calculated_number n = cn[c];
-
-               if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
-                       n = -n;
-
-               if(unlikely(options & RRDR_OPTION_PERCENTAGE))
-                       n = n * 100 / total;
-
-               if(unlikely(init)) {
-                       if(n > 0) {
-                               min = 0;
-                               max = n;
-                       }
-                       else {
-                               min = n;
-                               max = 0;
-                       }
-                       init = 0;
-               }
-
-               if(likely(!(co[c] & RRDR_EMPTY))) {
-                       all_null = 0;
-                       sum += n;
-               }
-
-               if(n < min) min = n;
-               if(n > max) max = n;
-       }
-
-       if(unlikely(all_null)) {
-               if(likely(*all_values_are_null))
-                       *all_values_are_null = 1;
-               return 0;
-       }
-       else {
-               if(likely(*all_values_are_null))
-                       *all_values_are_null = 0;
-       }
-
-       if(options & RRDR_OPTION_MIN2MAX)
-               v = max - min;
-       else
-               v = sum;
-
-       return v;
+    long c;
+    RRDDIM *d;
+
+    calculated_number *cn = &r->v[ i * r->d ];
+    uint8_t *co = &r->o[ i * r->d ];
+
+    calculated_number sum = 0, min = 0, max = 0, v;
+    int all_null = 1, init = 1;
+
+    calculated_number total = 1;
+    if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
+        total = 0;
+        for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+            calculated_number n = cn[c];
+
+            if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+                n = -n;
+
+            total += n;
+        }
+        // prevent a division by zero
+        if(total == 0) total = 1;
+    }
+
+    // for each dimension
+    for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
+        if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
+        if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
+
+        calculated_number n = cn[c];
+
+        if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
+            n = -n;
+
+        if(unlikely(options & RRDR_OPTION_PERCENTAGE))
+            n = n * 100 / total;
+
+        if(unlikely(init)) {
+            if(n > 0) {
+                min = 0;
+                max = n;
+            }
+            else {
+                min = n;
+                max = 0;
+            }
+            init = 0;
+        }
+
+        if(likely(!(co[c] & RRDR_EMPTY))) {
+            all_null = 0;
+            sum += n;
+        }
+
+        if(n < min) min = n;
+        if(n > max) max = n;
+    }
+
+    if(unlikely(all_null)) {
+        if(likely(*all_values_are_null))
+            *all_values_are_null = 1;
+        return 0;
+    }
+    else {
+        if(likely(*all_values_are_null))
+            *all_values_are_null = 0;
+    }
+
+    if(options & RRDR_OPTION_MIN2MAX)
+        v = max - min;
+    else
+        v = sum;
+
+    return v;
 }
 
 static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
 {
-       //info("RRD2SSV(): %s: BEGIN", r->st->id);
-       long i;
-
-       buffer_strcat(wb, prefix);
-       long start = 0, end = rrdr_rows(r), step = 1;
-       if((options & RRDR_OPTION_REVERSED)) {
-               start = rrdr_rows(r) - 1;
-               end = -1;
-               step = -1;
-       }
-
-       // for each line in the array
-       for(i = start; i != end ;i += step) {
-               int all_values_are_null = 0;
-               calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
-
-               if(likely(i != start)) {
-                       if(r->min > v) r->min = v;
-                       if(r->max < v) r->max = v;
-               }
-               else {
-                       r->min = v;
-                       r->max = v;
-               }
-
-               if(likely(i != start))
-                       buffer_strcat(wb, separator);
-
-               if(all_values_are_null) {
-                       if(options & RRDR_OPTION_NULL2ZERO)
-                               buffer_strcat(wb, "0");
-                       else
-                               buffer_strcat(wb, "null");
-               }
-               else
-                       buffer_rrd_value(wb, v);
-       }
-       buffer_strcat(wb, suffix);
-       //info("RRD2SSV(): %s: END", r->st->id);
+    //info("RRD2SSV(): %s: BEGIN", r->st->id);
+    long i;
+
+    buffer_strcat(wb, prefix);
+    long start = 0, end = rrdr_rows(r), step = 1;
+    if((options & RRDR_OPTION_REVERSED)) {
+        start = rrdr_rows(r) - 1;
+        end = -1;
+        step = -1;
+    }
+
+    // for each line in the array
+    for(i = start; i != end ;i += step) {
+        int all_values_are_null = 0;
+        calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
+
+        if(likely(i != start)) {
+            if(r->min > v) r->min = v;
+            if(r->max < v) r->max = v;
+        }
+        else {
+            r->min = v;
+            r->max = v;
+        }
+
+        if(likely(i != start))
+            buffer_strcat(wb, separator);
+
+        if(all_values_are_null) {
+            if(options & RRDR_OPTION_NULL2ZERO)
+                buffer_strcat(wb, "0");
+            else
+                buffer_strcat(wb, "null");
+        }
+        else
+            buffer_rrd_value(wb, v);
+    }
+    buffer_strcat(wb, suffix);
+    //info("RRD2SSV(): %s: END", r->st->id);
 }
 
 inline static calculated_number *rrdr_line_values(RRDR *r)
 {
-       return &r->v[ r->c * r->d ];
+    return &r->v[ r->c * r->d ];
 }
 
 inline static uint8_t *rrdr_line_options(RRDR *r)
 {
-       return &r->o[ r->c * r->d ];
+    return &r->o[ r->c * r->d ];
 }
 
 inline static int rrdr_line_init(RRDR *r, time_t t)
 {
-       r->c++;
+    r->c++;
 
-       if(unlikely(r->c >= r->n)) {
-               error("requested to step above RRDR size for chart %s", r->st->name);
-               r->c = r->n - 1;
-       }
+    if(unlikely(r->c >= r->n)) {
+        error("requested to step above RRDR size for chart %s", r->st->name);
+        r->c = r->n - 1;
+    }
 
-       // save the time
-       r->t[r->c] = t;
+    // save the time
+    r->t[r->c] = t;
 
-       return 1;
+    return 1;
 }
 
 inline static void rrdr_lock_rrdset(RRDR *r) {
-       if(unlikely(!r)) {
-               error("NULL value given!");
-               return;
-       }
+    if(unlikely(!r)) {
+        error("NULL value given!");
+        return;
+    }
 
-       pthread_rwlock_rdlock(&r->st->rwlock);
-       r->has_st_lock = 1;
+    pthread_rwlock_rdlock(&r->st->rwlock);
+    r->has_st_lock = 1;
 }
 
 inline static void rrdr_unlock_rrdset(RRDR *r) {
-       if(unlikely(!r)) {
-               error("NULL value given!");
-               return;
-       }
-
-       if(likely(r->has_st_lock)) {
-               pthread_rwlock_unlock(&r->st->rwlock);
-               r->has_st_lock = 0;
-       }
+    if(unlikely(!r)) {
+        error("NULL value given!");
+        return;
+    }
+
+    if(likely(r->has_st_lock)) {
+        pthread_rwlock_unlock(&r->st->rwlock);
+        r->has_st_lock = 0;
+    }
 }
 
 inline static void rrdr_free(RRDR *r)
 {
-       if(unlikely(!r)) {
-               error("NULL value given!");
-               return;
-       }
-
-       rrdr_unlock_rrdset(r);
-       freez(r->t);
-       freez(r->v);
-       freez(r->o);
-       freez(r->od);
-       freez(r);
+    if(unlikely(!r)) {
+        error("NULL value given!");
+        return;
+    }
+
+    rrdr_unlock_rrdset(r);
+    freez(r->t);
+    freez(r->v);
+    freez(r->o);
+    freez(r->od);
+    freez(r);
 }
 
 inline void rrdr_done(RRDR *r)
 {
-       r->rows = r->c + 1;
-       r->c = 0;
+    r->rows = r->c + 1;
+    r->c = 0;
 }
 
 static RRDR *rrdr_create(RRDSET *st, long n)
 {
-       if(unlikely(!st)) {
-               error("NULL value given!");
-               return NULL;
-       }
+    if(unlikely(!st)) {
+        error("NULL value given!");
+        return NULL;
+    }
 
-       RRDR *r = callocz(1, sizeof(RRDR));
-       r->st = st;
+    RRDR *r = callocz(1, sizeof(RRDR));
+    r->st = st;
 
-       rrdr_lock_rrdset(r);
+    rrdr_lock_rrdset(r);
 
-       RRDDIM *rd;
-       for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
+    RRDDIM *rd;
+    for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
 
-       r->n = n;
+    r->n = n;
 
-       r->t = mallocz(n * sizeof(time_t));
-       r->v = mallocz(n * r->d * sizeof(calculated_number));
-       r->o = mallocz(n * r->d * sizeof(uint8_t));
-       r->od = mallocz(r->d * sizeof(uint8_t));
+    r->t = mallocz(n * sizeof(time_t));
+    r->v = mallocz(n * r->d * sizeof(calculated_number));
+    r->o = mallocz(n * r->d * sizeof(uint8_t));
+    r->od = mallocz(r->d * sizeof(uint8_t));
 
-       // set the hidden flag on hidden dimensions
-       int c;
-       for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
-               if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
-               else r->od[c] = 0;
-       }
+    // set the hidden flag on hidden dimensions
+    int c;
+    for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
+        if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
+        else r->od[c] = 0;
+    }
 
-       r->c = -1;
-       r->group = 1;
-       r->update_every = 1;
+    r->c = -1;
+    r->group = 1;
+    r->update_every = 1;
 
-       return r;
+    return r;
 }
 
 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
 {
-       int debug = st->debug;
-       int absolute_period_requested = -1;
-
-       time_t first_entry_t = rrdset_first_entry_t(st);
-       time_t last_entry_t  = rrdset_last_entry_t(st);
-
-       if(before == 0 && after == 0) {
-               before = last_entry_t;
-               after = first_entry_t;
-               absolute_period_requested = 0;
-       }
-
-       // allow relative for before and after
-       if(((before < 0)?-before:before) <= (st->update_every * st->entries)) {
-               before = last_entry_t + before;
-               absolute_period_requested = 0;
-       }
-
-       if(((after < 0)?-after:after) <= (st->update_every * st->entries)) {
-               if(after == 0) after = -st->update_every;
-               after = before + after;
-               absolute_period_requested = 0;
-       }
-
-       if(absolute_period_requested == -1)
-               absolute_period_requested = 1;
-
-       // make sure they are within our timeframe
-       if(before > last_entry_t)  before = last_entry_t;
-       if(before < first_entry_t) before = first_entry_t;
-
-       if(after > last_entry_t)  after = last_entry_t;
-       if(after < first_entry_t) after = first_entry_t;
-
-       // check if they are upside down
-       if(after > before) {
-               time_t tmp = before;
-               before = after;
-               after = tmp;
-       }
-
-       // the duration of the chart
-       time_t duration = before - after;
-       long available_points = duration / st->update_every;
-
-       if(duration <= 0 || available_points <= 0)
-               return rrdr_create(st, 1);
-
-       // check the wanted points
-       if(points < 0) points = -points;
-       if(points > available_points) points = available_points;
-       if(points == 0) points = available_points;
-
-       // calculate proper grouping of source data
-       long group = available_points / points;
-       if(group <= 0) group = 1;
-
-       // round group to the closest integer
-       if(available_points % points > points / 2) group++;
-
-       time_t after_new  = (aligned) ? (after  - (after  % (group * st->update_every))) : after;
-       time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
-       long points_new   = (before_new - after_new) / st->update_every / group;
-
-       // find the starting and ending slots in our round robin db
-       long    start_at_slot = rrdset_time2slot(st, before_new),
-                       stop_at_slot  = rrdset_time2slot(st, after_new);
+    int debug = st->debug;
+    int absolute_period_requested = -1;
+
+    time_t first_entry_t = rrdset_first_entry_t(st);
+    time_t last_entry_t  = rrdset_last_entry_t(st);
+
+    if(before == 0 && after == 0) {
+        before = last_entry_t;
+        after = first_entry_t;
+        absolute_period_requested = 0;
+    }
+
+    // allow relative for before and after
+    if(((before < 0)?-before:before) <= (st->update_every * st->entries)) {
+        before = last_entry_t + before;
+        absolute_period_requested = 0;
+    }
+
+    if(((after < 0)?-after:after) <= (st->update_every * st->entries)) {
+        if(after == 0) after = -st->update_every;
+        after = before + after;
+        absolute_period_requested = 0;
+    }
+
+    if(absolute_period_requested == -1)
+        absolute_period_requested = 1;
+
+    // make sure they are within our timeframe
+    if(before > last_entry_t)  before = last_entry_t;
+    if(before < first_entry_t) before = first_entry_t;
+
+    if(after > last_entry_t)  after = last_entry_t;
+    if(after < first_entry_t) after = first_entry_t;
+
+    // check if they are upside down
+    if(after > before) {
+        time_t tmp = before;
+        before = after;
+        after = tmp;
+    }
+
+    // the duration of the chart
+    time_t duration = before - after;
+    long available_points = duration / st->update_every;
+
+    if(duration <= 0 || available_points <= 0)
+        return rrdr_create(st, 1);
+
+    // check the wanted points
+    if(points < 0) points = -points;
+    if(points > available_points) points = available_points;
+    if(points == 0) points = available_points;
+
+    // calculate proper grouping of source data
+    long group = available_points / points;
+    if(group <= 0) group = 1;
+
+    // round group to the closest integer
+    if(available_points % points > points / 2) group++;
+
+    time_t after_new  = (aligned) ? (after  - (after  % (group * st->update_every))) : after;
+    time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
+    long points_new   = (before_new - after_new) / st->update_every / group;
+
+    // find the starting and ending slots in our round robin db
+    long    start_at_slot = rrdset_time2slot(st, before_new),
+            stop_at_slot  = rrdset_time2slot(st, after_new);
 
 #ifdef NETDATA_INTERNAL_CHECKS
-       if(after_new < first_entry_t) {
-               error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
-       }
-       if(after_new > last_entry_t) {
-               error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
-       }
-       if(before_new < first_entry_t) {
-               error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
-       }
-       if(before_new > last_entry_t) {
-               error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
-       }
-       if(start_at_slot < 0 || start_at_slot >= st->entries) {
-               error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
-       }
-       if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
-               error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
-       }
-       if(points_new > (before_new - after_new) / group / st->update_every + 1) {
-               error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
-       }
+    if(after_new < first_entry_t) {
+        error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
+    }
+    if(after_new > last_entry_t) {
+        error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
+    }
+    if(before_new < first_entry_t) {
+        error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
+    }
+    if(before_new > last_entry_t) {
+        error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
+    }
+    if(start_at_slot < 0 || start_at_slot >= st->entries) {
+        error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
+    }
+    if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
+        error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
+    }
+    if(points_new > (before_new - after_new) / group / st->update_every + 1) {
+        error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
+    }
 #endif
 
-       //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new);
+    //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new);
 
-       after = after_new;
-       before = before_new;
-       duration = before - after;
-       points = points_new;
+    after = after_new;
+    before = before_new;
+    duration = before - after;
+    points = points_new;
 
-       // Now we have:
-       // before = the end time of the calculation
-       // after = the start time of the calculation
-       // duration = the duration of the calculation
-       // group = the number of source points to aggregate / group together
-       // method = the method of grouping source points
-       // points = the number of points to generate
+    // Now we have:
+    // before = the end time of the calculation
+    // after = the start time of the calculation
+    // duration = the duration of the calculation
+    // group = the number of source points to aggregate / group together
+    // method = the method of grouping source points
+    // points = the number of points to generate
 
 
-       // -------------------------------------------------------------------------
-       // initialize our result set
+    // -------------------------------------------------------------------------
+    // initialize our result set
 
-       RRDR *r = rrdr_create(st, points);
-       if(!r) {
+    RRDR *r = rrdr_create(st, points);
+    if(!r) {
 #ifdef NETDATA_INTERNAL_CHECKS
-               error("Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
+        error("Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
 #endif
-               return NULL;
-       }
-       if(!r->d) {
+        return NULL;
+    }
+    if(!r->d) {
 #ifdef NETDATA_INTERNAL_CHECKS
-               error("Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
+        error("Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
 #endif
-               return r;
-       }
-
-       if(absolute_period_requested == 1)
-               r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
-       else
-               r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
-
-       // find how many dimensions we have
-       long dimensions = r->d;
-
-
-       // -------------------------------------------------------------------------
-       // checks for debugging
-
-       if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld"
-                       , st->id
-                       , (uint32_t)first_entry_t
-                       , (uint32_t)last_entry_t
-                       , (uint32_t)(last_entry_t - first_entry_t)
-                       , (uint32_t)after
-                       , (uint32_t)before
-                       , (uint32_t)duration
-                       , points
-                       , group
-                       );
-
-
-       // -------------------------------------------------------------------------
-       // temp arrays for keeping values per dimension
-
-       calculated_number       last_values[dimensions]; // keep the last value of each dimension
-       calculated_number       group_values[dimensions]; // keep sums when grouping
-       long                            group_counts[dimensions]; // keep the number of values added to group_values
-       uint8_t                         group_options[dimensions];
-       uint8_t                         found_non_zero[dimensions];
-
-
-       // initialize them
-       RRDDIM *rd;
-       long c;
-       for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-               last_values[c] = 0;
-               group_values[c] = 0;
-               group_counts[c] = 0;
-               group_options[c] = 0;
-               found_non_zero[c] = 0;
-       }
-
-
-       // -------------------------------------------------------------------------
-       // the main loop
-
-       time_t  now = rrdset_slot2time(st, start_at_slot),
-                       dt = st->update_every,
-                       group_start_t = 0;
-
-       if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld"
-                       , st->id
-                       , (uint32_t)after
-                       , stop_at_slot
-                       , (uint32_t)before
-                       , start_at_slot
-                       , (uint32_t)now
-                       , st->current_entry
-                       , st->entries
-                       );
-
-       r->group = group;
-       r->update_every = group * st->update_every;
-       r->before = now;
-       r->after = now;
-
-       //info("RRD2RRDR(): %s: STARTING", st->id);
-
-       long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
-       for(; !stop_now ; now -= dt, slot--, counter++) {
-               if(unlikely(slot < 0)) slot = st->entries - 1;
-               if(unlikely(slot == stop_at_slot)) stop_now = counter;
-
-               if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
-                               , st->id
-                               , slot
-                               , counter
-                               , group_count + 1
-                               , added
-                               , now
-                               , (group_count + 1 == group)?"PRINT":"  -  "
-                               , (now >= after && now <= before)?"RANGE":"  -  "
-                               );
-
-               // make sure we return data in the proper time range
-               if(unlikely(now > before)) continue;
-               if(unlikely(now < after)) break;
-
-               if(unlikely(group_count == 0)) {
-                       group_start_t = now;
-               }
-               group_count++;
-
-               if(unlikely(group_count == group)) {
-                       if(unlikely(added >= points)) break;
-                       add_this = 1;
-               }
-
-               // do the calculations
-               for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-                       storage_number n = rd->values[slot];
-                       if(unlikely(!does_storage_number_exist(n))) continue;
-
-                       group_counts[c]++;
-
-                       calculated_number value = unpack_storage_number(n);
-                       if(likely(value != 0.0)) {
-                               group_options[c] |= RRDR_NONZERO;
-                               found_non_zero[c] = 1;
-                       }
-
-                       if(unlikely(did_storage_number_reset(n)))
-                               group_options[c] |= RRDR_RESET;
-
-                       switch(group_method) {
-                               case GROUP_MAX:
-                                       if(unlikely(fabsl(value) > fabsl(group_values[c])))
-                                               group_values[c] = value;
-                                       break;
-
-                               default:
-                               case GROUP_SUM:
-                               case GROUP_AVERAGE:
-                                       group_values[c] += value;
-                                       break;
-
-                               case GROUP_INCREMENTAL_SUM:
-                                       if(unlikely(slot == start_at_slot))
-                                               last_values[c] = value;
-
-                                       group_values[c] += last_values[c] - value;
-                                       last_values[c] = value;
-                                       break;
-                       }
-               }
-
-               // added it
-               if(unlikely(add_this)) {
-                       if(unlikely(!rrdr_line_init(r, group_start_t))) break;
-
-                       r->after = now;
-
-                       calculated_number *cn = rrdr_line_values(r);
-                       uint8_t *co = rrdr_line_options(r);
-
-                       for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-
-                               // update the dimension options
-                               if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
-
-                               // store the specific point options
-                               co[c] = group_options[c];
-
-                               // store the value
-                               if(unlikely(group_counts[c] == 0)) {
-                                       cn[c] = 0.0;
-                                       co[c] |= RRDR_EMPTY;
-                               }
-                               else if(unlikely(group_method == GROUP_AVERAGE)) {
-                                       // GROUP_AVERAGE
-                                       cn[c] = group_values[c] / group_counts[c];
-                               }
-                               else {
-                                       // GROUP_SUM
-                                       // GROUP_MAX
-                                       // GROUP_INCREMENTAL_SUM
-                                       cn[c] = group_values[c];
-                               }
-
-                               if(cn[c] < r->min) r->min = cn[c];
-                               if(cn[c] > r->max) r->max = cn[c];
-
-                               // reset them for the next loop
-                               group_values[c] = 0;
-                               group_counts[c] = 0;
-                               group_options[c] = 0;
-                       }
-
-                       added++;
-                       group_count = 0;
-                       add_this = 0;
-               }
-       }
-
-       rrdr_done(r);
-       //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
-       //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
-       return r;
+        return r;
+    }
+
+    if(absolute_period_requested == 1)
+        r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
+    else
+        r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
+
+    // find how many dimensions we have
+    long dimensions = r->d;
+
+
+    // -------------------------------------------------------------------------
+    // checks for debugging
+
+    if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld"
+            , st->id
+            , (uint32_t)first_entry_t
+            , (uint32_t)last_entry_t
+            , (uint32_t)(last_entry_t - first_entry_t)
+            , (uint32_t)after
+            , (uint32_t)before
+            , (uint32_t)duration
+            , points
+            , group
+            );
+
+
+    // -------------------------------------------------------------------------
+    // temp arrays for keeping values per dimension
+
+    calculated_number   last_values[dimensions]; // keep the last value of each dimension
+    calculated_number   group_values[dimensions]; // keep sums when grouping
+    long                group_counts[dimensions]; // keep the number of values added to group_values
+    uint8_t             group_options[dimensions];
+    uint8_t             found_non_zero[dimensions];
+
+
+    // initialize them
+    RRDDIM *rd;
+    long c;
+    for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+        last_values[c] = 0;
+        group_values[c] = 0;
+        group_counts[c] = 0;
+        group_options[c] = 0;
+        found_non_zero[c] = 0;
+    }
+
+
+    // -------------------------------------------------------------------------
+    // the main loop
+
+    time_t  now = rrdset_slot2time(st, start_at_slot),
+            dt = st->update_every,
+            group_start_t = 0;
+
+    if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld"
+            , st->id
+            , (uint32_t)after
+            , stop_at_slot
+            , (uint32_t)before
+            , start_at_slot
+            , (uint32_t)now
+            , st->current_entry
+            , st->entries
+            );
+
+    r->group = group;
+    r->update_every = group * st->update_every;
+    r->before = now;
+    r->after = now;
+
+    //info("RRD2RRDR(): %s: STARTING", st->id);
+
+    long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
+    for(; !stop_now ; now -= dt, slot--, counter++) {
+        if(unlikely(slot < 0)) slot = st->entries - 1;
+        if(unlikely(slot == stop_at_slot)) stop_now = counter;
+
+        if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
+                , st->id
+                , slot
+                , counter
+                , group_count + 1
+                , added
+                , now
+                , (group_count + 1 == group)?"PRINT":"  -  "
+                , (now >= after && now <= before)?"RANGE":"  -  "
+                );
+
+        // make sure we return data in the proper time range
+        if(unlikely(now > before)) continue;
+        if(unlikely(now < after)) break;
+
+        if(unlikely(group_count == 0)) {
+            group_start_t = now;
+        }
+        group_count++;
+
+        if(unlikely(group_count == group)) {
+            if(unlikely(added >= points)) break;
+            add_this = 1;
+        }
+
+        // do the calculations
+        for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+            storage_number n = rd->values[slot];
+            if(unlikely(!does_storage_number_exist(n))) continue;
+
+            group_counts[c]++;
+
+            calculated_number value = unpack_storage_number(n);
+            if(likely(value != 0.0)) {
+                group_options[c] |= RRDR_NONZERO;
+                found_non_zero[c] = 1;
+            }
+
+            if(unlikely(did_storage_number_reset(n)))
+                group_options[c] |= RRDR_RESET;
+
+            switch(group_method) {
+                case GROUP_MAX:
+                    if(unlikely(fabsl(value) > fabsl(group_values[c])))
+                        group_values[c] = value;
+                    break;
+
+                default:
+                case GROUP_SUM:
+                case GROUP_AVERAGE:
+                    group_values[c] += value;
+                    break;
+
+                case GROUP_INCREMENTAL_SUM:
+                    if(unlikely(slot == start_at_slot))
+                        last_values[c] = value;
+
+                    group_values[c] += last_values[c] - value;
+                    last_values[c] = value;
+                    break;
+            }
+        }
+
+        // added it
+        if(unlikely(add_this)) {
+            if(unlikely(!rrdr_line_init(r, group_start_t))) break;
+
+            r->after = now;
+
+            calculated_number *cn = rrdr_line_values(r);
+            uint8_t *co = rrdr_line_options(r);
+
+            for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+
+                // update the dimension options
+                if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
+
+                // store the specific point options
+                co[c] = group_options[c];
+
+                // store the value
+                if(unlikely(group_counts[c] == 0)) {
+                    cn[c] = 0.0;
+                    co[c] |= RRDR_EMPTY;
+                }
+                else if(unlikely(group_method == GROUP_AVERAGE)) {
+                    // GROUP_AVERAGE
+                    cn[c] = group_values[c] / group_counts[c];
+                }
+                else {
+                    // GROUP_SUM
+                    // GROUP_MAX
+                    // GROUP_INCREMENTAL_SUM
+                    cn[c] = group_values[c];
+                }
+
+                if(cn[c] < r->min) r->min = cn[c];
+                if(cn[c] > r->max) r->max = cn[c];
+
+                // reset them for the next loop
+                group_values[c] = 0;
+                group_counts[c] = 0;
+                group_options[c] = 0;
+            }
+
+            added++;
+            group_count = 0;
+            add_this = 0;
+        }
+    }
+
+    rrdr_done(r);
+    //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
+    //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
+    return r;
 }
 
 int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, BUFFER *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp, int *value_is_null)
 {
-       RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
-       if(!r) {
-               if(value_is_null) *value_is_null = 1;
-               return 500;
-       }
+    RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
+    if(!r) {
+        if(value_is_null) *value_is_null = 1;
+        return 500;
+    }
 
-       if(rrdr_rows(r) == 0) {
-               rrdr_free(r);
-               if(value_is_null) *value_is_null = 1;
-               return 400;
-       }
+    if(rrdr_rows(r) == 0) {
+        rrdr_free(r);
+        if(value_is_null) *value_is_null = 1;
+        return 400;
+    }
 
-       if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
-               wb->options |= WB_CONTENT_NO_CACHEABLE;
-       else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
-               wb->options |= WB_CONTENT_CACHEABLE;
+    if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
+        wb->options |= WB_CONTENT_NO_CACHEABLE;
+    else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
+        wb->options |= WB_CONTENT_CACHEABLE;
 
-       options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
+    options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
 
-       if(dimensions)
-               rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
+    if(dimensions)
+        rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
 
-       if(latest_timestamp)
-               *latest_timestamp = r->before;
+    if(latest_timestamp)
+        *latest_timestamp = r->before;
 
-       long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
-       *n = rrdr2value(r, i, options, value_is_null);
+    long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
+    *n = rrdr2value(r, i, options, value_is_null);
 
-       rrdr_free(r);
-       return 200;
+    rrdr_free(r);
+    return 200;
 }
 
 int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
 {
-       RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
-       if(!r) {
-               buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
-               return 500;
-       }
-
-       if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
-               wb->options |= WB_CONTENT_NO_CACHEABLE;
-       else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
-               wb->options |= WB_CONTENT_CACHEABLE;
-
-       options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
-
-       if(dimensions)
-               rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
-
-       if(latest_timestamp && rrdr_rows(r) > 0)
-               *latest_timestamp = r->before;
-
-       switch(format) {
-       case DATASOURCE_SSV:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 1);
-                       rrdr2ssv(r, wb, options, "", " ", "");
-                       rrdr_json_wrapper_end(r, wb, format, options, 1);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_PLAIN;
-                       rrdr2ssv(r, wb, options, "", " ", "");
-               }
-               break;
-
-       case DATASOURCE_SSV_COMMA:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 1);
-                       rrdr2ssv(r, wb, options, "", ",", "");
-                       rrdr_json_wrapper_end(r, wb, format, options, 1);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_PLAIN;
-                       rrdr2ssv(r, wb, options, "", ",", "");
-               }
-               break;
-
-       case DATASOURCE_JS_ARRAY:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-                       rrdr2ssv(r, wb, options, "[", ",", "]");
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               }
-               else {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr2ssv(r, wb, options, "[", ",", "]");
-               }
-               break;
-
-       case DATASOURCE_CSV:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 1);
-                       rrdr2csv(r, wb, options, "", ",", "\\n", "");
-                       rrdr_json_wrapper_end(r, wb, format, options, 1);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_PLAIN;
-                       rrdr2csv(r, wb, options, "", ",", "\r\n", "");
-               }
-               break;
-
-       case DATASOURCE_CSV_JSON_ARRAY:
-               wb->contenttype = CT_APPLICATION_JSON;
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-                       buffer_strcat(wb, "[\n");
-                       rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
-                       buffer_strcat(wb, "\n]");
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_PLAIN;
-                       buffer_strcat(wb, "[\n");
-                       rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
-                       buffer_strcat(wb, "\n]");
-               }
-               break;
-
-       case DATASOURCE_TSV:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 1);
-                       rrdr2csv(r, wb, options, "", "\t", "\\n", "");
-                       rrdr_json_wrapper_end(r, wb, format, options, 1);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_PLAIN;
-                       rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
-               }
-               break;
-
-       case DATASOURCE_HTML:
-               if(options & RRDR_OPTION_JSON_WRAP) {
-                       wb->contenttype = CT_APPLICATION_JSON;
-                       rrdr_json_wrapper_begin(r, wb, format, options, 1);
-                       buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
-                       rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
-                       buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
-                       rrdr_json_wrapper_end(r, wb, format, options, 1);
-               }
-               else {
-                       wb->contenttype = CT_TEXT_HTML;
-                       buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
-                       rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
-                       buffer_strcat(wb, "</table>\n</center>\n</html>\n");
-               }
-               break;
-
-       case DATASOURCE_DATATABLE_JSONP:
-               wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-
-               rrdr2json(r, wb, options, 1);
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               break;
-
-       case DATASOURCE_DATATABLE_JSON:
-               wb->contenttype = CT_APPLICATION_JSON;
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-
-               rrdr2json(r, wb, options, 1);
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               break;
-
-       case DATASOURCE_JSONP:
-               wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-
-               rrdr2json(r, wb, options, 0);
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               break;
-
-       case DATASOURCE_JSON:
-       default:
-               wb->contenttype = CT_APPLICATION_JSON;
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_begin(r, wb, format, options, 0);
-
-               rrdr2json(r, wb, options, 0);
-
-               if(options & RRDR_OPTION_JSON_WRAP)
-                       rrdr_json_wrapper_end(r, wb, format, options, 0);
-               break;
-       }
-
-       rrdr_free(r);
-       return 200;
+    RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
+    if(!r) {
+        buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
+        return 500;
+    }
+
+    if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
+        wb->options |= WB_CONTENT_NO_CACHEABLE;
+    else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
+        wb->options |= WB_CONTENT_CACHEABLE;
+
+    options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
+
+    if(dimensions)
+        rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
+
+    if(latest_timestamp && rrdr_rows(r) > 0)
+        *latest_timestamp = r->before;
+
+    switch(format) {
+    case DATASOURCE_SSV:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 1);
+            rrdr2ssv(r, wb, options, "", " ", "");
+            rrdr_json_wrapper_end(r, wb, format, options, 1);
+        }
+        else {
+            wb->contenttype = CT_TEXT_PLAIN;
+            rrdr2ssv(r, wb, options, "", " ", "");
+        }
+        break;
+
+    case DATASOURCE_SSV_COMMA:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 1);
+            rrdr2ssv(r, wb, options, "", ",", "");
+            rrdr_json_wrapper_end(r, wb, format, options, 1);
+        }
+        else {
+            wb->contenttype = CT_TEXT_PLAIN;
+            rrdr2ssv(r, wb, options, "", ",", "");
+        }
+        break;
+
+    case DATASOURCE_JS_ARRAY:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+            rrdr2ssv(r, wb, options, "[", ",", "]");
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        }
+        else {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr2ssv(r, wb, options, "[", ",", "]");
+        }
+        break;
+
+    case DATASOURCE_CSV:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 1);
+            rrdr2csv(r, wb, options, "", ",", "\\n", "");
+            rrdr_json_wrapper_end(r, wb, format, options, 1);
+        }
+        else {
+            wb->contenttype = CT_TEXT_PLAIN;
+            rrdr2csv(r, wb, options, "", ",", "\r\n", "");
+        }
+        break;
+
+    case DATASOURCE_CSV_JSON_ARRAY:
+        wb->contenttype = CT_APPLICATION_JSON;
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+            buffer_strcat(wb, "[\n");
+            rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
+            buffer_strcat(wb, "\n]");
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        }
+        else {
+            wb->contenttype = CT_TEXT_PLAIN;
+            buffer_strcat(wb, "[\n");
+            rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
+            buffer_strcat(wb, "\n]");
+        }
+        break;
+
+    case DATASOURCE_TSV:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 1);
+            rrdr2csv(r, wb, options, "", "\t", "\\n", "");
+            rrdr_json_wrapper_end(r, wb, format, options, 1);
+        }
+        else {
+            wb->contenttype = CT_TEXT_PLAIN;
+            rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
+        }
+        break;
+
+    case DATASOURCE_HTML:
+        if(options & RRDR_OPTION_JSON_WRAP) {
+            wb->contenttype = CT_APPLICATION_JSON;
+            rrdr_json_wrapper_begin(r, wb, format, options, 1);
+            buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
+            rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
+            buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
+            rrdr_json_wrapper_end(r, wb, format, options, 1);
+        }
+        else {
+            wb->contenttype = CT_TEXT_HTML;
+            buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
+            rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
+            buffer_strcat(wb, "</table>\n</center>\n</html>\n");
+        }
+        break;
+
+    case DATASOURCE_DATATABLE_JSONP:
+        wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+
+        rrdr2json(r, wb, options, 1);
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        break;
+
+    case DATASOURCE_DATATABLE_JSON:
+        wb->contenttype = CT_APPLICATION_JSON;
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+
+        rrdr2json(r, wb, options, 1);
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        break;
+
+    case DATASOURCE_JSONP:
+        wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+
+        rrdr2json(r, wb, options, 0);
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        break;
+
+    case DATASOURCE_JSON:
+    default:
+        wb->contenttype = CT_APPLICATION_JSON;
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_begin(r, wb, format, options, 0);
+
+        rrdr2json(r, wb, options, 0);
+
+        if(options & RRDR_OPTION_JSON_WRAP)
+            rrdr_json_wrapper_end(r, wb, format, options, 0);
+        break;
+    }
+
+    rrdr_free(r);
+    return 200;
 }
 
 time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long points, long group, int group_method, time_t after, time_t before, int only_non_zero)
 {
-       int c;
-       pthread_rwlock_rdlock(&st->rwlock);
+    int c;
+    pthread_rwlock_rdlock(&st->rwlock);
 
 
-       // -------------------------------------------------------------------------
-       // switch from JSON to google JSON
+    // -------------------------------------------------------------------------
+    // switch from JSON to google JSON
 
-       char kq[2] = "\"";
-       char sq[2] = "\"";
-       switch(type) {
-               case DATASOURCE_DATATABLE_JSON:
-               case DATASOURCE_DATATABLE_JSONP:
-                       kq[0] = '\0';
-                       sq[0] = '\'';
-                       break;
+    char kq[2] = "\"";
+    char sq[2] = "\"";
+    switch(type) {
+        case DATASOURCE_DATATABLE_JSON:
+        case DATASOURCE_DATATABLE_JSONP:
+            kq[0] = '\0';
+            sq[0] = '\'';
+            break;
 
-               case DATASOURCE_JSON:
-               default:
-                       break;
-       }
+        case DATASOURCE_JSON:
+        default:
+            break;
+    }
 
 
-       // -------------------------------------------------------------------------
-       // validate the parameters
+    // -------------------------------------------------------------------------
+    // validate the parameters
 
-       if(points < 1) points = 1;
-       if(group < 1) group = 1;
+    if(points < 1) points = 1;
+    if(group < 1) group = 1;
 
-       if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
-       if(after  == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
+    if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
+    if(after  == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
 
-       // ---
+    // ---
 
-       // our return value (the last timestamp printed)
-       // this is required to detect re-transmit in google JSONP
-       time_t last_timestamp = 0;
+    // our return value (the last timestamp printed)
+    // this is required to detect re-transmit in google JSONP
+    time_t last_timestamp = 0;
 
 
-       // -------------------------------------------------------------------------
-       // find how many dimensions we have
+    // -------------------------------------------------------------------------
+    // find how many dimensions we have
 
-       int dimensions = 0;
-       RRDDIM *rd;
-       for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
-       if(!dimensions) {
-               pthread_rwlock_unlock(&st->rwlock);
-               buffer_strcat(wb, "No dimensions yet.");
-               return 0;
-       }
+    int dimensions = 0;
+    RRDDIM *rd;
+    for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
+    if(!dimensions) {
+        pthread_rwlock_unlock(&st->rwlock);
+        buffer_strcat(wb, "No dimensions yet.");
+        return 0;
+    }
 
 
-       // -------------------------------------------------------------------------
-       // prepare various strings, to speed up the loop
+    // -------------------------------------------------------------------------
+    // prepare various strings, to speed up the loop
 
-       char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
-       char normal_annotation[201];   snprintfz(normal_annotation,   200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
-       char pre_date[51];             snprintfz(pre_date,             50, "            {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
-       char post_date[21];            snprintfz(post_date,            20, "%s}", sq);
-       char pre_value[21];            snprintfz(pre_value,            20, ",{%sv%s:", kq, kq);
-       char post_value[21];           strcpy(post_value,                  "}");
+    char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
+    char normal_annotation[201];   snprintfz(normal_annotation,   200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
+    char pre_date[51];             snprintfz(pre_date,             50, "        {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
+    char post_date[21];            snprintfz(post_date,            20, "%s}", sq);
+    char pre_value[21];            snprintfz(pre_value,            20, ",{%sv%s:", kq, kq);
+    char post_value[21];           strcpy(post_value,                  "}");
 
 
-       // -------------------------------------------------------------------------
-       // checks for debugging
+    // -------------------------------------------------------------------------
+    // checks for debugging
 
-       if(st->debug) {
-               debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
-                       , st->id
-                       , rrdset_first_entry_t(st)
-                       , rrdset_last_entry_t(st)
-                       , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
-                       , after
-                       , before
-                       , before - after
-                       , points
-                       , group
-                       );
+    if(st->debug) {
+        debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
+            , st->id
+            , rrdset_first_entry_t(st)
+            , rrdset_last_entry_t(st)
+            , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
+            , after
+            , before
+            , before - after
+            , points
+            , group
+            );
 
-               if(before < after)
-                       debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
+        if(before < after)
+            debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
 
-               if((before - after) > st->entries * st->update_every)
-                       debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
-       }
-
-
-       // -------------------------------------------------------------------------
-       // temp arrays for keeping values per dimension
-
-       calculated_number group_values[dimensions]; // keep sums when grouping
-       int               print_hidden[dimensions]; // keep hidden flags
-       int               found_non_zero[dimensions];
-       int               found_non_existing[dimensions];
+        if((before - after) > st->entries * st->update_every)
+            debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
+    }
+
+
+    // -------------------------------------------------------------------------
+    // temp arrays for keeping values per dimension
+
+    calculated_number group_values[dimensions]; // keep sums when grouping
+    int               print_hidden[dimensions]; // keep hidden flags
+    int               found_non_zero[dimensions];
+    int               found_non_existing[dimensions];
 
-       // initialize them
-       for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-               group_values[c] = 0;
-               print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
-               found_non_zero[c] = 0;
-               found_non_existing[c] = 0;
-       }
+    // initialize them
+    for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+        group_values[c] = 0;
+        print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
+        found_non_zero[c] = 0;
+        found_non_existing[c] = 0;
+    }
 
 
-       // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
-       // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
-       // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
-
-       // -------------------------------------------------------------------------
-       // remove dimensions that contain only zeros
-
-       int max_loop = 1;
-       if(only_non_zero) max_loop = 2;
-
-       for(; max_loop ; max_loop--) {
-
-               // -------------------------------------------------------------------------
-               // print the JSON header
-
-               buffer_sprintf(wb, "{\n %scols%s:\n     [\n", kq, kq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-               buffer_sprintf(wb, "            {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
-
-               // print the header for each dimension
-               // and update the print_hidden array for the dimensions that should be hidden
-               int pc = 0;
-               for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-                       if(!print_hidden[c]) {
-                               pc++;
-                               buffer_sprintf(wb, ",\n         {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
-                       }
-               }
-               if(!pc) {
-                       buffer_sprintf(wb, ",\n         {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
-               }
-
-               // print the begin of row data
-               buffer_sprintf(wb, "\n  ],\n    %srows%s:\n     [\n", kq, kq);
-
-
-               // -------------------------------------------------------------------------
-               // the main loop
-
-               int annotate_reset = 0;
-               int annotation_count = 0;
-
-               long    t = rrdset_time2slot(st, before),
-                               stop_at_t = rrdset_time2slot(st, after),
-                               stop_now = 0;
-
-               t -= t % group;
-
-               time_t  now = rrdset_slot2time(st, t),
-                               dt = st->update_every;
-
-               long count = 0, printed = 0, group_count = 0;
-               last_timestamp = 0;
-
-               if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
-                                       , st->id
-                                       , (uint32_t)after
-                                       , (uint32_t)before
-                                       , points
-                                       , group
-                                       , st->current_entry
-                                       , (uint32_t)rrdset_first_entry_t(st)
-                                       , (uint32_t)rrdset_last_entry_t(st)
-                                       , t
-                                       , stop_at_t
-                                       );
-
-               long counter = 0;
-               for(; !stop_now ; now -= dt, t--, counter++) {
-                       if(t < 0) t = st->entries - 1;
-                       if(t == stop_at_t) stop_now = counter;
-
-                       int print_this = 0;
-
-                       if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
-                                       , st->id
-                                       , t
-                                       , count + 1
-                                       , group_count + 1
-                                       , printed
-                                       , now
-                                       , (group_count + 1 == group)?"PRINT":"  -  "
-                                       , (now >= after && now <= before)?"RANGE":"  -  "
-                                       );
-
-
-                       // make sure we return data in the proper time range
-                       if(now > before) continue;
-                       if(now < after) break;
-
-                       //if(rrdset_slot2time(st, t) != now)
-                       //      error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
-
-                       count++;
-                       group_count++;
-
-                       // check if we have to print this now
-                       if(group_count == group) {
-                               if(printed >= points) {
-                                       // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
-                                       break;
-                               }
-
-                               // generate the local date time
-                               struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
-                               if(!tm) { error("localtime() failed."); continue; }
-                               if(now > last_timestamp) last_timestamp = now;
-
-                               if(printed) buffer_strcat(wb, "]},\n");
-                               buffer_strcat(wb, pre_date);
-                               buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-                               buffer_strcat(wb, post_date);
-
-                               print_this = 1;
-                       }
-
-                       // do the calculations
-                       for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-                               storage_number n = rd->values[t];
-                               calculated_number value = unpack_storage_number(n);
-
-                               if(!does_storage_number_exist(n)) {
-                                       value = 0.0;
-                                       found_non_existing[c]++;
-                               }
-                               if(did_storage_number_reset(n)) annotate_reset = 1;
-
-                               switch(group_method) {
-                                       case GROUP_MAX:
-                                               if(abs(value) > abs(group_values[c])) group_values[c] = value;
-                                               break;
-
-                                       case GROUP_SUM:
-                                               group_values[c] += value;
-                                               break;
-
-                                       default:
-                                       case GROUP_AVERAGE:
-                                               group_values[c] += value;
-                                               if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
-                                               break;
-                               }
-                       }
-
-                       if(print_this) {
-                               if(annotate_reset) {
-                                       annotation_count++;
-                                       buffer_strcat(wb, overflow_annotation);
-                                       annotate_reset = 0;
-                               }
-                               else
-                                       buffer_strcat(wb, normal_annotation);
-
-                               pc = 0;
-                               for(c = 0 ; c < dimensions ; c++) {
-                                       if(found_non_existing[c] == group_count) {
-                                               // all entries are non-existing
-                                               pc++;
-                                               buffer_strcat(wb, pre_value);
-                                               buffer_strcat(wb, "null");
-                                               buffer_strcat(wb, post_value);
-                                       }
-                                       else if(!print_hidden[c]) {
-                                               pc++;
-                                               buffer_strcat(wb, pre_value);
-                                               buffer_rrd_value(wb, group_values[c]);
-                                               buffer_strcat(wb, post_value);
-
-                                               if(group_values[c]) found_non_zero[c]++;
-                                       }
-
-                                       // reset them for the next loop
-                                       group_values[c] = 0;
-                                       found_non_existing[c] = 0;
-                               }
-
-                               // if all dimensions are hidden, print a null
-                               if(!pc) {
-                                       buffer_strcat(wb, pre_value);
-                                       buffer_strcat(wb, "null");
-                                       buffer_strcat(wb, post_value);
-                               }
-
-                               printed++;
-                               group_count = 0;
-                       }
-               }
-
-               if(printed) buffer_strcat(wb, "]}");
-               buffer_strcat(wb, "\n   ]\n}\n");
-
-               if(only_non_zero && max_loop > 1) {
-                       int changed = 0;
-                       for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
-                               group_values[c] = 0;
-                               found_non_existing[c] = 0;
-
-                               if(!print_hidden[c] && !found_non_zero[c]) {
-                                       changed = 1;
-                                       print_hidden[c] = 1;
-                               }
-                       }
-
-                       if(changed) buffer_flush(wb);
-                       else break;
-               }
-               else break;
-
-       } // max_loop
-
-       debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
-
-       pthread_rwlock_unlock(&st->rwlock);
-       return last_timestamp;
+    // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
+    // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
+    // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
+
+    // -------------------------------------------------------------------------
+    // remove dimensions that contain only zeros
+
+    int max_loop = 1;
+    if(only_non_zero) max_loop = 2;
+
+    for(; max_loop ; max_loop--) {
+
+        // -------------------------------------------------------------------------
+        // print the JSON header
+
+        buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+        buffer_sprintf(wb, "        {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
+
+        // print the header for each dimension
+        // and update the print_hidden array for the dimensions that should be hidden
+        int pc = 0;
+        for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+            if(!print_hidden[c]) {
+                pc++;
+                buffer_sprintf(wb, ",\n     {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
+            }
+        }
+        if(!pc) {
+            buffer_sprintf(wb, ",\n     {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
+        }
+
+        // print the begin of row data
+        buffer_sprintf(wb, "\n  ],\n    %srows%s:\n [\n", kq, kq);
+
+
+        // -------------------------------------------------------------------------
+        // the main loop
+
+        int annotate_reset = 0;
+        int annotation_count = 0;
+
+        long    t = rrdset_time2slot(st, before),
+                stop_at_t = rrdset_time2slot(st, after),
+                stop_now = 0;
+
+        t -= t % group;
+
+        time_t  now = rrdset_slot2time(st, t),
+                dt = st->update_every;
+
+        long count = 0, printed = 0, group_count = 0;
+        last_timestamp = 0;
+
+        if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
+                    , st->id
+                    , (uint32_t)after
+                    , (uint32_t)before
+                    , points
+                    , group
+                    , st->current_entry
+                    , (uint32_t)rrdset_first_entry_t(st)
+                    , (uint32_t)rrdset_last_entry_t(st)
+                    , t
+                    , stop_at_t
+                    );
+
+        long counter = 0;
+        for(; !stop_now ; now -= dt, t--, counter++) {
+            if(t < 0) t = st->entries - 1;
+            if(t == stop_at_t) stop_now = counter;
+
+            int print_this = 0;
+
+            if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
+                    , st->id
+                    , t
+                    , count + 1
+                    , group_count + 1
+                    , printed
+                    , now
+                    , (group_count + 1 == group)?"PRINT":"  -  "
+                    , (now >= after && now <= before)?"RANGE":"  -  "
+                    );
+
+
+            // make sure we return data in the proper time range
+            if(now > before) continue;
+            if(now < after) break;
+
+            //if(rrdset_slot2time(st, t) != now)
+            //  error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
+
+            count++;
+            group_count++;
+
+            // check if we have to print this now
+            if(group_count == group) {
+                if(printed >= points) {
+                    // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
+                    break;
+                }
+
+                // generate the local date time
+                struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
+                if(!tm) { error("localtime() failed."); continue; }
+                if(now > last_timestamp) last_timestamp = now;
+
+                if(printed) buffer_strcat(wb, "]},\n");
+                buffer_strcat(wb, pre_date);
+                buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+                buffer_strcat(wb, post_date);
+
+                print_this = 1;
+            }
+
+            // do the calculations
+            for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+                storage_number n = rd->values[t];
+                calculated_number value = unpack_storage_number(n);
+
+                if(!does_storage_number_exist(n)) {
+                    value = 0.0;
+                    found_non_existing[c]++;
+                }
+                if(did_storage_number_reset(n)) annotate_reset = 1;
+
+                switch(group_method) {
+                    case GROUP_MAX:
+                        if(abs(value) > abs(group_values[c])) group_values[c] = value;
+                        break;
+
+                    case GROUP_SUM:
+                        group_values[c] += value;
+                        break;
+
+                    default:
+                    case GROUP_AVERAGE:
+                        group_values[c] += value;
+                        if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
+                        break;
+                }
+            }
+
+            if(print_this) {
+                if(annotate_reset) {
+                    annotation_count++;
+                    buffer_strcat(wb, overflow_annotation);
+                    annotate_reset = 0;
+                }
+                else
+                    buffer_strcat(wb, normal_annotation);
+
+                pc = 0;
+                for(c = 0 ; c < dimensions ; c++) {
+                    if(found_non_existing[c] == group_count) {
+                        // all entries are non-existing
+                        pc++;
+                        buffer_strcat(wb, pre_value);
+                        buffer_strcat(wb, "null");
+                        buffer_strcat(wb, post_value);
+                    }
+                    else if(!print_hidden[c]) {
+                        pc++;
+                        buffer_strcat(wb, pre_value);
+                        buffer_rrd_value(wb, group_values[c]);
+                        buffer_strcat(wb, post_value);
+
+                        if(group_values[c]) found_non_zero[c]++;
+                    }
+
+                    // reset them for the next loop
+                    group_values[c] = 0;
+                    found_non_existing[c] = 0;
+                }
+
+                // if all dimensions are hidden, print a null
+                if(!pc) {
+                    buffer_strcat(wb, pre_value);
+                    buffer_strcat(wb, "null");
+                    buffer_strcat(wb, post_value);
+                }
+
+                printed++;
+                group_count = 0;
+            }
+        }
+
+        if(printed) buffer_strcat(wb, "]}");
+        buffer_strcat(wb, "\n   ]\n}\n");
+
+        if(only_non_zero && max_loop > 1) {
+            int changed = 0;
+            for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
+                group_values[c] = 0;
+                found_non_existing[c] = 0;
+
+                if(!print_hidden[c] && !found_non_zero[c]) {
+                    changed = 1;
+                    print_hidden[c] = 1;
+                }
+            }
+
+            if(changed) buffer_flush(wb);
+            else break;
+        }
+        else break;
+
+    } // max_loop
+
+    debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
+
+    pthread_rwlock_unlock(&st->rwlock);
+    return last_timestamp;
 }
index bb7b04064971f402a9de756d4ae84185261c4746..929ac1d52f09257c8241095810d25a536efdfed4 100644 (file)
@@ -30,24 +30,24 @@ extern char *hostname;
 #define DATASOURCE_FORMAT_SSV_COMMA "ssvcomma"
 #define DATASOURCE_FORMAT_CSV_JSON_ARRAY "csvjsonarray"
 
-#define GROUP_AVERAGE                  0
-#define GROUP_MAX                              1
-#define GROUP_SUM                              2
-#define GROUP_INCREMENTAL_SUM  3
+#define GROUP_AVERAGE           0
+#define GROUP_MAX               1
+#define GROUP_SUM               2
+#define GROUP_INCREMENTAL_SUM   3
 
-#define RRDR_OPTION_NONZERO            0x00000001 // don't output dimensions will just zero values
-#define RRDR_OPTION_REVERSED           0x00000002 // output the rows in reverse order (oldest to newest)
-#define RRDR_OPTION_ABSOLUTE           0x00000004 // values positive, for DATASOURCE_SSV before summing
-#define RRDR_OPTION_MIN2MAX                    0x00000008 // when adding dimensions, use max - min, instead of sum
-#define RRDR_OPTION_SECONDS                    0x00000010 // output seconds, instead of dates
-#define RRDR_OPTION_MILLISECONDS       0x00000020 // output milliseconds, instead of dates
-#define RRDR_OPTION_NULL2ZERO          0x00000040 // do not show nulls, convert them to zeros
-#define RRDR_OPTION_OBJECTSROWS                0x00000080 // each row of values should be an object, not an array
-#define RRDR_OPTION_GOOGLE_JSON                0x00000100 // comply with google JSON/JSONP specs
-#define RRDR_OPTION_JSON_WRAP          0x00000200 // wrap the response in a JSON header with info about the result
-#define RRDR_OPTION_LABEL_QUOTES       0x00000400 // in CSV output, wrap header labels in double quotes
-#define RRDR_OPTION_PERCENTAGE         0x00000800 // give values as percentage of total
-#define RRDR_OPTION_NOT_ALIGNED                0x00001000 // do not align charts for persistant timeframes
+#define RRDR_OPTION_NONZERO         0x00000001 // don't output dimensions will just zero values
+#define RRDR_OPTION_REVERSED        0x00000002 // output the rows in reverse order (oldest to newest)
+#define RRDR_OPTION_ABSOLUTE        0x00000004 // values positive, for DATASOURCE_SSV before summing
+#define RRDR_OPTION_MIN2MAX         0x00000008 // when adding dimensions, use max - min, instead of sum
+#define RRDR_OPTION_SECONDS         0x00000010 // output seconds, instead of dates
+#define RRDR_OPTION_MILLISECONDS    0x00000020 // output milliseconds, instead of dates
+#define RRDR_OPTION_NULL2ZERO       0x00000040 // do not show nulls, convert them to zeros
+#define RRDR_OPTION_OBJECTSROWS     0x00000080 // each row of values should be an object, not an array
+#define RRDR_OPTION_GOOGLE_JSON     0x00000100 // comply with google JSON/JSONP specs
+#define RRDR_OPTION_JSON_WRAP       0x00000200 // wrap the response in a JSON header with info about the result
+#define RRDR_OPTION_LABEL_QUOTES    0x00000400 // in CSV output, wrap header labels in double quotes
+#define RRDR_OPTION_PERCENTAGE      0x00000800 // give values as percentage of total
+#define RRDR_OPTION_NOT_ALIGNED     0x00001000 // do not align charts for persistant timeframes
 
 extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
 extern void rrd_stats_api_v1_charts(BUFFER *wb);
index 70eb638462825dc1faa3585a13a0ccdf76e3e7d6..27fe5f2c722a20a62b0e0dcd45d19c48eb632840 100644 (file)
@@ -5,164 +5,164 @@ extern char *print_number_llu_r(char *str, unsigned long long uvalue);
 
 storage_number pack_storage_number(calculated_number value, uint32_t flags)
 {
-       // bit 32 = sign 0:positive, 1:negative
-       // bit 31 = 0:divide, 1:multiply
-       // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
-       // bit 27, 26, 25 flags
-       // bit 24 to bit 1 = the value
-
-       storage_number r = get_storage_number_flags(flags);
-       if(!value) return r;
-
-       int m = 0;
-       calculated_number n = value;
-
-       // if the value is negative
-       // add the sign bit and make it positive
-       if(n < 0) {
-               r += (1 << 31); // the sign bit 32
-               n = -n;
-       }
-
-       // make its integer part fit in 0x00ffffff
-       // by dividing it by 10 up to 7 times
-       // and increasing the multiplier
-       while(m < 7 && n > (calculated_number)0x00ffffff) {
-               n /= 10;
-               m++;
-       }
-
-       if(m) {
-               // the value was too big and we divided it
-               // so we add a multiplier to unpack it
-               r += (1 << 30) + (m << 27); // the multiplier m
-
-               if(n > (calculated_number)0x00ffffff) {
-                       error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
-                       r += 0x00ffffff;
-                       return r;
-               }
-       }
-       else {
-               // 0x0019999e is the number that can be multiplied
-               // by 10 to give 0x00ffffff
-               // while the value is below 0x0019999e we can
-               // multiply it by 10, up to 7 times, increasing
-               // the multiplier
-               while(m < 7 && n < (calculated_number)0x0019999e) {
-                       n *= 10;
-                       m++;
-               }
-
-               // the value was small enough and we multiplied it
-               // so we add a divider to unpack it
-               r += (0 << 30) + (m << 27); // the divider m
-       }
+    // bit 32 = sign 0:positive, 1:negative
+    // bit 31 = 0:divide, 1:multiply
+    // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
+    // bit 27, 26, 25 flags
+    // bit 24 to bit 1 = the value
+
+    storage_number r = get_storage_number_flags(flags);
+    if(!value) return r;
+
+    int m = 0;
+    calculated_number n = value;
+
+    // if the value is negative
+    // add the sign bit and make it positive
+    if(n < 0) {
+        r += (1 << 31); // the sign bit 32
+        n = -n;
+    }
+
+    // make its integer part fit in 0x00ffffff
+    // by dividing it by 10 up to 7 times
+    // and increasing the multiplier
+    while(m < 7 && n > (calculated_number)0x00ffffff) {
+        n /= 10;
+        m++;
+    }
+
+    if(m) {
+        // the value was too big and we divided it
+        // so we add a multiplier to unpack it
+        r += (1 << 30) + (m << 27); // the multiplier m
+
+        if(n > (calculated_number)0x00ffffff) {
+            error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
+            r += 0x00ffffff;
+            return r;
+        }
+    }
+    else {
+        // 0x0019999e is the number that can be multiplied
+        // by 10 to give 0x00ffffff
+        // while the value is below 0x0019999e we can
+        // multiply it by 10, up to 7 times, increasing
+        // the multiplier
+        while(m < 7 && n < (calculated_number)0x0019999e) {
+            n *= 10;
+            m++;
+        }
+
+        // the value was small enough and we multiplied it
+        // so we add a divider to unpack it
+        r += (0 << 30) + (m << 27); // the divider m
+    }
 
 #ifdef STORAGE_WITH_MATH
-       // without this there are rounding problems
-       // example: 0.9 becomes 0.89
-       r += lrint((double) n);
+    // without this there are rounding problems
+    // example: 0.9 becomes 0.89
+    r += lrint((double) n);
 #else
-       r += (storage_number)n;
+    r += (storage_number)n;
 #endif
 
-       return r;
+    return r;
 }
 
 calculated_number unpack_storage_number(storage_number value)
 {
-       if(!value) return 0;
+    if(!value) return 0;
 
-       int sign = 0, exp = 0;
+    int sign = 0, exp = 0;
 
-       value ^= get_storage_number_flags(value);
+    value ^= get_storage_number_flags(value);
 
-       if(value & (1 << 31)) {
-               sign = 1;
-               value ^= 1 << 31;
-       }
+    if(value & (1 << 31)) {
+        sign = 1;
+        value ^= 1 << 31;
+    }
 
-       if(value & (1 << 30)) {
-               exp = 1;
-               value ^= 1 << 30;
-       }
+    if(value & (1 << 30)) {
+        exp = 1;
+        value ^= 1 << 30;
+    }
 
-       int mul = value >> 27;
-       value ^= mul << 27;
+    int mul = value >> 27;
+    value ^= mul << 27;
 
-       calculated_number n = value;
+    calculated_number n = value;
 
-       // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
+    // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
 
-       while(mul > 0) {
-               if(exp) n *= 10;
-               else n /= 10;
-               mul--;
-       }
+    while(mul > 0) {
+        if(exp) n *= 10;
+        else n /= 10;
+        mul--;
+    }
 
-       if(sign) n = -n;
-       return n;
+    if(sign) n = -n;
+    return n;
 }
 
 int print_calculated_number(char *str, calculated_number value)
 {
-       char *wstr = str;
+    char *wstr = str;
 
-       int sign = (value < 0) ? 1 : 0;
-       if(sign) value = -value;
+    int sign = (value < 0) ? 1 : 0;
+    if(sign) value = -value;
 
 #ifdef STORAGE_WITH_MATH
-       // without llrint() there are rounding problems
-       // for example 0.9 becomes 0.89
-       unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
+    // without llrint() there are rounding problems
+    // for example 0.9 becomes 0.89
+    unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
 #else
-       unsigned long long uvalue = value * (calculated_number)100000;
+    unsigned long long uvalue = value * (calculated_number)100000;
 #endif
 
 #ifdef ENVIRONMENT32
-       if(uvalue > (unsigned long long)0xffffffff)
-               wstr = print_number_llu_r(str, uvalue);
-       else
-               wstr = print_number_lu_r(str, uvalue);
+    if(uvalue > (unsigned long long)0xffffffff)
+        wstr = print_number_llu_r(str, uvalue);
+    else
+        wstr = print_number_lu_r(str, uvalue);
 #else
-       do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
+    do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
 #endif
 
-       // make sure we have 6 bytes at least
-       while((wstr - str) < 6) *wstr++ = '0';
+    // make sure we have 6 bytes at least
+    while((wstr - str) < 6) *wstr++ = '0';
 
-       // put the sign back
-       if(sign) *wstr++ = '-';
+    // put the sign back
+    if(sign) *wstr++ = '-';
 
-       // reverse it
+    // reverse it
     char *begin = str, *end = --wstr, aux;
     while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
-       // wstr--;
-       // strreverse(str, wstr);
-
-       // remove trailing zeros
-       int decimal = 5;
-       while(decimal > 0 && *wstr == '0') {
-               *wstr-- = '\0';
-               decimal--;
-       }
-
-       // terminate it, one position to the right
-       // to let space for a dot
-       wstr[2] = '\0';
-
-       // make space for the dot
-       int i;
-       for(i = 0; i < decimal ;i++) {
-               wstr[1] = wstr[0];
-               wstr--;
-       }
-
-       // put the dot
-       if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
-       else wstr[1] = '.';
-
-       // return the buffer length
-       return (int) ((wstr - str) + 2 + decimal );
+    // wstr--;
+    // strreverse(str, wstr);
+
+    // remove trailing zeros
+    int decimal = 5;
+    while(decimal > 0 && *wstr == '0') {
+        *wstr-- = '\0';
+        decimal--;
+    }
+
+    // terminate it, one position to the right
+    // to let space for a dot
+    wstr[2] = '\0';
+
+    // make space for the dot
+    int i;
+    for(i = 0; i < decimal ;i++) {
+        wstr[1] = wstr[0];
+        wstr--;
+    }
+
+    // put the dot
+    if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
+    else wstr[1] = '.';
+
+    // return the buffer length
+    return (int) ((wstr - str) + 2 + decimal );
 }
index 7ff839433f8639a655b029b88b2f503630720d1c..74d24a322719ef6384d76f22300943b8aa52addb 100644 (file)
@@ -17,15 +17,15 @@ typedef long double collected_number;
 typedef uint32_t storage_number;
 #define STORAGE_NUMBER_FORMAT "%u"
 
-#define SN_NOT_EXISTS          (0x0 << 24)
-#define SN_EXISTS                      (0x1 << 24)
-#define SN_EXISTS_RESET                (0x2 << 24)
-#define SN_EXISTS_UNDEF1       (0x3 << 24)
-#define SN_EXISTS_UNDEF2       (0x4 << 24)
-#define SN_EXISTS_UNDEF3       (0x5 << 24)
-#define SN_EXISTS_UNDEF4       (0x6 << 24)
-
-#define SN_FLAGS_MASK          (~(0x6 << 24))
+#define SN_NOT_EXISTS       (0x0 << 24)
+#define SN_EXISTS           (0x1 << 24)
+#define SN_EXISTS_RESET     (0x2 << 24)
+#define SN_EXISTS_UNDEF1    (0x3 << 24)
+#define SN_EXISTS_UNDEF2    (0x4 << 24)
+#define SN_EXISTS_UNDEF3    (0x5 << 24)
+#define SN_EXISTS_UNDEF4    (0x6 << 24)
+
+#define SN_FLAGS_MASK       (~(0x6 << 24))
 
 // extract the flags
 #define get_storage_number_flags(value) ((((storage_number)value) & (1 << 24)) | (((storage_number)value) & (2 << 24)) | (((storage_number)value) & (4 << 24)))
index 72d2dc263b2e24c3cf918c89d34783f55ddfd30c..616b806f678ef3136a573ea39cc7db15c3be7821 100644 (file)
@@ -20,171 +20,171 @@ static int cgroup_root_max = 500;
 static int cgroup_max_depth = 0;
 
 void read_cgroup_plugin_configuration() {
-       cgroup_check_for_new_every = config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every);
-
-       cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat", cgroup_enable_cpuacct_stat);
-       cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage", cgroup_enable_cpuacct_usage);
-       cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
-       cgroup_enable_blkio = config_get_boolean_ondemand("plugin:cgroups", "enable blkio", cgroup_enable_blkio);
-
-       char filename[FILENAME_MAX + 1], *s;
-       struct mountinfo *mi, *root = mountinfo_read();
-
-       mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
-       if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
-       if(!mi) {
-               error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
-               s = "/sys/fs/cgroup/cpuacct";
-       }
-       else s = mi->mount_point;
-       snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
-       cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
-
-       mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
-       if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
-       if(!mi) {
-               error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
-               s = "/sys/fs/cgroup/blkio";
-       }
-       else s = mi->mount_point;
-       snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
-       cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
-
-       mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
-       if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
-       if(!mi) {
-               error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
-               s = "/sys/fs/cgroup/memory";
-       }
-       else s = mi->mount_point;
-       snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
-       cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
-
-       mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
-       if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
-       if(!mi) {
-               error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
-               s = "/sys/fs/cgroup/devices";
-       }
-       else s = mi->mount_point;
-       snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
-       cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
-
-       cgroup_root_max = config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
-       cgroup_max_depth = config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
-
-       cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime);
-
-       mountinfo_free(root);
+    cgroup_check_for_new_every = config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every);
+
+    cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat", cgroup_enable_cpuacct_stat);
+    cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage", cgroup_enable_cpuacct_usage);
+    cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
+    cgroup_enable_blkio = config_get_boolean_ondemand("plugin:cgroups", "enable blkio", cgroup_enable_blkio);
+
+    char filename[FILENAME_MAX + 1], *s;
+    struct mountinfo *mi, *root = mountinfo_read();
+
+    mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
+    if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
+    if(!mi) {
+        error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
+        s = "/sys/fs/cgroup/cpuacct";
+    }
+    else s = mi->mount_point;
+    snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+    cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
+
+    mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
+    if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
+    if(!mi) {
+        error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
+        s = "/sys/fs/cgroup/blkio";
+    }
+    else s = mi->mount_point;
+    snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+    cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
+
+    mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
+    if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
+    if(!mi) {
+        error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
+        s = "/sys/fs/cgroup/memory";
+    }
+    else s = mi->mount_point;
+    snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+    cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
+
+    mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
+    if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
+    if(!mi) {
+        error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
+        s = "/sys/fs/cgroup/devices";
+    }
+    else s = mi->mount_point;
+    snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
+    cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
+
+    cgroup_root_max = config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
+    cgroup_max_depth = config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
+
+    cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime);
+
+    mountinfo_free(root);
 }
 
 // ----------------------------------------------------------------------------
 // cgroup objects
 
 struct blkio {
-       int updated;
+    int updated;
 
-       char *filename;
+    char *filename;
 
-       unsigned long long Read;
-       unsigned long long Write;
+    unsigned long long Read;
+    unsigned long long Write;
 /*
-       unsigned long long Sync;
-       unsigned long long Async;
-       unsigned long long Total;
+    unsigned long long Sync;
+    unsigned long long Async;
+    unsigned long long Total;
 */
 };
 
 // https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
 struct memory {
-       int updated;
-
-       char *filename;
-
-       int has_dirty_swap;
-
-       unsigned long long cache;
-       unsigned long long rss;
-       unsigned long long rss_huge;
-       unsigned long long mapped_file;
-       unsigned long long writeback;
-       unsigned long long dirty;
-       unsigned long long swap;
-       unsigned long long pgpgin;
-       unsigned long long pgpgout;
-       unsigned long long pgfault;
-       unsigned long long pgmajfault;
+    int updated;
+
+    char *filename;
+
+    int has_dirty_swap;
+
+    unsigned long long cache;
+    unsigned long long rss;
+    unsigned long long rss_huge;
+    unsigned long long mapped_file;
+    unsigned long long writeback;
+    unsigned long long dirty;
+    unsigned long long swap;
+    unsigned long long pgpgin;
+    unsigned long long pgpgout;
+    unsigned long long pgfault;
+    unsigned long long pgmajfault;
 /*
-       unsigned long long inactive_anon;
-       unsigned long long active_anon;
-       unsigned long long inactive_file;
-       unsigned long long active_file;
-       unsigned long long unevictable;
-       unsigned long long hierarchical_memory_limit;
-       unsigned long long total_cache;
-       unsigned long long total_rss;
-       unsigned long long total_rss_huge;
-       unsigned long long total_mapped_file;
-       unsigned long long total_writeback;
-       unsigned long long total_dirty;
-       unsigned long long total_swap;
-       unsigned long long total_pgpgin;
-       unsigned long long total_pgpgout;
-       unsigned long long total_pgfault;
-       unsigned long long total_pgmajfault;
-       unsigned long long total_inactive_anon;
-       unsigned long long total_active_anon;
-       unsigned long long total_inactive_file;
-       unsigned long long total_active_file;
-       unsigned long long total_unevictable;
+    unsigned long long inactive_anon;
+    unsigned long long active_anon;
+    unsigned long long inactive_file;
+    unsigned long long active_file;
+    unsigned long long unevictable;
+    unsigned long long hierarchical_memory_limit;
+    unsigned long long total_cache;
+    unsigned long long total_rss;
+    unsigned long long total_rss_huge;
+    unsigned long long total_mapped_file;
+    unsigned long long total_writeback;
+    unsigned long long total_dirty;
+    unsigned long long total_swap;
+    unsigned long long total_pgpgin;
+    unsigned long long total_pgpgout;
+    unsigned long long total_pgfault;
+    unsigned long long total_pgmajfault;
+    unsigned long long total_inactive_anon;
+    unsigned long long total_active_anon;
+    unsigned long long total_inactive_file;
+    unsigned long long total_active_file;
+    unsigned long long total_unevictable;
 */
 };
 
 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
 struct cpuacct_stat {
-       int updated;
+    int updated;
 
-       char *filename;
+    char *filename;
 
-       unsigned long long user;
-       unsigned long long system;
+    unsigned long long user;
+    unsigned long long system;
 };
 
 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
 struct cpuacct_usage {
-       int updated;
+    int updated;
 
-       char *filename;
+    char *filename;
 
-       unsigned int cpus;
-       unsigned long long *cpu_percpu;
+    unsigned int cpus;
+    unsigned long long *cpu_percpu;
 };
 
 struct cgroup {
-       int available;          // found in the filesystem
-       int enabled;            // enabled in the config
+    int available;      // found in the filesystem
+    int enabled;        // enabled in the config
 
-       char *id;
-       uint32_t hash;
+    char *id;
+    uint32_t hash;
 
-       char *chart_id;
-       char *chart_title;
+    char *chart_id;
+    char *chart_title;
 
-       struct cpuacct_stat cpuacct_stat;
-       struct cpuacct_usage cpuacct_usage;
+    struct cpuacct_stat cpuacct_stat;
+    struct cpuacct_usage cpuacct_usage;
 
-       struct memory memory;
+    struct memory memory;
 
-       struct blkio io_service_bytes;                          // bytes
-       struct blkio io_serviced;                                       // operations
+    struct blkio io_service_bytes;              // bytes
+    struct blkio io_serviced;                   // operations
 
-       struct blkio throttle_io_service_bytes;         // bytes
-       struct blkio throttle_io_serviced;                      // operations
+    struct blkio throttle_io_service_bytes;     // bytes
+    struct blkio throttle_io_serviced;          // operations
 
-       struct blkio io_merged;                                         // operations
-       struct blkio io_queued;                                         // operations
+    struct blkio io_merged;                     // operations
+    struct blkio io_queued;                     // operations
 
-       struct cgroup *next;
+    struct cgroup *next;
 
 } *cgroup_root = NULL;
 
@@ -192,389 +192,389 @@ struct cgroup {
 // read values from /sys
 
 void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
-       static procfile *ff = NULL;
+    static procfile *ff = NULL;
 
-       static uint32_t user_hash = 0;
-       static uint32_t system_hash = 0;
+    static uint32_t user_hash = 0;
+    static uint32_t system_hash = 0;
 
-       if(unlikely(user_hash == 0)) {
-               user_hash = simple_hash("user");
-               system_hash = simple_hash("system");
-       }
+    if(unlikely(user_hash == 0)) {
+        user_hash = simple_hash("user");
+        system_hash = simple_hash("system");
+    }
 
-       cp->updated = 0;
-       if(cp->filename) {
-               ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
-               if(!ff) return;
+    cp->updated = 0;
+    if(cp->filename) {
+        ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
+        if(!ff) return;
 
-               ff = procfile_readall(ff);
-               if(!ff) return;
+        ff = procfile_readall(ff);
+        if(!ff) return;
 
-               unsigned long i, lines = procfile_lines(ff);
+        unsigned long i, lines = procfile_lines(ff);
 
-               if(lines < 1) {
-                       error("File '%s' should have 1+ lines.", cp->filename);
-                       return;
-               }
+        if(lines < 1) {
+            error("File '%s' should have 1+ lines.", cp->filename);
+            return;
+        }
 
-               for(i = 0; i < lines ; i++) {
-                       char *s = procfile_lineword(ff, i, 0);
-                       uint32_t hash = simple_hash(s);
+        for(i = 0; i < lines ; i++) {
+            char *s = procfile_lineword(ff, i, 0);
+            uint32_t hash = simple_hash(s);
 
-                       if(hash == user_hash && !strcmp(s, "user"))
-                               cp->user = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            if(hash == user_hash && !strcmp(s, "user"))
+                cp->user = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == system_hash && !strcmp(s, "system"))
-                               cp->system = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
-               }
+            else if(hash == system_hash && !strcmp(s, "system"))
+                cp->system = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+        }
 
-               cp->updated = 1;
+        cp->updated = 1;
 
-               // fprintf(stderr, "READ '%s': user: %llu, system: %llu\n", cp->filename, cp->user, cp->system);
-       }
+        // fprintf(stderr, "READ '%s': user: %llu, system: %llu\n", cp->filename, cp->user, cp->system);
+    }
 }
 
 void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
-       static procfile *ff = NULL;
-
-       ca->updated = 0;
-       if(ca->filename) {
-               ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
-               if(!ff) return;
-
-               ff = procfile_readall(ff);
-               if(!ff) return;
-
-               if(procfile_lines(ff) < 1) {
-                       error("File '%s' should have 1+ lines but has %u.", ca->filename, procfile_lines(ff));
-                       return;
-               }
-
-               unsigned long i = procfile_linewords(ff, 0);
-               if(i <= 0) return;
-
-               // we may have 1 more CPU reported
-               while(i > 0) {
-                       char *s = procfile_lineword(ff, 0, i - 1);
-                       if(!*s) i--;
-                       else break;
-               }
-
-               if(i != ca->cpus) {
-                       freez(ca->cpu_percpu);
-                       ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
-                       ca->cpus = (unsigned int)i;
-               }
-
-               for(i = 0; i < ca->cpus ;i++) {
-                       ca->cpu_percpu[i] = strtoull(procfile_lineword(ff, 0, i), NULL, 10);
-                       // fprintf(stderr, "READ '%s': cpu%d/%d: %llu ('%s')\n", ca->filename, i, ca->cpus, ca->cpu_percpu[i], procfile_lineword(ff, 0, i));
-               }
-
-               ca->updated = 1;
-       }
+    static procfile *ff = NULL;
+
+    ca->updated = 0;
+    if(ca->filename) {
+        ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
+        if(!ff) return;
+
+        ff = procfile_readall(ff);
+        if(!ff) return;
+
+        if(procfile_lines(ff) < 1) {
+            error("File '%s' should have 1+ lines but has %u.", ca->filename, procfile_lines(ff));
+            return;
+        }
+
+        unsigned long i = procfile_linewords(ff, 0);
+        if(i <= 0) return;
+
+        // we may have 1 more CPU reported
+        while(i > 0) {
+            char *s = procfile_lineword(ff, 0, i - 1);
+            if(!*s) i--;
+            else break;
+        }
+
+        if(i != ca->cpus) {
+            freez(ca->cpu_percpu);
+            ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
+            ca->cpus = (unsigned int)i;
+        }
+
+        for(i = 0; i < ca->cpus ;i++) {
+            ca->cpu_percpu[i] = strtoull(procfile_lineword(ff, 0, i), NULL, 10);
+            // fprintf(stderr, "READ '%s': cpu%d/%d: %llu ('%s')\n", ca->filename, i, ca->cpus, ca->cpu_percpu[i], procfile_lineword(ff, 0, i));
+        }
+
+        ca->updated = 1;
+    }
 }
 
 void cgroup_read_blkio(struct blkio *io) {
-       static procfile *ff = NULL;
+    static procfile *ff = NULL;
 
-       static uint32_t Read_hash = 0;
-       static uint32_t Write_hash = 0;
+    static uint32_t Read_hash = 0;
+    static uint32_t Write_hash = 0;
 /*
-       static uint32_t Sync_hash = 0;
-       static uint32_t Async_hash = 0;
-       static uint32_t Total_hash = 0;
+    static uint32_t Sync_hash = 0;
+    static uint32_t Async_hash = 0;
+    static uint32_t Total_hash = 0;
 */
 
-       if(unlikely(Read_hash == 0)) {
-               Read_hash = simple_hash("Read");
-               Write_hash = simple_hash("Write");
+    if(unlikely(Read_hash == 0)) {
+        Read_hash = simple_hash("Read");
+        Write_hash = simple_hash("Write");
 /*
-               Sync_hash = simple_hash("Sync");
-               Async_hash = simple_hash("Async");
-               Total_hash = simple_hash("Total");
+        Sync_hash = simple_hash("Sync");
+        Async_hash = simple_hash("Async");
+        Total_hash = simple_hash("Total");
 */
-       }
+    }
 
-       io->updated = 0;
-       if(io->filename) {
-               ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
-               if(!ff) return;
+    io->updated = 0;
+    if(io->filename) {
+        ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
+        if(!ff) return;
 
-               ff = procfile_readall(ff);
-               if(!ff) return;
+        ff = procfile_readall(ff);
+        if(!ff) return;
 
-               unsigned long i, lines = procfile_lines(ff);
+        unsigned long i, lines = procfile_lines(ff);
 
-               if(lines < 1) {
-                       error("File '%s' should have 1+ lines.", io->filename);
-                       return;
-               }
+        if(lines < 1) {
+            error("File '%s' should have 1+ lines.", io->filename);
+            return;
+        }
 
-               io->Read = 0;
-               io->Write = 0;
+        io->Read = 0;
+        io->Write = 0;
 /*
-               io->Sync = 0;
-               io->Async = 0;
-               io->Total = 0;
+        io->Sync = 0;
+        io->Async = 0;
+        io->Total = 0;
 */
 
-               for(i = 0; i < lines ; i++) {
-                       char *s = procfile_lineword(ff, i, 1);
-                       uint32_t hash = simple_hash(s);
+        for(i = 0; i < lines ; i++) {
+            char *s = procfile_lineword(ff, i, 1);
+            uint32_t hash = simple_hash(s);
 
-                       if(hash == Read_hash && !strcmp(s, "Read"))
-                               io->Read += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
+            if(hash == Read_hash && !strcmp(s, "Read"))
+                io->Read += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
 
-                       else if(hash == Write_hash && !strcmp(s, "Write"))
-                               io->Write += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
+            else if(hash == Write_hash && !strcmp(s, "Write"))
+                io->Write += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
 
 /*
-                       else if(hash == Sync_hash && !strcmp(s, "Sync"))
-                               io->Sync += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
+            else if(hash == Sync_hash && !strcmp(s, "Sync"))
+                io->Sync += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
 
-                       else if(hash == Async_hash && !strcmp(s, "Async"))
-                               io->Async += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
+            else if(hash == Async_hash && !strcmp(s, "Async"))
+                io->Async += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
 
-                       else if(hash == Total_hash && !strcmp(s, "Total"))
-                               io->Total += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
+            else if(hash == Total_hash && !strcmp(s, "Total"))
+                io->Total += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
 */
-               }
+        }
 
-               io->updated = 1;
-               // fprintf(stderr, "READ '%s': Read: %llu, Write: %llu, Sync: %llu, Async: %llu, Total: %llu\n", io->filename, io->Read, io->Write, io->Sync, io->Async, io->Total);
-       }
+        io->updated = 1;
+        // fprintf(stderr, "READ '%s': Read: %llu, Write: %llu, Sync: %llu, Async: %llu, Total: %llu\n", io->filename, io->Read, io->Write, io->Sync, io->Async, io->Total);
+    }
 }
 
 void cgroup_read_memory(struct memory *mem) {
-       static procfile *ff = NULL;
-
-       static uint32_t cache_hash = 0;
-       static uint32_t rss_hash = 0;
-       static uint32_t rss_huge_hash = 0;
-       static uint32_t mapped_file_hash = 0;
-       static uint32_t writeback_hash = 0;
-       static uint32_t dirty_hash = 0;
-       static uint32_t swap_hash = 0;
-       static uint32_t pgpgin_hash = 0;
-       static uint32_t pgpgout_hash = 0;
-       static uint32_t pgfault_hash = 0;
-       static uint32_t pgmajfault_hash = 0;
+    static procfile *ff = NULL;
+
+    static uint32_t cache_hash = 0;
+    static uint32_t rss_hash = 0;
+    static uint32_t rss_huge_hash = 0;
+    static uint32_t mapped_file_hash = 0;
+    static uint32_t writeback_hash = 0;
+    static uint32_t dirty_hash = 0;
+    static uint32_t swap_hash = 0;
+    static uint32_t pgpgin_hash = 0;
+    static uint32_t pgpgout_hash = 0;
+    static uint32_t pgfault_hash = 0;
+    static uint32_t pgmajfault_hash = 0;
 /*
-       static uint32_t inactive_anon_hash = 0;
-       static uint32_t active_anon_hash = 0;
-       static uint32_t inactive_file_hash = 0;
-       static uint32_t active_file_hash = 0;
-       static uint32_t unevictable_hash = 0;
-       static uint32_t hierarchical_memory_limit_hash = 0;
-       static uint32_t total_cache_hash = 0;
-       static uint32_t total_rss_hash = 0;
-       static uint32_t total_rss_huge_hash = 0;
-       static uint32_t total_mapped_file_hash = 0;
-       static uint32_t total_writeback_hash = 0;
-       static uint32_t total_dirty_hash = 0;
-       static uint32_t total_swap_hash = 0;
-       static uint32_t total_pgpgin_hash = 0;
-       static uint32_t total_pgpgout_hash = 0;
-       static uint32_t total_pgfault_hash = 0;
-       static uint32_t total_pgmajfault_hash = 0;
-       static uint32_t total_inactive_anon_hash = 0;
-       static uint32_t total_active_anon_hash = 0;
-       static uint32_t total_inactive_file_hash = 0;
-       static uint32_t total_active_file_hash = 0;
-       static uint32_t total_unevictable_hash = 0;
+    static uint32_t inactive_anon_hash = 0;
+    static uint32_t active_anon_hash = 0;
+    static uint32_t inactive_file_hash = 0;
+    static uint32_t active_file_hash = 0;
+    static uint32_t unevictable_hash = 0;
+    static uint32_t hierarchical_memory_limit_hash = 0;
+    static uint32_t total_cache_hash = 0;
+    static uint32_t total_rss_hash = 0;
+    static uint32_t total_rss_huge_hash = 0;
+    static uint32_t total_mapped_file_hash = 0;
+    static uint32_t total_writeback_hash = 0;
+    static uint32_t total_dirty_hash = 0;
+    static uint32_t total_swap_hash = 0;
+    static uint32_t total_pgpgin_hash = 0;
+    static uint32_t total_pgpgout_hash = 0;
+    static uint32_t total_pgfault_hash = 0;
+    static uint32_t total_pgmajfault_hash = 0;
+    static uint32_t total_inactive_anon_hash = 0;
+    static uint32_t total_active_anon_hash = 0;
+    static uint32_t total_inactive_file_hash = 0;
+    static uint32_t total_active_file_hash = 0;
+    static uint32_t total_unevictable_hash = 0;
 */
-       if(unlikely(cache_hash == 0)) {
-               cache_hash = simple_hash("cache");
-               rss_hash = simple_hash("rss");
-               rss_huge_hash = simple_hash("rss_huge");
-               mapped_file_hash = simple_hash("mapped_file");
-               writeback_hash = simple_hash("writeback");
-               dirty_hash = simple_hash("dirty");
-               swap_hash = simple_hash("swap");
-               pgpgin_hash = simple_hash("pgpgin");
-               pgpgout_hash = simple_hash("pgpgout");
-               pgfault_hash = simple_hash("pgfault");
-               pgmajfault_hash = simple_hash("pgmajfault");
+    if(unlikely(cache_hash == 0)) {
+        cache_hash = simple_hash("cache");
+        rss_hash = simple_hash("rss");
+        rss_huge_hash = simple_hash("rss_huge");
+        mapped_file_hash = simple_hash("mapped_file");
+        writeback_hash = simple_hash("writeback");
+        dirty_hash = simple_hash("dirty");
+        swap_hash = simple_hash("swap");
+        pgpgin_hash = simple_hash("pgpgin");
+        pgpgout_hash = simple_hash("pgpgout");
+        pgfault_hash = simple_hash("pgfault");
+        pgmajfault_hash = simple_hash("pgmajfault");
 /*
-               inactive_anon_hash = simple_hash("inactive_anon");
-               active_anon_hash = simple_hash("active_anon");
-               inactive_file_hash = simple_hash("inactive_file");
-               active_file_hash = simple_hash("active_file");
-               unevictable_hash = simple_hash("unevictable");
-               hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
-               total_cache_hash = simple_hash("total_cache");
-               total_rss_hash = simple_hash("total_rss");
-               total_rss_huge_hash = simple_hash("total_rss_huge");
-               total_mapped_file_hash = simple_hash("total_mapped_file");
-               total_writeback_hash = simple_hash("total_writeback");
-               total_dirty_hash = simple_hash("total_dirty");
-               total_swap_hash = simple_hash("total_swap");
-               total_pgpgin_hash = simple_hash("total_pgpgin");
-               total_pgpgout_hash = simple_hash("total_pgpgout");
-               total_pgfault_hash = simple_hash("total_pgfault");
-               total_pgmajfault_hash = simple_hash("total_pgmajfault");
-               total_inactive_anon_hash = simple_hash("total_inactive_anon");
-               total_active_anon_hash = simple_hash("total_active_anon");
-               total_inactive_file_hash = simple_hash("total_inactive_file");
-               total_active_file_hash = simple_hash("total_active_file");
-               total_unevictable_hash = simple_hash("total_unevictable");
+        inactive_anon_hash = simple_hash("inactive_anon");
+        active_anon_hash = simple_hash("active_anon");
+        inactive_file_hash = simple_hash("inactive_file");
+        active_file_hash = simple_hash("active_file");
+        unevictable_hash = simple_hash("unevictable");
+        hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
+        total_cache_hash = simple_hash("total_cache");
+        total_rss_hash = simple_hash("total_rss");
+        total_rss_huge_hash = simple_hash("total_rss_huge");
+        total_mapped_file_hash = simple_hash("total_mapped_file");
+        total_writeback_hash = simple_hash("total_writeback");
+        total_dirty_hash = simple_hash("total_dirty");
+        total_swap_hash = simple_hash("total_swap");
+        total_pgpgin_hash = simple_hash("total_pgpgin");
+        total_pgpgout_hash = simple_hash("total_pgpgout");
+        total_pgfault_hash = simple_hash("total_pgfault");
+        total_pgmajfault_hash = simple_hash("total_pgmajfault");
+        total_inactive_anon_hash = simple_hash("total_inactive_anon");
+        total_active_anon_hash = simple_hash("total_active_anon");
+        total_inactive_file_hash = simple_hash("total_inactive_file");
+        total_active_file_hash = simple_hash("total_active_file");
+        total_unevictable_hash = simple_hash("total_unevictable");
 */
-       }
+    }
 
-       mem->updated = 0;
-       if(mem->filename) {
-               ff = procfile_reopen(ff, mem->filename, NULL, PROCFILE_FLAG_DEFAULT);
-               if(!ff) return;
+    mem->updated = 0;
+    if(mem->filename) {
+        ff = procfile_reopen(ff, mem->filename, NULL, PROCFILE_FLAG_DEFAULT);
+        if(!ff) return;
 
-               ff = procfile_readall(ff);
-               if(!ff) return;
+        ff = procfile_readall(ff);
+        if(!ff) return;
 
-               unsigned long i, lines = procfile_lines(ff);
+        unsigned long i, lines = procfile_lines(ff);
 
-               if(lines < 1) {
-                       error("File '%s' should have 1+ lines.", mem->filename);
-                       return;
-               }
+        if(lines < 1) {
+            error("File '%s' should have 1+ lines.", mem->filename);
+            return;
+        }
 
-               for(i = 0; i < lines ; i++) {
-                       char *s = procfile_lineword(ff, i, 0);
-                       uint32_t hash = simple_hash(s);
+        for(i = 0; i < lines ; i++) {
+            char *s = procfile_lineword(ff, i, 0);
+            uint32_t hash = simple_hash(s);
 
-                       if(hash == cache_hash && !strcmp(s, "cache"))
-                               mem->cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            if(hash == cache_hash && !strcmp(s, "cache"))
+                mem->cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == rss_hash && !strcmp(s, "rss"))
-                               mem->rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == rss_hash && !strcmp(s, "rss"))
+                mem->rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == rss_huge_hash && !strcmp(s, "rss_huge"))
-                               mem->rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == rss_huge_hash && !strcmp(s, "rss_huge"))
+                mem->rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == mapped_file_hash && !strcmp(s, "mapped_file"))
-                               mem->mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == mapped_file_hash && !strcmp(s, "mapped_file"))
+                mem->mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == writeback_hash && !strcmp(s, "writeback"))
-                               mem->writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == writeback_hash && !strcmp(s, "writeback"))
+                mem->writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == dirty_hash && !strcmp(s, "dirty")) {
-                               mem->dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
-                               mem->has_dirty_swap = 1;
-                       }
+            else if(hash == dirty_hash && !strcmp(s, "dirty")) {
+                mem->dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+                mem->has_dirty_swap = 1;
+            }
 
-                       else if(hash == swap_hash && !strcmp(s, "swap")) {
-                               mem->swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
-                               mem->has_dirty_swap = 1;
-                       }
+            else if(hash == swap_hash && !strcmp(s, "swap")) {
+                mem->swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+                mem->has_dirty_swap = 1;
+            }
 
-                       else if(hash == pgpgin_hash && !strcmp(s, "pgpgin"))
-                               mem->pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == pgpgin_hash && !strcmp(s, "pgpgin"))
+                mem->pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == pgpgout_hash && !strcmp(s, "pgpgout"))
-                               mem->pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == pgpgout_hash && !strcmp(s, "pgpgout"))
+                mem->pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == pgfault_hash && !strcmp(s, "pgfault"))
-                               mem->pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == pgfault_hash && !strcmp(s, "pgfault"))
+                mem->pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))
-                               mem->pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))
+                mem->pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
 /*
-                       else if(hash == inactive_anon_hash && !strcmp(s, "inactive_anon"))
-                               mem->inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == inactive_anon_hash && !strcmp(s, "inactive_anon"))
+                mem->inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == active_anon_hash && !strcmp(s, "active_anon"))
-                               mem->active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == active_anon_hash && !strcmp(s, "active_anon"))
+                mem->active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == inactive_file_hash && !strcmp(s, "inactive_file"))
-                               mem->inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == inactive_file_hash && !strcmp(s, "inactive_file"))
+                mem->inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == active_file_hash && !strcmp(s, "active_file"))
-                               mem->active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == active_file_hash && !strcmp(s, "active_file"))
+                mem->active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == unevictable_hash && !strcmp(s, "unevictable"))
-                               mem->unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == unevictable_hash && !strcmp(s, "unevictable"))
+                mem->unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == hierarchical_memory_limit_hash && !strcmp(s, "hierarchical_memory_limit"))
-                               mem->hierarchical_memory_limit = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == hierarchical_memory_limit_hash && !strcmp(s, "hierarchical_memory_limit"))
+                mem->hierarchical_memory_limit = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-               else if(hash == total_cache_hash && !strcmp(s, "total_cache"))
-                               mem->total_cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_cache_hash && !strcmp(s, "total_cache"))
+                mem->total_cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_rss_hash && !strcmp(s, "total_rss"))
-                               mem->total_rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_rss_hash && !strcmp(s, "total_rss"))
+                mem->total_rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_rss_huge_hash && !strcmp(s, "total_rss_huge"))
-                               mem->total_rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_rss_huge_hash && !strcmp(s, "total_rss_huge"))
+                mem->total_rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_mapped_file_hash && !strcmp(s, "total_mapped_file"))
-                               mem->total_mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_mapped_file_hash && !strcmp(s, "total_mapped_file"))
+                mem->total_mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_writeback_hash && !strcmp(s, "total_writeback"))
-                               mem->total_writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_writeback_hash && !strcmp(s, "total_writeback"))
+                mem->total_writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_dirty_hash && !strcmp(s, "total_dirty"))
-                               mem->total_dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_dirty_hash && !strcmp(s, "total_dirty"))
+                mem->total_dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_swap_hash && !strcmp(s, "total_swap"))
-                               mem->total_swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_swap_hash && !strcmp(s, "total_swap"))
+                mem->total_swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_pgpgin_hash && !strcmp(s, "total_pgpgin"))
-                               mem->total_pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_pgpgin_hash && !strcmp(s, "total_pgpgin"))
+                mem->total_pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_pgpgout_hash && !strcmp(s, "total_pgpgout"))
-                               mem->total_pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_pgpgout_hash && !strcmp(s, "total_pgpgout"))
+                mem->total_pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_pgfault_hash && !strcmp(s, "total_pgfault"))
-                               mem->total_pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_pgfault_hash && !strcmp(s, "total_pgfault"))
+                mem->total_pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_pgmajfault_hash && !strcmp(s, "total_pgmajfault"))
-                               mem->total_pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_pgmajfault_hash && !strcmp(s, "total_pgmajfault"))
+                mem->total_pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_inactive_anon_hash && !strcmp(s, "total_inactive_anon"))
-                               mem->total_inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_inactive_anon_hash && !strcmp(s, "total_inactive_anon"))
+                mem->total_inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_active_anon_hash && !strcmp(s, "total_active_anon"))
-                               mem->total_active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_active_anon_hash && !strcmp(s, "total_active_anon"))
+                mem->total_active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_inactive_file_hash && !strcmp(s, "total_inactive_file"))
-                               mem->total_inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_inactive_file_hash && !strcmp(s, "total_inactive_file"))
+                mem->total_inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_active_file_hash && !strcmp(s, "total_active_file"))
-                               mem->total_active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_active_file_hash && !strcmp(s, "total_active_file"))
+                mem->total_active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 
-                       else if(hash == total_unevictable_hash && !strcmp(s, "total_unevictable"))
-                               mem->total_unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
+            else if(hash == total_unevictable_hash && !strcmp(s, "total_unevictable"))
+                mem->total_unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
 */
-               }
+        }
 
-               // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable);
+        // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable);
 
-               mem->updated = 1;
-       }
+        mem->updated = 1;
+    }
 }
 
 void cgroup_read(struct cgroup *cg) {
-       debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
-
-       cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
-       cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
-       cgroup_read_memory(&cg->memory);
-       cgroup_read_blkio(&cg->io_service_bytes);
-       cgroup_read_blkio(&cg->io_serviced);
-       cgroup_read_blkio(&cg->throttle_io_service_bytes);
-       cgroup_read_blkio(&cg->throttle_io_serviced);
-       cgroup_read_blkio(&cg->io_merged);
-       cgroup_read_blkio(&cg->io_queued);
+    debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
+
+    cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
+    cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
+    cgroup_read_memory(&cg->memory);
+    cgroup_read_blkio(&cg->io_service_bytes);
+    cgroup_read_blkio(&cg->io_serviced);
+    cgroup_read_blkio(&cg->throttle_io_service_bytes);
+    cgroup_read_blkio(&cg->throttle_io_serviced);
+    cgroup_read_blkio(&cg->io_merged);
+    cgroup_read_blkio(&cg->io_queued);
 }
 
 void read_all_cgroups(struct cgroup *root) {
-       debug(D_CGROUP, "reading metrics for all cgroups");
+    debug(D_CGROUP, "reading metrics for all cgroups");
 
-       struct cgroup *cg;
+    struct cgroup *cg;
 
-       for(cg = root; cg ; cg = cg->next)
-               if(cg->enabled && cg->available)
-                       cgroup_read(cg);
+    for(cg = root; cg ; cg = cg->next)
+        if(cg->enabled && cg->available)
+            cgroup_read(cg);
 }
 
 // ----------------------------------------------------------------------------
@@ -583,167 +583,167 @@ void read_all_cgroups(struct cgroup *root) {
 #define CGROUP_CHARTID_LINE_MAX 1024
 
 void cgroup_get_chart_id(struct cgroup *cg) {
-       debug(D_CGROUP, "getting the name of cgroup '%s'", cg->id);
+    debug(D_CGROUP, "getting the name of cgroup '%s'", cg->id);
 
-       pid_t cgroup_pid;
-       char buffer[CGROUP_CHARTID_LINE_MAX + 1];
+    pid_t cgroup_pid;
+    char buffer[CGROUP_CHARTID_LINE_MAX + 1];
 
-       snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'",
-                config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->chart_id);
+    snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'",
+             config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->chart_id);
 
-       debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
-       FILE *fp = mypopen(buffer, &cgroup_pid);
-       if(!fp) {
-               error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
-               return;
-       }
-       debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
-       char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
-       debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
-       mypclose(fp, cgroup_pid);
-       debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
+    debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
+    FILE *fp = mypopen(buffer, &cgroup_pid);
+    if(!fp) {
+        error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
+        return;
+    }
+    debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
+    char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
+    debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
+    mypclose(fp, cgroup_pid);
+    debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
 
-       if(s && *s && *s != '\n') {
-               debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
+    if(s && *s && *s != '\n') {
+        debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
 
-               trim(s);
+        trim(s);
 
-               freez(cg->chart_title);
-               cg->chart_title = strdupz(s);
-               netdata_fix_chart_name(cg->chart_title);
+        freez(cg->chart_title);
+        cg->chart_title = strdupz(s);
+        netdata_fix_chart_name(cg->chart_title);
 
-               freez(cg->chart_id);
-               cg->chart_id = strdupz(s);
+        freez(cg->chart_id);
+        cg->chart_id = strdupz(s);
 
-               netdata_fix_chart_id(cg->chart_id);
+        netdata_fix_chart_id(cg->chart_id);
 
-               debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
-       }
-       else debug(D_CGROUP, "cgroup '%s' is not to be renamed (will be shown as '%s')", cg->id, cg->chart_id);
+        debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
+    }
+    else debug(D_CGROUP, "cgroup '%s' is not to be renamed (will be shown as '%s')", cg->id, cg->chart_id);
 }
 
 struct cgroup *cgroup_add(const char *id) {
-       debug(D_CGROUP, "adding cgroup '%s'", id);
-
-       if(cgroup_root_count >= cgroup_root_max) {
-               info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
-               return NULL;
-       }
-
-       int def = cgroup_enable_new_cgroups_detected_at_runtime;
-       const char *chart_id = id;
-       if(!*chart_id) {
-               chart_id = "/";
-
-               // disable by default the root cgroup
-               def = 0;
-               debug(D_CGROUP, "cgroup '%s' is the root container (by default %s)", id, (def)?"enabled":"disabled");
-       }
-       else {
-               if(*chart_id == '/') chart_id++;
-
-               size_t len = strlen(chart_id);
-
-               // disable by default the parent cgroup
-               // for known cgroup managers
-               if(!strcmp(chart_id, "lxc") ||
-                               !strcmp(chart_id, "docker") ||
-                               !strcmp(chart_id, "libvirt") ||
-                               !strcmp(chart_id, "qemu") ||
-                               !strcmp(chart_id, "systemd") ||
-                               !strcmp(chart_id, "system.slice") ||
-                               !strcmp(chart_id, "machine.slice") ||
-                               !strcmp(chart_id, "init.scope") ||
-                               !strcmp(chart_id, "user") ||
-                               !strcmp(chart_id, "system") ||
-                               !strcmp(chart_id, "machine") ||
-                               // starts with them
-                               (len >  6 && !strncmp(chart_id, "user/", 6)) ||
-                               (len > 11 && !strncmp(chart_id, "user.slice/", 11)) ||
-                               // ends with them
-                               (len >  5 && !strncmp(&chart_id[len -  5], ".user", 5)) ||
-                               (len >  5 && !strncmp(&chart_id[len -  5], ".swap", 5)) ||
-                               (len >  6 && !strncmp(&chart_id[len -  6], ".slice", 6)) ||
-                               (len >  6 && !strncmp(&chart_id[len -  6], ".mount", 6)) ||
-                               (len >  8 && !strncmp(&chart_id[len -  8], ".session", 8)) ||
-                               (len >  8 && !strncmp(&chart_id[len -  8], ".service", 8)) ||
-                               (len > 10 && !strncmp(&chart_id[len - 10], ".partition", 10))
-                               ) {
-                       def = 0;
-                       debug(D_CGROUP, "cgroup '%s' is %s (by default)", id, (def)?"enabled":"disabled");
-               }
-       }
-
-       struct cgroup *cg = callocz(1, sizeof(struct cgroup));
-
-       debug(D_CGROUP, "adding cgroup '%s'", id);
-
-       cg->id = strdupz(id);
-       cg->hash = simple_hash(cg->id);
-
-       cg->chart_id = strdupz(chart_id);
-       cg->chart_title = strdupz(chart_id);
-
-       if(!cgroup_root)
-               cgroup_root = cg;
-       else {
-               // append it
-               struct cgroup *e;
-               for(e = cgroup_root; e->next ;e = e->next) ;
-               e->next = cg;
-       }
-
-       cgroup_root_count++;
-
-       // fix the name by calling the external script
-       cgroup_get_chart_id(cg);
-
-       char option[FILENAME_MAX + 1];
-       snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
-       cg->enabled = config_get_boolean("plugin:cgroups", option, def);
-
-       debug(D_CGROUP, "Added cgroup '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
-
-       return cg;
+    debug(D_CGROUP, "adding cgroup '%s'", id);
+
+    if(cgroup_root_count >= cgroup_root_max) {
+        info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
+        return NULL;
+    }
+
+    int def = cgroup_enable_new_cgroups_detected_at_runtime;
+    const char *chart_id = id;
+    if(!*chart_id) {
+        chart_id = "/";
+
+        // disable by default the root cgroup
+        def = 0;
+        debug(D_CGROUP, "cgroup '%s' is the root container (by default %s)", id, (def)?"enabled":"disabled");
+    }
+    else {
+        if(*chart_id == '/') chart_id++;
+
+        size_t len = strlen(chart_id);
+
+        // disable by default the parent cgroup
+        // for known cgroup managers
+        if(!strcmp(chart_id, "lxc") ||
+                !strcmp(chart_id, "docker") ||
+                !strcmp(chart_id, "libvirt") ||
+                !strcmp(chart_id, "qemu") ||
+                !strcmp(chart_id, "systemd") ||
+                !strcmp(chart_id, "system.slice") ||
+                !strcmp(chart_id, "machine.slice") ||
+                !strcmp(chart_id, "init.scope") ||
+                !strcmp(chart_id, "user") ||
+                !strcmp(chart_id, "system") ||
+                !strcmp(chart_id, "machine") ||
+                // starts with them
+                (len >  6 && !strncmp(chart_id, "user/", 6)) ||
+                (len > 11 && !strncmp(chart_id, "user.slice/", 11)) ||
+                // ends with them
+                (len >  5 && !strncmp(&chart_id[len -  5], ".user", 5)) ||
+                (len >  5 && !strncmp(&chart_id[len -  5], ".swap", 5)) ||
+                (len >  6 && !strncmp(&chart_id[len -  6], ".slice", 6)) ||
+                (len >  6 && !strncmp(&chart_id[len -  6], ".mount", 6)) ||
+                (len >  8 && !strncmp(&chart_id[len -  8], ".session", 8)) ||
+                (len >  8 && !strncmp(&chart_id[len -  8], ".service", 8)) ||
+                (len > 10 && !strncmp(&chart_id[len - 10], ".partition", 10))
+                ) {
+            def = 0;
+            debug(D_CGROUP, "cgroup '%s' is %s (by default)", id, (def)?"enabled":"disabled");
+        }
+    }
+
+    struct cgroup *cg = callocz(1, sizeof(struct cgroup));
+
+    debug(D_CGROUP, "adding cgroup '%s'", id);
+
+    cg->id = strdupz(id);
+    cg->hash = simple_hash(cg->id);
+
+    cg->chart_id = strdupz(chart_id);
+    cg->chart_title = strdupz(chart_id);
+
+    if(!cgroup_root)
+        cgroup_root = cg;
+    else {
+        // append it
+        struct cgroup *e;
+        for(e = cgroup_root; e->next ;e = e->next) ;
+        e->next = cg;
+    }
+
+    cgroup_root_count++;
+
+    // fix the name by calling the external script
+    cgroup_get_chart_id(cg);
+
+    char option[FILENAME_MAX + 1];
+    snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
+    cg->enabled = config_get_boolean("plugin:cgroups", option, def);
+
+    debug(D_CGROUP, "Added cgroup '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
+
+    return cg;
 }
 
 void cgroup_free(struct cgroup *cg) {
-       debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
-
-       freez(cg->cpuacct_usage.cpu_percpu);
-
-       freez(cg->cpuacct_stat.filename);
-       freez(cg->cpuacct_usage.filename);
-       freez(cg->memory.filename);
-       freez(cg->io_service_bytes.filename);
-       freez(cg->io_serviced.filename);
-       freez(cg->throttle_io_service_bytes.filename);
-       freez(cg->throttle_io_serviced.filename);
-       freez(cg->io_merged.filename);
-       freez(cg->io_queued.filename);
-
-       freez(cg->id);
-       freez(cg->chart_id);
-       freez(cg->chart_title);
-       freez(cg);
-
-       cgroup_root_count--;
+    debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
+
+    freez(cg->cpuacct_usage.cpu_percpu);
+
+    freez(cg->cpuacct_stat.filename);
+    freez(cg->cpuacct_usage.filename);
+    freez(cg->memory.filename);
+    freez(cg->io_service_bytes.filename);
+    freez(cg->io_serviced.filename);
+    freez(cg->throttle_io_service_bytes.filename);
+    freez(cg->throttle_io_serviced.filename);
+    freez(cg->io_merged.filename);
+    freez(cg->io_queued.filename);
+
+    freez(cg->id);
+    freez(cg->chart_id);
+    freez(cg->chart_title);
+    freez(cg);
+
+    cgroup_root_count--;
 }
 
 // find if a given cgroup exists
 struct cgroup *cgroup_find(const char *id) {
-       debug(D_CGROUP, "searching for cgroup '%s'", id);
+    debug(D_CGROUP, "searching for cgroup '%s'", id);
 
-       uint32_t hash = simple_hash(id);
+    uint32_t hash = simple_hash(id);
 
-       struct cgroup *cg;
-       for(cg = cgroup_root; cg ; cg = cg->next) {
-               if(hash == cg->hash && strcmp(id, cg->id) == 0)
-                       break;
-       }
+    struct cgroup *cg;
+    for(cg = cgroup_root; cg ; cg = cg->next) {
+        if(hash == cg->hash && strcmp(id, cg->id) == 0)
+            break;
+    }
 
-       debug(D_CGROUP, "cgroup_find('%s') %s", id, (cg)?"found":"not found");
-       return cg;
+    debug(D_CGROUP, "cgroup_find('%s') %s", id, (cg)?"found":"not found");
+    return cg;
 }
 
 // ----------------------------------------------------------------------------
@@ -751,232 +751,232 @@ struct cgroup *cgroup_find(const char *id) {
 
 // callback for find_file_in_subdirs()
 void found_subdir_in_dir(const char *dir) {
-       debug(D_CGROUP, "examining cgroup dir '%s'", dir);
-
-       struct cgroup *cg = cgroup_find(dir);
-       if(!cg) {
-               if(*dir && cgroup_max_depth > 0) {
-                       int depth = 0;
-                       const char *s;
-
-                       for(s = dir; *s ;s++)
-                               if(unlikely(*s == '/'))
-                                       depth++;
-
-                       if(depth > cgroup_max_depth) {
-                               info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
-                               return;
-                       }
-               }
-               debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
-               cg = cgroup_add(dir);
-       }
-
-       if(cg) cg->available = 1;
+    debug(D_CGROUP, "examining cgroup dir '%s'", dir);
+
+    struct cgroup *cg = cgroup_find(dir);
+    if(!cg) {
+        if(*dir && cgroup_max_depth > 0) {
+            int depth = 0;
+            const char *s;
+
+            for(s = dir; *s ;s++)
+                if(unlikely(*s == '/'))
+                    depth++;
+
+            if(depth > cgroup_max_depth) {
+                info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
+                return;
+            }
+        }
+        debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
+        cg = cgroup_add(dir);
+    }
+
+    if(cg) cg->available = 1;
 }
 
 void find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
-       debug(D_CGROUP, "searching for directories in '%s'", base);
-
-       int enabled = -1;
-       if(!this) this = base;
-       size_t dirlen = strlen(this), baselen = strlen(base);
-       const char *relative_path = &this[baselen];
-
-       DIR *dir = opendir(this);
-       if(!dir) {
-               error("Cannot read cgroups directory '%s'", base);
-               return;
-       }
-
-       callback(relative_path);
-
-       struct dirent *de = NULL;
-       while((de = readdir(dir))) {
-               if(de->d_type == DT_DIR
-                       && (
-                               (de->d_name[0] == '.' && de->d_name[1] == '\0')
-                               || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
-                               ))
-                       continue;
-
-               debug(D_CGROUP, "examining '%s/%s'", this, de->d_name);
-
-               if(de->d_type == DT_DIR) {
-                       if(enabled == -1) {
-                               const char *r = relative_path;
-                               if(*r == '\0') r = "/";
-                               else if (*r == '/') r++;
-
-                               // we check for this option here
-                               // so that the config will not have settings
-                               // for leaf directories
-                               char option[FILENAME_MAX + 1];
-                               snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
-                               option[FILENAME_MAX] = '\0';
-                               enabled = config_get_boolean("plugin:cgroups", option, 1);
-                       }
-
-                       if(enabled) {
-                               char *s = mallocz(dirlen + strlen(de->d_name) + 2);
+    debug(D_CGROUP, "searching for directories in '%s'", base);
+
+    int enabled = -1;
+    if(!this) this = base;
+    size_t dirlen = strlen(this), baselen = strlen(base);
+    const char *relative_path = &this[baselen];
+
+    DIR *dir = opendir(this);
+    if(!dir) {
+        error("Cannot read cgroups directory '%s'", base);
+        return;
+    }
+
+    callback(relative_path);
+
+    struct dirent *de = NULL;
+    while((de = readdir(dir))) {
+        if(de->d_type == DT_DIR
+            && (
+                (de->d_name[0] == '.' && de->d_name[1] == '\0')
+                || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
+                ))
+            continue;
+
+        debug(D_CGROUP, "examining '%s/%s'", this, de->d_name);
+
+        if(de->d_type == DT_DIR) {
+            if(enabled == -1) {
+                const char *r = relative_path;
+                if(*r == '\0') r = "/";
+                else if (*r == '/') r++;
+
+                // we check for this option here
+                // so that the config will not have settings
+                // for leaf directories
+                char option[FILENAME_MAX + 1];
+                snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
+                option[FILENAME_MAX] = '\0';
+                enabled = config_get_boolean("plugin:cgroups", option, 1);
+            }
+
+            if(enabled) {
+                char *s = mallocz(dirlen + strlen(de->d_name) + 2);
                 strcpy(s, this);
                 strcat(s, "/");
                 strcat(s, de->d_name);
                 find_dir_in_subdirs(base, s, callback);
                 freez(s);
-                       }
-               }
-       }
+            }
+        }
+    }
 
-       closedir(dir);
+    closedir(dir);
 }
 
 void mark_all_cgroups_as_not_available() {
-       debug(D_CGROUP, "marking all cgroups as not available");
+    debug(D_CGROUP, "marking all cgroups as not available");
 
-       struct cgroup *cg;
+    struct cgroup *cg;
 
-       // mark all as not available
-       for(cg = cgroup_root; cg ; cg = cg->next)
-               cg->available = 0;
+    // mark all as not available
+    for(cg = cgroup_root; cg ; cg = cg->next)
+        cg->available = 0;
 }
 
 void cleanup_all_cgroups() {
-       struct cgroup *cg = cgroup_root, *last = NULL;
-
-       for(; cg ;) {
-               if(!cg->available) {
-
-                       if(!last)
-                               cgroup_root = cg->next;
-                       else
-                               last->next = cg->next;
-
-                       cgroup_free(cg);
-
-                       if(!last)
-                               cg = cgroup_root;
-                       else
-                               cg = last->next;
-               }
-               else {
-                       last = cg;
-                       cg = cg->next;
-               }
-       }
+    struct cgroup *cg = cgroup_root, *last = NULL;
+
+    for(; cg ;) {
+        if(!cg->available) {
+
+            if(!last)
+                cgroup_root = cg->next;
+            else
+                last->next = cg->next;
+
+            cgroup_free(cg);
+
+            if(!last)
+                cg = cgroup_root;
+            else
+                cg = last->next;
+        }
+        else {
+            last = cg;
+            cg = cg->next;
+        }
+    }
 }
 
 void find_all_cgroups() {
-       debug(D_CGROUP, "searching for cgroups");
-
-       mark_all_cgroups_as_not_available();
-
-       if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage)
-               find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir);
-
-       if(cgroup_enable_blkio)
-               find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir);
-
-       if(cgroup_enable_memory)
-               find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir);
-
-       if(cgroup_enable_devices)
-               find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir);
-
-       // remove any non-existing cgroups
-       cleanup_all_cgroups();
-
-       struct cgroup *cg;
-       struct stat buf;
-       for(cg = cgroup_root; cg ; cg = cg->next) {
-               // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
-
-               if(unlikely(!cg->available))
-                       continue;
-
-               debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
-
-               // check for newly added cgroups
-               // and update the filenames they read
-               char filename[FILENAME_MAX + 1];
-               if(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename) {
-                       snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
-                       if(stat(filename, &buf) != -1) {
-                               cg->cpuacct_stat.filename = strdupz(filename);
-                               debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
-                       }
-                       else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-               }
-               if(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename) {
-                       snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
-                       if(stat(filename, &buf) != -1) {
-                               cg->cpuacct_usage.filename = strdupz(filename);
-                               debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
-                       }
-                       else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-               }
-               if(cgroup_enable_memory && !cg->memory.filename) {
-                       snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
-                       if(stat(filename, &buf) != -1) {
-                               cg->memory.filename = strdupz(filename);
-                               debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
-                       }
-                       else debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-               }
-               if(cgroup_enable_blkio) {
-                       if(!cg->io_service_bytes.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->io_service_bytes.filename = strdupz(filename);
-                                       debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
-                               }
-                               else debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-                       if(!cg->io_serviced.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->io_serviced.filename = strdupz(filename);
-                                       debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
-                               }
-                               else debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-                       if(!cg->throttle_io_service_bytes.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->throttle_io_service_bytes.filename = strdupz(filename);
-                                       debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
-                               }
-                               else debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-                       if(!cg->throttle_io_serviced.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->throttle_io_serviced.filename = strdupz(filename);
-                                       debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
-                               }
-                               else debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-                       if(!cg->io_merged.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->io_merged.filename = strdupz(filename);
-                                       debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
-                               }
-                               else debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-                       if(!cg->io_queued.filename) {
-                               snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
-                               if(stat(filename, &buf) != -1) {
-                                       cg->io_queued.filename = strdupz(filename);
-                                       debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
-                               }
-                               else debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
-                       }
-               }
-       }
-
-       debug(D_CGROUP, "done searching for cgroups");
-       return;
+    debug(D_CGROUP, "searching for cgroups");
+
+    mark_all_cgroups_as_not_available();
+
+    if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage)
+        find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir);
+
+    if(cgroup_enable_blkio)
+        find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir);
+
+    if(cgroup_enable_memory)
+        find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir);
+
+    if(cgroup_enable_devices)
+        find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir);
+
+    // remove any non-existing cgroups
+    cleanup_all_cgroups();
+
+    struct cgroup *cg;
+    struct stat buf;
+    for(cg = cgroup_root; cg ; cg = cg->next) {
+        // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
+
+        if(unlikely(!cg->available))
+            continue;
+
+        debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
+
+        // check for newly added cgroups
+        // and update the filenames they read
+        char filename[FILENAME_MAX + 1];
+        if(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename) {
+            snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
+            if(stat(filename, &buf) != -1) {
+                cg->cpuacct_stat.filename = strdupz(filename);
+                debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
+            }
+            else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+        }
+        if(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename) {
+            snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
+            if(stat(filename, &buf) != -1) {
+                cg->cpuacct_usage.filename = strdupz(filename);
+                debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
+            }
+            else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+        }
+        if(cgroup_enable_memory && !cg->memory.filename) {
+            snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
+            if(stat(filename, &buf) != -1) {
+                cg->memory.filename = strdupz(filename);
+                debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
+            }
+            else debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+        }
+        if(cgroup_enable_blkio) {
+            if(!cg->io_service_bytes.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->io_service_bytes.filename = strdupz(filename);
+                    debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
+                }
+                else debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+            if(!cg->io_serviced.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->io_serviced.filename = strdupz(filename);
+                    debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
+                }
+                else debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+            if(!cg->throttle_io_service_bytes.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->throttle_io_service_bytes.filename = strdupz(filename);
+                    debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
+                }
+                else debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+            if(!cg->throttle_io_serviced.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->throttle_io_serviced.filename = strdupz(filename);
+                    debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
+                }
+                else debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+            if(!cg->io_merged.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->io_merged.filename = strdupz(filename);
+                    debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
+                }
+                else debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+            if(!cg->io_queued.filename) {
+                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
+                if(stat(filename, &buf) != -1) {
+                    cg->io_queued.filename = strdupz(filename);
+                    debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
+                }
+                else debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
+            }
+        }
+    }
+
+    debug(D_CGROUP, "done searching for cgroups");
+    return;
 }
 
 // ----------------------------------------------------------------------------
@@ -985,349 +985,349 @@ void find_all_cgroups() {
 #define CHART_TITLE_MAX 300
 
 void update_cgroup_charts(int update_every) {
-       debug(D_CGROUP, "updating cgroups charts");
-
-       char type[RRD_ID_LENGTH_MAX + 1];
-       char title[CHART_TITLE_MAX + 1];
-
-       struct cgroup *cg;
-       RRDSET *st;
-
-       for(cg = cgroup_root; cg ; cg = cg->next) {
-               if(!cg->available || !cg->enabled)
-                       continue;
-
-               if(cg->id[0] == '\0')
-                       strcpy(type, "cgroup_root");
-               else if(cg->id[0] == '/')
-                       snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
-               else
-                       snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
-
-               netdata_fix_chart_id(type);
-
-               if(cg->cpuacct_stat.updated) {
-                       st = rrdset_find_bytype(type, "cpu");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "CPU Usage for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", 40000, update_every, RRDSET_TYPE_STACKED);
-
-                               rrddim_add(st, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "user", cg->cpuacct_stat.user);
-                       rrddim_set(st, "system", cg->cpuacct_stat.system);
-                       rrdset_done(st);
-               }
-
-               if(cg->cpuacct_usage.updated) {
-                       char id[RRD_ID_LENGTH_MAX + 1];
-                       unsigned int i;
-
-                       st = rrdset_find_bytype(type, "cpu_per_core");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "CPU Usage Per Core for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", 40100, update_every, RRDSET_TYPE_STACKED);
-
-                               for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
-                                       snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
-                                       rrddim_add(st, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
-                               }
-                       }
-                       else rrdset_next(st);
-
-                       for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
-                               snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
-                               rrddim_set(st, id, cg->cpuacct_usage.cpu_percpu[i]);
-                       }
-                       rrdset_done(st);
-               }
-
-               if(cg->memory.updated) {
-                       if(cg->memory.cache + cg->memory.rss + cg->memory.rss_huge + cg->memory.mapped_file > 0) {
-                               st = rrdset_find_bytype(type, "mem");
-                               if(!st) {
-                                       snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
-                                       st = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", 40200, update_every,
-                                                          RRDSET_TYPE_STACKED);
-
-                                       rrddim_add(st, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                                       rrddim_add(st, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                                       if(cg->memory.has_dirty_swap)
-                                               rrddim_add(st, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                                       rrddim_add(st, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                                       rrddim_add(st, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "cache", cg->memory.cache);
-                               rrddim_set(st, "rss", cg->memory.rss);
-                               if(cg->memory.has_dirty_swap)
-                                       rrddim_set(st, "swap", cg->memory.swap);
-                               rrddim_set(st, "rss_huge", cg->memory.rss_huge);
-                               rrddim_set(st, "mapped_file", cg->memory.mapped_file);
-                               rrdset_done(st);
-                       }
-
-                       st = rrdset_find_bytype(type, "writeback");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", 40300,
-                                                  update_every, RRDSET_TYPE_AREA);
-
-                               if(cg->memory.has_dirty_swap)
-                                       rrddim_add(st, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                               rrddim_add(st, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-                       }
-                       else rrdset_next(st);
-
-                       if(cg->memory.has_dirty_swap)
-                               rrddim_set(st, "dirty", cg->memory.dirty);
-                       rrddim_set(st, "writeback", cg->memory.writeback);
-                       rrdset_done(st);
-
-                       if(cg->memory.pgpgin + cg->memory.pgpgout > 0) {
-                               st = rrdset_find_bytype(type, "mem_activity");
-                               if(!st) {
-                                       snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
-                                       st = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s",
-                                                          40400, update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "pgpgin", "in", sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "pgpgout", "out", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "pgpgin", cg->memory.pgpgin);
-                               rrddim_set(st, "pgpgout", cg->memory.pgpgout);
-                               rrdset_done(st);
-                       }
-
-                       if(cg->memory.pgfault + cg->memory.pgmajfault > 0) {
-                               st = rrdset_find_bytype(type, "pgfaults");
-                               if(!st) {
-                                       snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
-                                       st = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", 40500,
-                                                          update_every, RRDSET_TYPE_LINE);
-
-                                       rrddim_add(st, "pgfault", NULL, sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
-                                       rrddim_add(st, "pgmajfault", "swap", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
-                               }
-                               else rrdset_next(st);
-
-                               rrddim_set(st, "pgfault", cg->memory.pgfault);
-                               rrddim_set(st, "pgmajfault", cg->memory.pgmajfault);
-                               rrdset_done(st);
-                       }
-               }
-
-               if(cg->io_service_bytes.updated && cg->io_service_bytes.Read + cg->io_service_bytes.Write > 0) {
-                       st = rrdset_find_bytype(type, "io");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->io_service_bytes.Read);
-                       rrddim_set(st, "write", cg->io_service_bytes.Write);
-                       rrdset_done(st);
-               }
-
-               if(cg->io_serviced.updated && cg->io_serviced.Read + cg->io_serviced.Write > 0) {
-                       st = rrdset_find_bytype(type, "serviced_ops");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", 41200,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->io_serviced.Read);
-                       rrddim_set(st, "write", cg->io_serviced.Write);
-                       rrdset_done(st);
-               }
-
-               if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.Read + cg->throttle_io_service_bytes.Write > 0) {
-                       st = rrdset_find_bytype(type, "io");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->throttle_io_service_bytes.Read);
-                       rrddim_set(st, "write", cg->throttle_io_service_bytes.Write);
-                       rrdset_done(st);
-               }
-
-
-               if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.Read + cg->throttle_io_serviced.Write > 0) {
-                       st = rrdset_find_bytype(type, "throttle_serviced_ops");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", 41200,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->throttle_io_serviced.Read);
-                       rrddim_set(st, "write", cg->throttle_io_serviced.Write);
-                       rrdset_done(st);
-               }
-
-               if(cg->io_queued.updated) {
-                       st = rrdset_find_bytype(type, "queued_ops");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", 42000,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
-                               rrddim_add(st, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->io_queued.Read);
-                       rrddim_set(st, "write", cg->io_queued.Write);
-                       rrdset_done(st);
-               }
-
-               if(cg->io_merged.updated && cg->io_merged.Read + cg->io_merged.Write > 0) {
-                       st = rrdset_find_bytype(type, "merged_ops");
-                       if(!st) {
-                               snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
-                               st = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", 42100,
-                                                  update_every, RRDSET_TYPE_LINE);
-
-                               rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
-                               rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(st);
-
-                       rrddim_set(st, "read", cg->io_merged.Read);
-                       rrddim_set(st, "write", cg->io_merged.Write);
-                       rrdset_done(st);
-               }
-       }
-
-       debug(D_CGROUP, "done updating cgroups charts");
+    debug(D_CGROUP, "updating cgroups charts");
+
+    char type[RRD_ID_LENGTH_MAX + 1];
+    char title[CHART_TITLE_MAX + 1];
+
+    struct cgroup *cg;
+    RRDSET *st;
+
+    for(cg = cgroup_root; cg ; cg = cg->next) {
+        if(!cg->available || !cg->enabled)
+            continue;
+
+        if(cg->id[0] == '\0')
+            strcpy(type, "cgroup_root");
+        else if(cg->id[0] == '/')
+            snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
+        else
+            snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
+
+        netdata_fix_chart_id(type);
+
+        if(cg->cpuacct_stat.updated) {
+            st = rrdset_find_bytype(type, "cpu");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "CPU Usage for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", 40000, update_every, RRDSET_TYPE_STACKED);
+
+                rrddim_add(st, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "user", cg->cpuacct_stat.user);
+            rrddim_set(st, "system", cg->cpuacct_stat.system);
+            rrdset_done(st);
+        }
+
+        if(cg->cpuacct_usage.updated) {
+            char id[RRD_ID_LENGTH_MAX + 1];
+            unsigned int i;
+
+            st = rrdset_find_bytype(type, "cpu_per_core");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "CPU Usage Per Core for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", 40100, update_every, RRDSET_TYPE_STACKED);
+
+                for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
+                    snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
+                    rrddim_add(st, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
+                }
+            }
+            else rrdset_next(st);
+
+            for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
+                snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
+                rrddim_set(st, id, cg->cpuacct_usage.cpu_percpu[i]);
+            }
+            rrdset_done(st);
+        }
+
+        if(cg->memory.updated) {
+            if(cg->memory.cache + cg->memory.rss + cg->memory.rss_huge + cg->memory.mapped_file > 0) {
+                st = rrdset_find_bytype(type, "mem");
+                if(!st) {
+                    snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
+                    st = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", 40200, update_every,
+                                       RRDSET_TYPE_STACKED);
+
+                    rrddim_add(st, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                    if(cg->memory.has_dirty_swap)
+                        rrddim_add(st, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "cache", cg->memory.cache);
+                rrddim_set(st, "rss", cg->memory.rss);
+                if(cg->memory.has_dirty_swap)
+                    rrddim_set(st, "swap", cg->memory.swap);
+                rrddim_set(st, "rss_huge", cg->memory.rss_huge);
+                rrddim_set(st, "mapped_file", cg->memory.mapped_file);
+                rrdset_done(st);
+            }
+
+            st = rrdset_find_bytype(type, "writeback");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", 40300,
+                                   update_every, RRDSET_TYPE_AREA);
+
+                if(cg->memory.has_dirty_swap)
+                    rrddim_add(st, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+                rrddim_add(st, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            if(cg->memory.has_dirty_swap)
+                rrddim_set(st, "dirty", cg->memory.dirty);
+            rrddim_set(st, "writeback", cg->memory.writeback);
+            rrdset_done(st);
+
+            if(cg->memory.pgpgin + cg->memory.pgpgout > 0) {
+                st = rrdset_find_bytype(type, "mem_activity");
+                if(!st) {
+                    snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
+                    st = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s",
+                                       40400, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "pgpgin", "in", sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "pgpgout", "out", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "pgpgin", cg->memory.pgpgin);
+                rrddim_set(st, "pgpgout", cg->memory.pgpgout);
+                rrdset_done(st);
+            }
+
+            if(cg->memory.pgfault + cg->memory.pgmajfault > 0) {
+                st = rrdset_find_bytype(type, "pgfaults");
+                if(!st) {
+                    snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
+                    st = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", 40500,
+                                       update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "pgfault", NULL, sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "pgmajfault", "swap", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "pgfault", cg->memory.pgfault);
+                rrddim_set(st, "pgmajfault", cg->memory.pgmajfault);
+                rrdset_done(st);
+            }
+        }
+
+        if(cg->io_service_bytes.updated && cg->io_service_bytes.Read + cg->io_service_bytes.Write > 0) {
+            st = rrdset_find_bytype(type, "io");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->io_service_bytes.Read);
+            rrddim_set(st, "write", cg->io_service_bytes.Write);
+            rrdset_done(st);
+        }
+
+        if(cg->io_serviced.updated && cg->io_serviced.Read + cg->io_serviced.Write > 0) {
+            st = rrdset_find_bytype(type, "serviced_ops");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", 41200,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->io_serviced.Read);
+            rrddim_set(st, "write", cg->io_serviced.Write);
+            rrdset_done(st);
+        }
+
+        if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.Read + cg->throttle_io_service_bytes.Write > 0) {
+            st = rrdset_find_bytype(type, "io");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->throttle_io_service_bytes.Read);
+            rrddim_set(st, "write", cg->throttle_io_service_bytes.Write);
+            rrdset_done(st);
+        }
+
+
+        if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.Read + cg->throttle_io_serviced.Write > 0) {
+            st = rrdset_find_bytype(type, "throttle_serviced_ops");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", 41200,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->throttle_io_serviced.Read);
+            rrddim_set(st, "write", cg->throttle_io_serviced.Write);
+            rrdset_done(st);
+        }
+
+        if(cg->io_queued.updated) {
+            st = rrdset_find_bytype(type, "queued_ops");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", 42000,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                rrddim_add(st, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->io_queued.Read);
+            rrddim_set(st, "write", cg->io_queued.Write);
+            rrdset_done(st);
+        }
+
+        if(cg->io_merged.updated && cg->io_merged.Read + cg->io_merged.Write > 0) {
+            st = rrdset_find_bytype(type, "merged_ops");
+            if(!st) {
+                snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
+                st = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", 42100,
+                                   update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
+                rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "read", cg->io_merged.Read);
+            rrddim_set(st, "write", cg->io_merged.Write);
+            rrdset_done(st);
+        }
+    }
+
+    debug(D_CGROUP, "done updating cgroups charts");
 }
 
 // ----------------------------------------------------------------------------
 // cgroups main
 
 int do_sys_fs_cgroup(int update_every, unsigned long long dt) {
-       (void)dt;
+    (void)dt;
 
-       static int cgroup_global_config_read = 0;
-       static time_t last_run = 0;
-       time_t now = time(NULL);
+    static int cgroup_global_config_read = 0;
+    static time_t last_run = 0;
+    time_t now = time(NULL);
 
-       if(unlikely(!cgroup_global_config_read)) {
-               read_cgroup_plugin_configuration();
-               cgroup_global_config_read = 1;
-       }
+    if(unlikely(!cgroup_global_config_read)) {
+        read_cgroup_plugin_configuration();
+        cgroup_global_config_read = 1;
+    }
 
-       if(unlikely(cgroup_enable_new_cgroups_detected_at_runtime && now - last_run > cgroup_check_for_new_every)) {
-               find_all_cgroups();
-               last_run = now;
-       }
+    if(unlikely(cgroup_enable_new_cgroups_detected_at_runtime && now - last_run > cgroup_check_for_new_every)) {
+        find_all_cgroups();
+        last_run = now;
+    }
 
-       read_all_cgroups(cgroup_root);
-       update_cgroup_charts(update_every);
+    read_all_cgroups(cgroup_root);
+    update_cgroup_charts(update_every);
 
-       return 0;
+    return 0;
 }
 
 void *cgroups_main(void *ptr)
 {
-       if(ptr) { ; }
+    if(ptr) { ; }
 
-       info("CGROUP Plugin thread created with task id %d", gettid());
+    info("CGROUP Plugin thread created with task id %d", gettid());
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       struct rusage thread;
+    struct rusage thread;
 
-       // when ZERO, attempt to do it
-       int vdo_sys_fs_cgroup                   = 0;
-       int vdo_cpu_netdata                     = !config_get_boolean("plugin:cgroups", "cgroups plugin resources", 1);
+    // when ZERO, attempt to do it
+    int vdo_sys_fs_cgroup           = 0;
+    int vdo_cpu_netdata             = !config_get_boolean("plugin:cgroups", "cgroups plugin resources", 1);
 
-       // keep track of the time each module was called
-       unsigned long long sutime_sys_fs_cgroup = 0ULL;
+    // keep track of the time each module was called
+    unsigned long long sutime_sys_fs_cgroup = 0ULL;
 
-       // the next time we will run - aligned properly
-       unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
-       unsigned long long sunow;
+    // the next time we will run - aligned properly
+    unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
+    unsigned long long sunow;
 
-       RRDSET *stcpu_thread = NULL;
+    RRDSET *stcpu_thread = NULL;
 
-       for(;1;) {
-               if(unlikely(netdata_exit)) break;
+    for(;1;) {
+        if(unlikely(netdata_exit)) break;
 
-               // delay until it is our time to run
-               while((sunow = time_usec()) < sunext)
-                       sleep_usec(sunext - sunow);
+        // delay until it is our time to run
+        while((sunow = time_usec()) < sunext)
+            sleep_usec(sunext - sunow);
 
-               // find the next time we need to run
-               while(time_usec() > sunext)
-                       sunext += rrd_update_every * 1000000ULL;
+        // find the next time we need to run
+        while(time_usec() > sunext)
+            sunext += rrd_update_every * 1000000ULL;
 
-               if(unlikely(netdata_exit)) break;
+        if(unlikely(netdata_exit)) break;
 
-               // BEGIN -- the job to be done
+        // BEGIN -- the job to be done
 
-               if(!vdo_sys_fs_cgroup) {
-                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
-                       sunow = time_usec();
-                       vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
-                       sutime_sys_fs_cgroup = sunow;
-               }
-               if(unlikely(netdata_exit)) break;
+        if(!vdo_sys_fs_cgroup) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
+            sunow = time_usec();
+            vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
+            sutime_sys_fs_cgroup = sunow;
+        }
+        if(unlikely(netdata_exit)) break;
 
-               // END -- the job is done
+        // END -- the job is done
 
-               // --------------------------------------------------------------------
+        // --------------------------------------------------------------------
 
-               if(!vdo_cpu_netdata) {
-                       getrusage(RUSAGE_THREAD, &thread);
+        if(!vdo_cpu_netdata) {
+            getrusage(RUSAGE_THREAD, &thread);
 
-                       if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
-                       if(!stcpu_thread) {
-                               stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every, RRDSET_TYPE_STACKED);
+            if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
+            if(!stcpu_thread) {
+                stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every, RRDSET_TYPE_STACKED);
 
-                               rrddim_add(stcpu_thread, "user",  NULL,  1, 1000, RRDDIM_INCREMENTAL);
-                               rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
-                       }
-                       else rrdset_next(stcpu_thread);
+                rrddim_add(stcpu_thread, "user",  NULL,  1, 1000, RRDDIM_INCREMENTAL);
+                rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(stcpu_thread);
 
-                       rrddim_set(stcpu_thread, "user"  , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
-                       rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
-                       rrdset_done(stcpu_thread);
-               }
-       }
+            rrddim_set(stcpu_thread, "user"  , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
+            rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
+            rrdset_done(stcpu_thread);
+        }
+    }
 
-       pthread_exit(NULL);
-       return NULL;
+    pthread_exit(NULL);
+    return NULL;
 }
index f6cf52f9cbb2033561c7fabc89ff86b146df3e5b..8c51be1df5e0b08337b61656d2682634eefdf35f 100644 (file)
@@ -1,8 +1,8 @@
 #include "common.h"
 
 typedef struct ksm_name_value {
-       char filename[FILENAME_MAX + 1];
-       unsigned long long value;
+    char filename[FILENAME_MAX + 1];
+    unsigned long long value;
 } KSM_NAME_VALUE;
 
 #define PAGES_SHARED 0
@@ -12,127 +12,127 @@ typedef struct ksm_name_value {
 #define PAGES_TO_SCAN 4
 
 KSM_NAME_VALUE values[] = {
-               [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
-               [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
-               [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
-               [PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL },
-               [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
+        [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
+        [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
+        [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
+        [PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL },
+        [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
 };
 
 int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt) {
-       static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
-       static long page_size = -1;
+    static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
+    static long page_size = -1;
 
-       if(dt) {};
-
-       if(page_size == -1)
-               page_size = sysconf(_SC_PAGESIZE);
-
-       if(!ff_pages_shared) {
-               snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
-               snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
-               ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
-       }
+    if(dt) {};
+
+    if(page_size == -1)
+        page_size = sysconf(_SC_PAGESIZE);
+
+    if(!ff_pages_shared) {
+        snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
+        snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
+        ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
+    }
 
-       if(!ff_pages_sharing) {
-               snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
-               snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
-               ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
-       }
+    if(!ff_pages_sharing) {
+        snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
+        snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
+        ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
+    }
 
-       if(!ff_pages_unshared) {
-               snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
-               snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
-               ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
-       }
+    if(!ff_pages_unshared) {
+        snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
+        snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
+        ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
+    }
 
-       if(!ff_pages_volatile) {
-               snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
-               snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
-               ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
-       }
+    if(!ff_pages_volatile) {
+        snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
+        snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
+        ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
+    }
 
-       if(!ff_pages_to_scan) {
-               snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
-               snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
-               ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
-       }
+    if(!ff_pages_to_scan) {
+        snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
+        snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
+        ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
+    }
 
-       if(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan) return 1;
+    if(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan) return 1;
 
-       unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, pages_to_scan = 0, offered = 0, saved = 0;
+    unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, pages_to_scan = 0, offered = 0, saved = 0;
 
-       ff_pages_shared = procfile_readall(ff_pages_shared);
-       if(!ff_pages_shared) return 0; // we return 0, so that we will retry to open it next time
-       pages_shared = strtoull(procfile_lineword(ff_pages_shared, 0, 0), NULL, 10);
+    ff_pages_shared = procfile_readall(ff_pages_shared);
+    if(!ff_pages_shared) return 0; // we return 0, so that we will retry to open it next time
+    pages_shared = strtoull(procfile_lineword(ff_pages_shared, 0, 0), NULL, 10);
 
-       ff_pages_sharing = procfile_readall(ff_pages_sharing);
-       if(!ff_pages_sharing) return 0; // we return 0, so that we will retry to open it next time
-       pages_sharing = strtoull(procfile_lineword(ff_pages_sharing, 0, 0), NULL, 10);
+    ff_pages_sharing = procfile_readall(ff_pages_sharing);
+    if(!ff_pages_sharing) return 0; // we return 0, so that we will retry to open it next time
+    pages_sharing = strtoull(procfile_lineword(ff_pages_sharing, 0, 0), NULL, 10);
 
-       ff_pages_unshared = procfile_readall(ff_pages_unshared);
-       if(!ff_pages_unshared) return 0; // we return 0, so that we will retry to open it next time
-       pages_unshared = strtoull(procfile_lineword(ff_pages_unshared, 0, 0), NULL, 10);
+    ff_pages_unshared = procfile_readall(ff_pages_unshared);
+    if(!ff_pages_unshared) return 0; // we return 0, so that we will retry to open it next time
+    pages_unshared = strtoull(procfile_lineword(ff_pages_unshared, 0, 0), NULL, 10);
 
-       ff_pages_volatile = procfile_readall(ff_pages_volatile);
-       if(!ff_pages_volatile) return 0; // we return 0, so that we will retry to open it next time
-       pages_volatile = strtoull(procfile_lineword(ff_pages_volatile, 0, 0), NULL, 10);
+    ff_pages_volatile = procfile_readall(ff_pages_volatile);
+    if(!ff_pages_volatile) return 0; // we return 0, so that we will retry to open it next time
+    pages_volatile = strtoull(procfile_lineword(ff_pages_volatile, 0, 0), NULL, 10);
 
-       ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
-       if(!ff_pages_to_scan) return 0; // we return 0, so that we will retry to open it next time
-       pages_to_scan = strtoull(procfile_lineword(ff_pages_to_scan, 0, 0), NULL, 10);
+    ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
+    if(!ff_pages_to_scan) return 0; // we return 0, so that we will retry to open it next time
+    pages_to_scan = strtoull(procfile_lineword(ff_pages_to_scan, 0, 0), NULL, 10);
 
-       offered = pages_sharing + pages_shared + pages_unshared + pages_volatile;
-       saved = pages_sharing - pages_shared;
+    offered = pages_sharing + pages_shared + pages_unshared + pages_volatile;
+    saved = pages_sharing - pages_shared;
 
-       if(!offered || !pages_to_scan) return 0;
+    if(!offered || !pages_to_scan) return 0;
 
-       RRDSET *st;
+    RRDSET *st;
 
-       // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-       st = rrdset_find("mem.ksm");
-       if(!st) {
-               st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
+    st = rrdset_find("mem.ksm");
+    if(!st) {
+        st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
 
-               rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(st);
+        rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(st);
 
-       rrddim_set(st, "shared", pages_shared * page_size);
-       rrddim_set(st, "unshared", pages_unshared * page_size);
-       rrddim_set(st, "sharing", pages_sharing * page_size);
-       rrddim_set(st, "volatile", pages_volatile * page_size);
-       rrddim_set(st, "to_scan", pages_to_scan * page_size);
-       rrdset_done(st);
+    rrddim_set(st, "shared", pages_shared * page_size);
+    rrddim_set(st, "unshared", pages_unshared * page_size);
+    rrddim_set(st, "sharing", pages_sharing * page_size);
+    rrddim_set(st, "volatile", pages_volatile * page_size);
+    rrddim_set(st, "to_scan", pages_to_scan * page_size);
+    rrdset_done(st);
 
-       st = rrdset_find("mem.ksm_savings");
-       if(!st) {
-               st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
+    st = rrdset_find("mem.ksm_savings");
+    if(!st) {
+        st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
 
-               rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
-               rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(st);
+        rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
+        rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(st);
 
-       rrddim_set(st, "savings", saved * page_size);
-       rrddim_set(st, "offered", offered * page_size);
-       rrdset_done(st);
+    rrddim_set(st, "savings", saved * page_size);
+    rrddim_set(st, "offered", offered * page_size);
+    rrdset_done(st);
 
-       st = rrdset_find("mem.ksm_ratios");
-       if(!st) {
-               st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
-
-               rrddim_add(st, "savings", NULL, 1, 10000, RRDDIM_ABSOLUTE);
-       }
-       else rrdset_next(st);
-
-       rrddim_set(st, "savings", (saved * 1000000) / offered);
-       rrdset_done(st);
+    st = rrdset_find("mem.ksm_ratios");
+    if(!st) {
+        st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
+
+        rrddim_add(st, "savings", NULL, 1, 10000, RRDDIM_ABSOLUTE);
+    }
+    else rrdset_next(st);
+
+    rrddim_set(st, "savings", (saved * 1000000) / offered);
+    rrdset_done(st);
 
-       return 0;
+    return 0;
 }
index 1a8ef012acd19083f0bd89c1ccb5c101d3190fc9..a77fdb1349b60a98228b7fc64c3da54f7915c2f8 100644 (file)
 #include "common.h"
 
 int check_storage_number(calculated_number n, int debug) {
-       char buffer[100];
-       uint32_t flags = SN_EXISTS;
-
-       storage_number s = pack_storage_number(n, flags);
-       calculated_number d = unpack_storage_number(s);
-
-       if(!does_storage_number_exist(s)) {
-               fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n);
-               return 5;
-       }
-
-       calculated_number ddiff = d - n;
-       calculated_number dcdiff = ddiff * 100.0 / n;
-
-       if(dcdiff < 0) dcdiff = -dcdiff;
-
-       size_t len = print_calculated_number(buffer, d);
-       calculated_number p = strtold(buffer, NULL);
-       calculated_number pdiff = n - p;
-       calculated_number pcdiff = pdiff * 100.0 / n;
-       if(pcdiff < 0) pcdiff = -pcdiff;
-
-       if(debug) {
-               fprintf(stderr,
-                       CALCULATED_NUMBER_FORMAT " original\n"
-                       CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
-                       "%s printed after unpacked (%zu bytes)\n"
-                       CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
-                       n,
-                       d, s, ddiff, dcdiff,
-                       buffer,
-                       len, p, pdiff, pcdiff
-               );
-               if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
-               if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
-               if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, pcdiff);
-       }
-
-       if(len != strlen(buffer)) return 1;
-       if(dcdiff > ACCURACY_LOSS) return 3;
-       if(pcdiff > ACCURACY_LOSS) return 4;
-       return 0;
+    char buffer[100];
+    uint32_t flags = SN_EXISTS;
+
+    storage_number s = pack_storage_number(n, flags);
+    calculated_number d = unpack_storage_number(s);
+
+    if(!does_storage_number_exist(s)) {
+        fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n);
+        return 5;
+    }
+
+    calculated_number ddiff = d - n;
+    calculated_number dcdiff = ddiff * 100.0 / n;
+
+    if(dcdiff < 0) dcdiff = -dcdiff;
+
+    size_t len = print_calculated_number(buffer, d);
+    calculated_number p = strtold(buffer, NULL);
+    calculated_number pdiff = n - p;
+    calculated_number pcdiff = pdiff * 100.0 / n;
+    if(pcdiff < 0) pcdiff = -pcdiff;
+
+    if(debug) {
+        fprintf(stderr,
+            CALCULATED_NUMBER_FORMAT " original\n"
+            CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
+            "%s printed after unpacked (%zu bytes)\n"
+            CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
+            n,
+            d, s, ddiff, dcdiff,
+            buffer,
+            len, p, pdiff, pcdiff
+        );
+        if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
+        if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
+        if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, pcdiff);
+    }
+
+    if(len != strlen(buffer)) return 1;
+    if(dcdiff > ACCURACY_LOSS) return 3;
+    if(pcdiff > ACCURACY_LOSS) return 4;
+    return 0;
 }
 
 void benchmark_storage_number(int loop, int multiplier) {
-       int i, j;
-       calculated_number n, d;
-       storage_number s;
-       unsigned long long user, system, total, mine, their;
+    int i, j;
+    calculated_number n, d;
+    storage_number s;
+    unsigned long long user, system, total, mine, their;
 
-       char buffer[100];
+    char buffer[100];
 
-       struct rusage now, last;
+    struct rusage now, last;
 
-       fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
+    fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       fprintf(stderr, "SYSTEM  LONG DOUBLE    SIZE: %zu bytes\n", sizeof(calculated_number));
-       fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number));
+    fprintf(stderr, "SYSTEM  LONG DOUBLE    SIZE: %zu bytes\n", sizeof(calculated_number));
+    fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number));
 
-       mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
-       their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
+    mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
+    their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
 
-       if(mine > their) {
-               fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
-       }
-       else {
-               fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
-       }
+    if(mine > their) {
+        fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
+    }
+    else {
+        fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
+    }
 
-       fprintf(stderr, "\nNETDATA FLOATING POINT\n");
-       fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
-       fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
-       fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
-       fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
-       fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
+    fprintf(stderr, "\nNETDATA FLOATING POINT\n");
+    fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
+    fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
+    fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
+    fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
+    fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
-       getrusage(RUSAGE_SELF, &last);
+    fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
+    getrusage(RUSAGE_SELF, &last);
 
-       // do the job
-       for(j = 1; j < 11 ;j++) {
-               n = STORAGE_NUMBER_POSITIVE_MIN * j;
+    // do the job
+    for(j = 1; j < 11 ;j++) {
+        n = STORAGE_NUMBER_POSITIVE_MIN * j;
 
-               for(i = 0; i < loop ;i++) {
-                       n *= multiplier;
-                       if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
+        for(i = 0; i < loop ;i++) {
+            n *= multiplier;
+            if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
 
-                       print_calculated_number(buffer, n);
-               }
-       }
+            print_calculated_number(buffer, n);
+        }
+    }
 
-       getrusage(RUSAGE_SELF, &now);
-       user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
-       system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
-       total  = user + system;
-       mine = total;
+    getrusage(RUSAGE_SELF, &now);
+    user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
+    system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
+    total  = user + system;
+    mine = total;
 
-       fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
+    fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       fprintf(stderr, "SYSTEM   LONG DOUBLE PRINTING: ");
-       getrusage(RUSAGE_SELF, &last);
+    fprintf(stderr, "SYSTEM   LONG DOUBLE PRINTING: ");
+    getrusage(RUSAGE_SELF, &last);
 
-       // do the job
-       for(j = 1; j < 11 ;j++) {
-               n = STORAGE_NUMBER_POSITIVE_MIN * j;
+    // do the job
+    for(j = 1; j < 11 ;j++) {
+        n = STORAGE_NUMBER_POSITIVE_MIN * j;
 
-               for(i = 0; i < loop ;i++) {
-                       n *= multiplier;
-                       if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
-                       snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
-               }
-       }
+        for(i = 0; i < loop ;i++) {
+            n *= multiplier;
+            if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
+            snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
+        }
+    }
 
-       getrusage(RUSAGE_SELF, &now);
-       user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
-       system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
-       total  = user + system;
-       their = total;
+    getrusage(RUSAGE_SELF, &now);
+    user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
+    system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
+    total  = user + system;
+    their = total;
 
-       fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
+    fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
 
-       if(mine > total) {
-               fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
-       }
-       else {
-               fprintf(stderr, "NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
-       }
+    if(mine > total) {
+        fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
+    }
+    else {
+        fprintf(stderr, "NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
+    }
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
-       fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
-       getrusage(RUSAGE_SELF, &last);
+    fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
+    getrusage(RUSAGE_SELF, &last);
 
-       // do the job
-       for(j = 1; j < 11 ;j++) {
-               n = STORAGE_NUMBER_POSITIVE_MIN * j;
+    // do the job
+    for(j = 1; j < 11 ;j++) {
+        n = STORAGE_NUMBER_POSITIVE_MIN * j;
 
-               for(i = 0; i < loop ;i++) {
-                       n *= multiplier;
-                       if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
+        for(i = 0; i < loop ;i++) {
+            n *= multiplier;
+            if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
 
-                       s = pack_storage_number(n, 1);
-                       d = unpack_storage_number(s);
-                       print_calculated_number(buffer, d);
-               }
-       }
+            s = pack_storage_number(n, 1);
+            d = unpack_storage_number(s);
+            print_calculated_number(buffer, d);
+        }
+    }
 
-       getrusage(RUSAGE_SELF, &now);
-       user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
-       system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
-       total  = user + system;
-       mine = total;
-
-       fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
+    getrusage(RUSAGE_SELF, &now);
+    user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
+    system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
+    total  = user + system;
+    mine = total;
+
+    fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
 
-       if(mine > their) {
-               fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
-       }
-       else {
-               fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
-       }
+    if(mine > their) {
+        fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
+    }
+    else {
+        fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
+    }
 
-       // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
 }
 
 static int check_storage_number_exists() {
-       uint32_t flags = SN_EXISTS;
-
-
-       for(flags = 0; flags < 7 ; flags++) {
-               if(get_storage_number_flags(flags << 24) != flags << 24) {
-                       fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
-                       return 1;
-               }
-       }
-
-       flags = SN_EXISTS;
-       calculated_number n = 0.0;
-
-       storage_number s = pack_storage_number(n, flags);
-       calculated_number d = unpack_storage_number(s);
-       if(get_storage_number_flags(s) != flags) {
-               fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
-               return 1;
-       }
-       if(n != d) {
-               fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
-               return 1;
-       }
-
-       return 0;
+    uint32_t flags = SN_EXISTS;
+
+
+    for(flags = 0; flags < 7 ; flags++) {
+        if(get_storage_number_flags(flags << 24) != flags << 24) {
+            fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
+            return 1;
+        }
+    }
+
+    flags = SN_EXISTS;
+    calculated_number n = 0.0;
+
+    storage_number s = pack_storage_number(n, flags);
+    calculated_number d = unpack_storage_number(s);
+    if(get_storage_number_flags(s) != flags) {
+        fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
+        return 1;
+    }
+    if(n != d) {
+        fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
+        return 1;
+    }
+
+    return 0;
 }
 
 int unit_test_storage()
 {
-       if(check_storage_number_exists()) return 0;
+    if(check_storage_number_exists()) return 0;
 
-       calculated_number c, a = 0;
-       int i, j, g, r = 0;
+    calculated_number c, a = 0;
+    int i, j, g, r = 0;
 
-       for(g = -1; g <= 1 ; g++) {
-               a = 0;
+    for(g = -1; g <= 1 ; g++) {
+        a = 0;
 
-               if(!g) continue;
+        if(!g) continue;
 
-               for(j = 0; j < 9 ;j++) {
-                       a += 0.0000001;
-                       c = a * g;
-                       for(i = 0; i < 21 ;i++, c *= 10) {
-                               if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
-                               if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
+        for(j = 0; j < 9 ;j++) {
+            a += 0.0000001;
+            c = a * g;
+            for(i = 0; i < 21 ;i++, c *= 10) {
+                if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
+                if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
 
-                               if(check_storage_number(c, 1)) return 1;
-                       }
-               }
-       }
+                if(check_storage_number(c, 1)) return 1;
+            }
+        }
+    }
 
-       benchmark_storage_number(1000000, 2);
-       return r;
+    benchmark_storage_number(1000000, 2);
+    return r;
 }
 
 
 // --------------------------------------------------------------------------------------------------------------------
 
 struct feed_values {
-               unsigned long long microseconds;
-               collected_number value;
+        unsigned long long microseconds;
+        collected_number value;
 };
 
 struct test {
-       char name[100];
-       char description[1024];
+    char name[100];
+    char description[1024];
 
-       int update_every;
-       unsigned long long multiplier;
-       unsigned long long divisor;
-       int algorithm;
+    int update_every;
+    unsigned long long multiplier;
+    unsigned long long divisor;
+    int algorithm;
 
-       unsigned long feed_entries;
-       unsigned long result_entries;
-       struct feed_values *feed;
-       calculated_number *results;
+    unsigned long feed_entries;
+    unsigned long result_entries;
+    struct feed_values *feed;
+    calculated_number *results;
 
-       collected_number *feed2;
-       calculated_number *results2;
+    collected_number *feed2;
+    calculated_number *results2;
 };
 
 // --------------------------------------------------------------------------------------------------------------------
@@ -260,35 +260,35 @@ struct test {
 // test absolute values stored
 
 struct feed_values test1_feed[] = {
-               { 0, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 0, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 calculated_number test1_results[] = {
-               20, 30, 40, 50, 60, 70, 80, 90, 100
+        20, 30, 40, 50, 60, 70, 80, 90, 100
 };
 
 struct test test1 = {
-               "test1",                        // name
-               "test absolute values stored at exactly second boundaries",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_ABSOLUTE,        // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test1_feed,                     // feed
-               test1_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test1",            // name
+        "test absolute values stored at exactly second boundaries",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_ABSOLUTE,    // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test1_feed,         // feed
+        test1_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
@@ -296,667 +296,667 @@ struct test test1 = {
 // test absolute values stored in the middle of second boundaries
 
 struct feed_values test2_feed[] = {
-               { 500000, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 500000, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 calculated_number test2_results[] = {
-               20, 30, 40, 50, 60, 70, 80, 90, 100
+        20, 30, 40, 50, 60, 70, 80, 90, 100
 };
 
 struct test test2 = {
-               "test2",                        // name
-               "test absolute values stored in the middle of second boundaries",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_ABSOLUTE,        // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test2_feed,                     // feed
-               test2_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test2",            // name
+        "test absolute values stored in the middle of second boundaries",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_ABSOLUTE,    // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test2_feed,         // feed
+        test2_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test3
 
 struct feed_values test3_feed[] = {
-               { 0, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 0, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 calculated_number test3_results[] = {
-               10, 10, 10, 10, 10, 10, 10, 10, 10
+        10, 10, 10, 10, 10, 10, 10, 10, 10
 };
 
 struct test test3 = {
-               "test3",                        // name
-               "test incremental values stored at exactly second boundaries",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test3_feed,                     // feed
-               test3_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test3",            // name
+        "test incremental values stored at exactly second boundaries",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test3_feed,         // feed
+        test3_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test4
 
 struct feed_values test4_feed[] = {
-               { 500000, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 500000, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 calculated_number test4_results[] = {
-               5, 10, 10, 10, 10, 10, 10, 10, 10
+        5, 10, 10, 10, 10, 10, 10, 10, 10
 };
 
 struct test test4 = {
-               "test4",                        // name
-               "test incremental values stored in the middle of second boundaries",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test4_feed,                     // feed
-               test4_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test4",            // name
+        "test incremental values stored in the middle of second boundaries",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test4_feed,         // feed
+        test4_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test5
 
 struct feed_values test5_feed[] = {
-               { 500000, 1000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
-               { 1000000, 3000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
-               { 1000000, 2000 },
+        { 500000, 1000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
+        { 1000000, 3000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
+        { 1000000, 2000 },
 };
 
 calculated_number test5_results[] = {
-               500, 500, 0, 500, 500, 0, 0, 0, 0
+        500, 500, 0, 500, 500, 0, 0, 0, 0
 };
 
 struct test test5 = {
-               "test5",                        // name
-               "test incremental values ups and downs",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test5_feed,                     // feed
-               test5_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test5",            // name
+        "test incremental values ups and downs",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test5_feed,         // feed
+        test5_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test6
 
 struct feed_values test6_feed[] = {
-               { 250000, 1000 },
-               { 250000, 2000 },
-               { 250000, 3000 },
-               { 250000, 4000 },
-               { 250000, 5000 },
-               { 250000, 6000 },
-               { 250000, 7000 },
-               { 250000, 8000 },
-               { 250000, 9000 },
-               { 250000, 10000 },
-               { 250000, 11000 },
-               { 250000, 12000 },
-               { 250000, 13000 },
-               { 250000, 14000 },
-               { 250000, 15000 },
-               { 250000, 16000 },
+        { 250000, 1000 },
+        { 250000, 2000 },
+        { 250000, 3000 },
+        { 250000, 4000 },
+        { 250000, 5000 },
+        { 250000, 6000 },
+        { 250000, 7000 },
+        { 250000, 8000 },
+        { 250000, 9000 },
+        { 250000, 10000 },
+        { 250000, 11000 },
+        { 250000, 12000 },
+        { 250000, 13000 },
+        { 250000, 14000 },
+        { 250000, 15000 },
+        { 250000, 16000 },
 };
 
 calculated_number test6_results[] = {
-               3000, 4000, 4000, 4000
+        3000, 4000, 4000, 4000
 };
 
 struct test test6 = {
-               "test6",                        // name
-               "test incremental values updated within the same second",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               16,                                     // feed entries
-               4,                                      // result entries
-               test6_feed,                     // feed
-               test6_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test6",            // name
+        "test incremental values updated within the same second",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        16,                 // feed entries
+        4,                  // result entries
+        test6_feed,         // feed
+        test6_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test7
 
 struct feed_values test7_feed[] = {
-               { 500000, 1000 },
-               { 2000000, 2000 },
-               { 2000000, 3000 },
-               { 2000000, 4000 },
-               { 2000000, 5000 },
-               { 2000000, 6000 },
-               { 2000000, 7000 },
-               { 2000000, 8000 },
-               { 2000000, 9000 },
-               { 2000000, 10000 },
+        { 500000, 1000 },
+        { 2000000, 2000 },
+        { 2000000, 3000 },
+        { 2000000, 4000 },
+        { 2000000, 5000 },
+        { 2000000, 6000 },
+        { 2000000, 7000 },
+        { 2000000, 8000 },
+        { 2000000, 9000 },
+        { 2000000, 10000 },
 };
 
 calculated_number test7_results[] = {
-               250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
+        250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
 };
 
 struct test test7 = {
-               "test7",                        // name
-               "test incremental values updated in long durations",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               10,                                     // feed entries
-               18,                                     // result entries
-               test7_feed,                     // feed
-               test7_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test7",            // name
+        "test incremental values updated in long durations",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        10,                 // feed entries
+        18,                 // result entries
+        test7_feed,         // feed
+        test7_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test8
 
 struct feed_values test8_feed[] = {
-               { 500000, 1000 },
-               { 2000000, 2000 },
-               { 2000000, 3000 },
-               { 2000000, 4000 },
-               { 2000000, 5000 },
-               { 2000000, 6000 },
+        { 500000, 1000 },
+        { 2000000, 2000 },
+        { 2000000, 3000 },
+        { 2000000, 4000 },
+        { 2000000, 5000 },
+        { 2000000, 6000 },
 };
 
 calculated_number test8_results[] = {
-               1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
+        1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
 };
 
 struct test test8 = {
-               "test8",                        // name
-               "test absolute values updated in long durations",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_ABSOLUTE,        // algorithm
-               6,                                      // feed entries
-               10,                                     // result entries
-               test8_feed,                     // feed
-               test8_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test8",            // name
+        "test absolute values updated in long durations",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_ABSOLUTE,    // algorithm
+        6,                  // feed entries
+        10,                 // result entries
+        test8_feed,         // feed
+        test8_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test9
 
 struct feed_values test9_feed[] = {
-               { 250000, 1000 },
-               { 250000, 2000 },
-               { 250000, 3000 },
-               { 250000, 4000 },
-               { 250000, 5000 },
-               { 250000, 6000 },
-               { 250000, 7000 },
-               { 250000, 8000 },
-               { 250000, 9000 },
-               { 250000, 10000 },
-               { 250000, 11000 },
-               { 250000, 12000 },
-               { 250000, 13000 },
-               { 250000, 14000 },
-               { 250000, 15000 },
-               { 250000, 16000 },
+        { 250000, 1000 },
+        { 250000, 2000 },
+        { 250000, 3000 },
+        { 250000, 4000 },
+        { 250000, 5000 },
+        { 250000, 6000 },
+        { 250000, 7000 },
+        { 250000, 8000 },
+        { 250000, 9000 },
+        { 250000, 10000 },
+        { 250000, 11000 },
+        { 250000, 12000 },
+        { 250000, 13000 },
+        { 250000, 14000 },
+        { 250000, 15000 },
+        { 250000, 16000 },
 };
 
 calculated_number test9_results[] = {
-               4000, 8000, 12000, 16000
+        4000, 8000, 12000, 16000
 };
 
 struct test test9 = {
-               "test9",                        // name
-               "test absolute values updated within the same second",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_ABSOLUTE,        // algorithm
-               16,                                     // feed entries
-               4,                                      // result entries
-               test9_feed,                     // feed
-               test9_results,          // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test9",            // name
+        "test absolute values updated within the same second",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_ABSOLUTE,    // algorithm
+        16,                 // feed entries
+        4,                  // result entries
+        test9_feed,         // feed
+        test9_results,      // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test10
 
 struct feed_values test10_feed[] = {
-               { 500000,  1000 },
-               { 600000,  1000 +  600 },
-               { 200000,  1600 +  200 },
-               { 1000000, 1800 + 1000 },
-               { 200000,  2800 +  200 },
-               { 2000000, 3000 + 2000 },
-               { 600000,  5000 +  600 },
-               { 400000,  5600 +  400 },
-               { 900000,  6000 +  900 },
-               { 1000000, 6900 + 1000 },
+        { 500000,  1000 },
+        { 600000,  1000 +  600 },
+        { 200000,  1600 +  200 },
+        { 1000000, 1800 + 1000 },
+        { 200000,  2800 +  200 },
+        { 2000000, 3000 + 2000 },
+        { 600000,  5000 +  600 },
+        { 400000,  5600 +  400 },
+        { 900000,  6000 +  900 },
+        { 1000000, 6900 + 1000 },
 };
 
 calculated_number test10_results[] = {
-               500, 1000, 1000, 1000, 1000, 1000, 1000
+        500, 1000, 1000, 1000, 1000, 1000, 1000
 };
 
 struct test test10 = {
-               "test10",                       // name
-               "test incremental values updated in short and long durations",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_INCREMENTAL,     // algorithm
-               10,                                     // feed entries
-               7,                                      // result entries
-               test10_feed,            // feed
-               test10_results,         // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test10",           // name
+        "test incremental values updated in short and long durations",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_INCREMENTAL, // algorithm
+        10,                 // feed entries
+        7,                  // result entries
+        test10_feed,        // feed
+        test10_results,     // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test11
 
 struct feed_values test11_feed[] = {
-               { 0, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 0, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 collected_number test11_feed2[] = {
-       10, 20, 30, 40, 50, 60, 70, 80, 90, 100
+    10, 20, 30, 40, 50, 60, 70, 80, 90, 100
 };
 
 calculated_number test11_results[] = {
-               50, 50, 50, 50, 50, 50, 50, 50, 50
+        50, 50, 50, 50, 50, 50, 50, 50, 50
 };
 
 calculated_number test11_results2[] = {
-               50, 50, 50, 50, 50, 50, 50, 50, 50
+        50, 50, 50, 50, 50, 50, 50, 50, 50
 };
 
 struct test test11 = {
-               "test11",                       // name
-               "test percentage-of-incremental-row with equal values",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test11_feed,            // feed
-               test11_results,         // results
-               test11_feed2,           // feed2
-               test11_results2         // results2
+        "test11",           // name
+        "test percentage-of-incremental-row with equal values",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test11_feed,        // feed
+        test11_results,     // results
+        test11_feed2,       // feed2
+        test11_results2     // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test12
 
 struct feed_values test12_feed[] = {
-               { 0, 10 },
-               { 1000000, 20 },
-               { 1000000, 30 },
-               { 1000000, 40 },
-               { 1000000, 50 },
-               { 1000000, 60 },
-               { 1000000, 70 },
-               { 1000000, 80 },
-               { 1000000, 90 },
-               { 1000000, 100 },
+        { 0, 10 },
+        { 1000000, 20 },
+        { 1000000, 30 },
+        { 1000000, 40 },
+        { 1000000, 50 },
+        { 1000000, 60 },
+        { 1000000, 70 },
+        { 1000000, 80 },
+        { 1000000, 90 },
+        { 1000000, 100 },
 };
 
 collected_number test12_feed2[] = {
-       10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3
+    10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3
 };
 
 calculated_number test12_results[] = {
-               25, 25, 25, 25, 25, 25, 25, 25, 25
+        25, 25, 25, 25, 25, 25, 25, 25, 25
 };
 
 calculated_number test12_results2[] = {
-               75, 75, 75, 75, 75, 75, 75, 75, 75
+        75, 75, 75, 75, 75, 75, 75, 75, 75
 };
 
 struct test test12 = {
-               "test12",                       // name
-               "test percentage-of-incremental-row with equal values",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
-               10,                                     // feed entries
-               9,                                      // result entries
-               test12_feed,            // feed
-               test12_results,         // results
-               test12_feed2,           // feed2
-               test12_results2         // results2
+        "test12",           // name
+        "test percentage-of-incremental-row with equal values",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
+        10,                 // feed entries
+        9,                  // result entries
+        test12_feed,        // feed
+        test12_results,     // results
+        test12_feed2,       // feed2
+        test12_results2     // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 // test13
 
 struct feed_values test13_feed[] = {
-               { 500000,  1000 },
-               { 600000,  1000 +  600 },
-               { 200000,  1600 +  200 },
-               { 1000000, 1800 + 1000 },
-               { 200000,  2800 +  200 },
-               { 2000000, 3000 + 2000 },
-               { 600000,  5000 +  600 },
-               { 400000,  5600 +  400 },
-               { 900000,  6000 +  900 },
-               { 1000000, 6900 + 1000 },
+        { 500000,  1000 },
+        { 600000,  1000 +  600 },
+        { 200000,  1600 +  200 },
+        { 1000000, 1800 + 1000 },
+        { 200000,  2800 +  200 },
+        { 2000000, 3000 + 2000 },
+        { 600000,  5000 +  600 },
+        { 400000,  5600 +  400 },
+        { 900000,  6000 +  900 },
+        { 1000000, 6900 + 1000 },
 };
 
 calculated_number test13_results[] = {
-               83.3333300, 100, 100, 100, 100, 100, 100
+        83.3333300, 100, 100, 100, 100, 100, 100
 };
 
 struct test test13 = {
-               "test13",                       // name
-               "test incremental values updated in short and long durations",
-               1,                                      // update_every
-               1,                                      // multiplier
-               1,                                      // divisor
-               RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
-               10,                                     // feed entries
-               7,                                      // result entries
-               test13_feed,            // feed
-               test13_results,         // results
-               NULL,                           // feed2
-               NULL                            // results2
+        "test13",           // name
+        "test incremental values updated in short and long durations",
+        1,                  // update_every
+        1,                  // multiplier
+        1,                  // divisor
+        RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
+        10,                 // feed entries
+        7,                  // result entries
+        test13_feed,        // feed
+        test13_results,     // results
+        NULL,               // feed2
+        NULL                // results2
 };
 
 // --------------------------------------------------------------------------------------------------------------------
 
 int run_test(struct test *test)
 {
-       fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
-
-       rrd_memory_mode = RRD_MEMORY_MODE_RAM;
-       rrd_update_every = test->update_every;
-
-       char name[101];
-       snprintfz(name, 100, "unittest-%s", test->name);
-
-       // create the chart
-       RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
-       RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
-       
-       RRDDIM *rd2 = NULL;
-       if(test->feed2)
-               rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
-
-       st->debug = 1;
-
-       // feed it with the test data
-       unsigned long c;
-       for(c = 0; c < test->feed_entries; c++) {
-               if(debug_flags) fprintf(stderr, "\n\n");
-
-               if(c) {
-                       fprintf(stderr, "    > %s: feeding position %lu, after %llu microseconds\n", test->name, c+1, test->feed[c].microseconds);
-                       rrdset_next_usec(st, test->feed[c].microseconds);
-               }
-               else {
-                       fprintf(stderr, "    > %s: feeding position %lu\n", test->name, c+1);
-               }
-
-               fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
-               rrddim_set(st, "dim1", test->feed[c].value);
-
-               if(rd2) {
-                       fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
-                       rrddim_set(st, "dim2", test->feed2[c]);
-               }
-
-               rrdset_done(st);
-
-               // align the first entry to second boundary
-               if(!c) {
-                       fprintf(stderr, "    > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
-                       rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
-               }
-       }
-
-       // check the result
-       int errors = 0;
-
-       if(st->counter != test->result_entries) {
-               fprintf(stderr, "    %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
-               errors++;
-       }
-
-       unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
-       for(c = 0 ; c < max ; c++) {
-               calculated_number v = unpack_storage_number(rd->values[c]);
-               calculated_number n = test->results[c];
-               int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
-               fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
-               if(!same) errors++;
-
-               if(rd2) {
-                       v = unpack_storage_number(rd2->values[c]);
-                       n = test->results2[c];
-                       same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
-                       fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd2->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
-                       if(!same) errors++;
-               }
-       }
-
-       return errors;
+    fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
+
+    rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+    rrd_update_every = test->update_every;
+
+    char name[101];
+    snprintfz(name, 100, "unittest-%s", test->name);
+
+    // create the chart
+    RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
+    RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
+    
+    RRDDIM *rd2 = NULL;
+    if(test->feed2)
+        rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
+
+    st->debug = 1;
+
+    // feed it with the test data
+    unsigned long c;
+    for(c = 0; c < test->feed_entries; c++) {
+        if(debug_flags) fprintf(stderr, "\n\n");
+
+        if(c) {
+            fprintf(stderr, "    > %s: feeding position %lu, after %llu microseconds\n", test->name, c+1, test->feed[c].microseconds);
+            rrdset_next_usec(st, test->feed[c].microseconds);
+        }
+        else {
+            fprintf(stderr, "    > %s: feeding position %lu\n", test->name, c+1);
+        }
+
+        fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
+        rrddim_set(st, "dim1", test->feed[c].value);
+
+        if(rd2) {
+            fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
+            rrddim_set(st, "dim2", test->feed2[c]);
+        }
+
+        rrdset_done(st);
+
+        // align the first entry to second boundary
+        if(!c) {
+            fprintf(stderr, "    > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
+            rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
+        }
+    }
+
+    // check the result
+    int errors = 0;
+
+    if(st->counter != test->result_entries) {
+        fprintf(stderr, "    %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
+        errors++;
+    }
+
+    unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
+    for(c = 0 ; c < max ; c++) {
+        calculated_number v = unpack_storage_number(rd->values[c]);
+        calculated_number n = test->results[c];
+        int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
+        fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
+        if(!same) errors++;
+
+        if(rd2) {
+            v = unpack_storage_number(rd2->values[c]);
+            n = test->results2[c];
+            same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
+            fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd2->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
+            if(!same) errors++;
+        }
+    }
+
+    return errors;
 }
 
 int run_all_mockup_tests(void)
 {
-       if(run_test(&test1))
-               return 1;
+    if(run_test(&test1))
+        return 1;
 
-       if(run_test(&test2))
-               return 1;
+    if(run_test(&test2))
+        return 1;
 
-       if(run_test(&test3))
-               return 1;
+    if(run_test(&test3))
+        return 1;
 
-       if(run_test(&test4))
-               return 1;
+    if(run_test(&test4))
+        return 1;
 
-       if(run_test(&test5))
-               return 1;
+    if(run_test(&test5))
+        return 1;
 
-       if(run_test(&test6))
-               return 1;
+    if(run_test(&test6))
+        return 1;
 
-       if(run_test(&test7))
-               return 1;
+    if(run_test(&test7))
+        return 1;
 
-       if(run_test(&test8))
-               return 1;
+    if(run_test(&test8))
+        return 1;
 
-       if(run_test(&test9))
-               return 1;
+    if(run_test(&test9))
+        return 1;
 
-       if(run_test(&test10))
-               return 1;
+    if(run_test(&test10))
+        return 1;
 
-       if(run_test(&test11))
-               return 1;
+    if(run_test(&test11))
+        return 1;
 
-       if(run_test(&test12))
-               return 1;
+    if(run_test(&test12))
+        return 1;
 
-       if(run_test(&test13))
-               return 1;
+    if(run_test(&test13))
+        return 1;
 
-       return 0;
+    return 0;
 }
 
 int unit_test(long delay, long shift)
 {
-       static int repeat = 0;
-       repeat++;
-
-       char name[101];
-       snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
-
-       //debug_flags = 0xffffffff;
-       rrd_memory_mode = RRD_MEMORY_MODE_RAM;
-       rrd_update_every = 1;
-
-       int do_abs = 1;
-       int do_inc = 1;
-       int do_abst = 0;
-       int do_absi = 0;
-
-       RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
-       st->debug = 1;
-
-       RRDDIM *rdabs = NULL;
-       RRDDIM *rdinc = NULL;
-       RRDDIM *rdabst = NULL;
-       RRDDIM *rdabsi = NULL;
-
-       if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
-       if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
-       if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
-       if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
-
-       long increment = 1000;
-       collected_number i = 0;
-
-       unsigned long c, dimensions = 0;
-       RRDDIM *rd;
-       for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
-
-       for(c = 0; c < 20 ;c++) {
-               i += increment;
-
-               fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
-               if(c) {
-                       rrdset_next_usec(st, delay);
-               }
-               if(do_abs) rrddim_set(st, "absolute", i);
-               if(do_inc) rrddim_set(st, "incremental", i);
-               if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
-               if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
-
-               if(!c) {
-                       gettimeofday(&st->last_collected_time, NULL);
-                       st->last_collected_time.tv_usec = shift;
-               }
-
-               // prevent it from deleting the dimensions
-               for(rd = st->dimensions ; rd ; rd = rd->next)
-                       rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
-
-               rrdset_done(st);
-       }
-
-       unsigned long oincrement = increment;
-       increment = increment * st->update_every * 1000000 / delay;
-       fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift);
-
-       int ret = 0;
-       storage_number sn;
-       calculated_number cn, v;
-       for(c = 0 ; c < st->counter ; c++) {
-               fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
-
-               for(rd = st->dimensions ; rd ; rd = rd->next) {
-                       sn = rd->values[c];
-                       cn = unpack_storage_number(sn);
-                       fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ")   ->   ", rd->id, cn, sn);
-
-                       if(rd == rdabs) v =
-                               (         oincrement
-                                       // + (increment * (1000000 - shift) / 1000000)
-                                       + (c + 1) * increment
-                               );
-
-                       else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
-                       else if(rd == rdabst) v = oincrement / dimensions / 10;
-                       else if(rd == rdabsi) v = oincrement / dimensions / 10;
-                       else v = 0;
-
-                       if(v == cn) fprintf(stderr, "passed.\n");
-                       else {
-                               fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
-                               ret = 1;
-                       }
-               }
-       }
-
-       if(ret)
-               fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
-
-       return ret;
+    static int repeat = 0;
+    repeat++;
+
+    char name[101];
+    snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
+
+    //debug_flags = 0xffffffff;
+    rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+    rrd_update_every = 1;
+
+    int do_abs = 1;
+    int do_inc = 1;
+    int do_abst = 0;
+    int do_absi = 0;
+
+    RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
+    st->debug = 1;
+
+    RRDDIM *rdabs = NULL;
+    RRDDIM *rdinc = NULL;
+    RRDDIM *rdabst = NULL;
+    RRDDIM *rdabsi = NULL;
+
+    if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
+    if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
+    if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
+    if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+
+    long increment = 1000;
+    collected_number i = 0;
+
+    unsigned long c, dimensions = 0;
+    RRDDIM *rd;
+    for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
+
+    for(c = 0; c < 20 ;c++) {
+        i += increment;
+
+        fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
+        if(c) {
+            rrdset_next_usec(st, delay);
+        }
+        if(do_abs) rrddim_set(st, "absolute", i);
+        if(do_inc) rrddim_set(st, "incremental", i);
+        if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
+        if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
+
+        if(!c) {
+            gettimeofday(&st->last_collected_time, NULL);
+            st->last_collected_time.tv_usec = shift;
+        }
+
+        // prevent it from deleting the dimensions
+        for(rd = st->dimensions ; rd ; rd = rd->next)
+            rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
+
+        rrdset_done(st);
+    }
+
+    unsigned long oincrement = increment;
+    increment = increment * st->update_every * 1000000 / delay;
+    fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift);
+
+    int ret = 0;
+    storage_number sn;
+    calculated_number cn, v;
+    for(c = 0 ; c < st->counter ; c++) {
+        fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
+
+        for(rd = st->dimensions ; rd ; rd = rd->next) {
+            sn = rd->values[c];
+            cn = unpack_storage_number(sn);
+            fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ")   ->   ", rd->id, cn, sn);
+
+            if(rd == rdabs) v =
+                (     oincrement
+                    // + (increment * (1000000 - shift) / 1000000)
+                    + (c + 1) * increment
+                );
+
+            else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
+            else if(rd == rdabst) v = oincrement / dimensions / 10;
+            else if(rd == rdabsi) v = oincrement / dimensions / 10;
+            else v = 0;
+
+            if(v == cn) fprintf(stderr, "passed.\n");
+            else {
+                fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
+                ret = 1;
+            }
+        }
+    }
+
+    if(ret)
+        fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
+
+    return ret;
 }
index 44c5a6dc9cc166406e06a7dcd8fe6a742e2dc945..6be4d96489351d84374642169f38e94d7f132996 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -6,72 +6,72 @@
 
 /* Converts a hex character to its integer value */
 char from_hex(char ch) {
-       return (char)(isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10);
+    return (char)(isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10);
 }
 
 /* Converts an integer value to its hex character*/
 char to_hex(char code) {
-       static char hex[] = "0123456789abcdef";
-       return hex[code & 15];
+    static char hex[] = "0123456789abcdef";
+    return hex[code & 15];
 }
 
 /* Returns a url-encoded version of str */
 /* IMPORTANT: be sure to free() the returned string after use */
 char *url_encode(char *str) {
-       char *buf, *pbuf;
+    char *buf, *pbuf;
 
-       pbuf = buf = mallocz(strlen(str) * 3 + 1);
+    pbuf = buf = mallocz(strlen(str) * 3 + 1);
 
-       while (*str) {
-               if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
-                       *pbuf++ = *str;
+    while (*str) {
+        if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
+            *pbuf++ = *str;
 
-               else if (*str == ' ')
-                       *pbuf++ = '+';
+        else if (*str == ' ')
+            *pbuf++ = '+';
 
-               else
-                       *pbuf++ = '%', *pbuf++ = to_hex(*str >> 4), *pbuf++ = to_hex(*str & 15);
+        else
+            *pbuf++ = '%', *pbuf++ = to_hex(*str >> 4), *pbuf++ = to_hex(*str & 15);
 
-               str++;
-       }
-       *pbuf = '\0';
+        str++;
+    }
+    *pbuf = '\0';
 
-       pbuf = strdupz(buf);
-       freez(buf);
-       return pbuf;
+    pbuf = strdupz(buf);
+    freez(buf);
+    return pbuf;
 }
 
 /* Returns a url-decoded version of str */
 /* IMPORTANT: be sure to free() the returned string after use */
 char *url_decode(char *str) {
-       size_t size = strlen(str) + 1;
+    size_t size = strlen(str) + 1;
 
-       char *buf = mallocz(size);
-       return url_decode_r(buf, str, size);
+    char *buf = mallocz(size);
+    return url_decode_r(buf, str, size);
 }
 
 char *url_decode_r(char *to, char *url, size_t size) {
-       char *s = url,           // source
-                *d = to,            // destination
-                *e = &to[size - 1]; // destination end
+    char *s = url,           // source
+         *d = to,            // destination
+         *e = &to[size - 1]; // destination end
 
-       while(*s && d < e) {
-               if(unlikely(*s == '%')) {
-                       if(likely(s[1] && s[2])) {
-                               *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
-                               s += 2;
-                       }
-               }
-               else if(unlikely(*s == '+'))
-                       *d++ = ' ';
+    while(*s && d < e) {
+        if(unlikely(*s == '%')) {
+            if(likely(s[1] && s[2])) {
+                *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
+                s += 2;
+            }
+        }
+        else if(unlikely(*s == '+'))
+            *d++ = ' ';
 
-               else
-                       *d++ = *s;
+        else
+            *d++ = *s;
 
-               s++;
-       }
+        s++;
+    }
 
-       *d = '\0';
+    *d = '\0';
 
-       return to;
+    return to;
 }
index c4aa2f8d9811e058da9fd5a6ba2e7fedd028f6b4..5b4f24623ba86ef230fc1c90e95a2bf283d34e94 100644 (file)
@@ -4,8 +4,8 @@
 
 static inline void buffer_overflow_init(BUFFER *b)
 {
-       b->buffer[b->size] = '\0';
-       strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
+    b->buffer[b->size] = '\0';
+    strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
 }
 
 #ifdef NETDATA_INTERNAL_CHECKS
@@ -16,49 +16,49 @@ static inline void buffer_overflow_init(BUFFER *b)
 
 static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line)
 {
-       if(b->len > b->size) {
-               error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
-               b->len = b->size;
-       }
-
-       if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF)) {
-               error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
-               buffer_overflow_init(b);
-       }
+    if(b->len > b->size) {
+        error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
+        b->len = b->size;
+    }
+
+    if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF)) {
+        error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
+        buffer_overflow_init(b);
+    }
 }
 
 
 void buffer_reset(BUFFER *wb)
 {
-       buffer_flush(wb);
+    buffer_flush(wb);
 
-       wb->contenttype = CT_TEXT_PLAIN;
-       wb->options = 0;
-       wb->date = 0;
+    wb->contenttype = CT_TEXT_PLAIN;
+    wb->options = 0;
+    wb->date = 0;
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 }
 
 const char *buffer_tostring(BUFFER *wb)
 {
-       buffer_need_bytes(wb, 1);
-       wb->buffer[wb->len] = '\0';
+    buffer_need_bytes(wb, 1);
+    wb->buffer[wb->len] = '\0';
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 
-       return(wb->buffer);
+    return(wb->buffer);
 }
 
 void buffer_char_replace(BUFFER *wb, char from, char to)
 {
-       char *s = wb->buffer, *end = &wb->buffer[wb->len];
+    char *s = wb->buffer, *end = &wb->buffer[wb->len];
 
-       while(s != end) {
-               if(*s == from) *s = to;
-               s++;
-       }
+    while(s != end) {
+        if(*s == from) *s = to;
+        s++;
+    }
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 }
 
 // This trick seems to give an 80% speed increase in 32bit systems
@@ -67,171 +67,171 @@ void buffer_char_replace(BUFFER *wb, char from, char to)
 // print_calculated_number_lu_r() to print the rest with 32 bit arithmetic.
 
 inline char *print_number_lu_r(char *str, unsigned long uvalue) {
-       char *wstr = str;
+    char *wstr = str;
 
-       // print each digit
-       do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
-       return wstr;
+    // print each digit
+    do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
+    return wstr;
 }
 
 inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
-       char *wstr = str;
+    char *wstr = str;
 
-       // print each digit
-       do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
-       if(uvalue) return print_number_lu_r(wstr, uvalue);
-       return wstr;
+    // print each digit
+    do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
+    if(uvalue) return print_number_lu_r(wstr, uvalue);
+    return wstr;
 }
 
 void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
 {
-       buffer_need_bytes(wb, 50);
+    buffer_need_bytes(wb, 50);
 
-       char *str = &wb->buffer[wb->len];
-       char *wstr = str;
+    char *str = &wb->buffer[wb->len];
+    char *wstr = str;
 
 #ifdef ENVIRONMENT32
-       if(uvalue > (unsigned long long)0xffffffff)
-               wstr = print_number_llu_r(wstr, uvalue);
-       else
-               wstr = print_number_lu_r(wstr, uvalue);
+    if(uvalue > (unsigned long long)0xffffffff)
+        wstr = print_number_llu_r(wstr, uvalue);
+    else
+        wstr = print_number_lu_r(wstr, uvalue);
 #else
-       do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
+    do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
 #endif
 
-       // terminate it
-       *wstr = '\0';
+    // terminate it
+    *wstr = '\0';
 
-       // reverse it
-       char *begin = str, *end = wstr - 1, aux;
-       while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
+    // reverse it
+    char *begin = str, *end = wstr - 1, aux;
+    while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
 
-       // return the buffer length
-       wb->len += wstr - str;
+    // return the buffer length
+    wb->len += wstr - str;
 }
 
 void buffer_strcat(BUFFER *wb, const char *txt)
 {
-       if(unlikely(!txt || !*txt)) return;
-
-       buffer_need_bytes(wb, 1);
-
-       char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
-       long len = wb->len;
-
-       start = s;
-       while(*txt && s != end)
-               *s++ = *txt++;
-
-       len += s - start;
-
-       wb->len = len;
-       buffer_overflow_check(wb);
-
-       if(*txt) {
-               debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
-               len = strlen(txt);
-               buffer_increase(wb, len);
-               buffer_strcat(wb, txt);
-       }
-       else {
-               // terminate the string
-               // without increasing the length
-               buffer_need_bytes(wb, (size_t)1);
-               wb->buffer[wb->len] = '\0';
-       }
+    if(unlikely(!txt || !*txt)) return;
+
+    buffer_need_bytes(wb, 1);
+
+    char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
+    long len = wb->len;
+
+    start = s;
+    while(*txt && s != end)
+        *s++ = *txt++;
+
+    len += s - start;
+
+    wb->len = len;
+    buffer_overflow_check(wb);
+
+    if(*txt) {
+        debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
+        len = strlen(txt);
+        buffer_increase(wb, len);
+        buffer_strcat(wb, txt);
+    }
+    else {
+        // terminate the string
+        // without increasing the length
+        buffer_need_bytes(wb, (size_t)1);
+        wb->buffer[wb->len] = '\0';
+    }
 }
 
 
 void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...)
 {
-       if(unlikely(!fmt || !*fmt)) return;
+    if(unlikely(!fmt || !*fmt)) return;
 
-       buffer_need_bytes(wb, len + 1);
+    buffer_need_bytes(wb, len + 1);
 
-       va_list args;
-       va_start(args, fmt);
-       wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
-       va_end(args);
+    va_list args;
+    va_start(args, fmt);
+    wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
+    va_end(args);
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 
-       // the buffer is \0 terminated by vsnprintfz
+    // the buffer is \0 terminated by vsnprintfz
 }
 
 void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args)
 {
-       if(unlikely(!fmt || !*fmt)) return;
+    if(unlikely(!fmt || !*fmt)) return;
 
-       buffer_need_bytes(wb, 2);
+    buffer_need_bytes(wb, 2);
 
-       size_t len = wb->size - wb->len - 1;
+    size_t len = wb->size - wb->len - 1;
 
-       wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
+    wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 
-       // the buffer is \0 terminated by vsnprintfz
+    // the buffer is \0 terminated by vsnprintfz
 }
 
 void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
 {
-       if(unlikely(!fmt || !*fmt)) return;
+    if(unlikely(!fmt || !*fmt)) return;
 
-       buffer_need_bytes(wb, 2);
+    buffer_need_bytes(wb, 2);
 
-       size_t len = wb->size - wb->len - 1;
-       size_t wrote;
+    size_t len = wb->size - wb->len - 1;
+    size_t wrote;
 
-       va_list args;
-       va_start(args, fmt);
-       wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
-       va_end(args);
+    va_list args;
+    va_start(args, fmt);
+    wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
+    va_end(args);
 
-       if(unlikely(wrote >= len)) {
-               // there is bug in vsnprintf() and it returns
-               // a number higher to len, but it does not
-               // overflow the buffer.
-               // our buffer overflow detector will log it
-               // if it does.
-               buffer_overflow_check(wb);
+    if(unlikely(wrote >= len)) {
+        // there is bug in vsnprintf() and it returns
+        // a number higher to len, but it does not
+        // overflow the buffer.
+        // our buffer overflow detector will log it
+        // if it does.
+        buffer_overflow_check(wb);
 
-               debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
-               buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
+        debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
+        buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
 
-               va_start(args, fmt);
-               buffer_vsprintf(wb, fmt, args);
-               va_end(args);
-       }
-       else
-               wb->len += wrote;
+        va_start(args, fmt);
+        buffer_vsprintf(wb, fmt, args);
+        va_end(args);
+    }
+    else
+        wb->len += wrote;
 
-       // the buffer is \0 terminated by vsnprintf
+    // the buffer is \0 terminated by vsnprintf
 }
 
 
 void buffer_rrd_value(BUFFER *wb, calculated_number value)
 {
-       buffer_need_bytes(wb, 50);
-       wb->len += print_calculated_number(&wb->buffer[wb->len], value);
+    buffer_need_bytes(wb, 50);
+    wb->len += print_calculated_number(&wb->buffer[wb->len], value);
 
-       // terminate it
-       buffer_need_bytes(wb, 1);
-       wb->buffer[wb->len] = '\0';
+    // terminate it
+    buffer_need_bytes(wb, 1);
+    wb->buffer[wb->len] = '\0';
 
-       buffer_overflow_check(wb);
+    buffer_overflow_check(wb);
 }
 
 // generate a javascript date, the fastest possible way...
 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
 {
   //         10        20        30      = 35
-       // 01234567890123456789012345678901234
-       // Date(2014,04,01,03,28,20)
+    // 01234567890123456789012345678901234
+    // Date(2014,04,01,03,28,20)
 
-       buffer_need_bytes(wb, 30);
+    buffer_need_bytes(wb, 30);
 
-       char *b = &wb->buffer[wb->len], *p;
+    char *b = &wb->buffer[wb->len], *p;
   unsigned int *q = (unsigned int *)b;  
 
   #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -270,23 +270,23 @@ void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minu
     *r++ = 0x2900;  // ")\0"
   #endif
 
-       wb->len += (size_t)((char *)r - b - 1);
+    wb->len += (size_t)((char *)r - b - 1);
 
-       // terminate it
-       wb->buffer[wb->len] = '\0';
-       buffer_overflow_check(wb);
+    // terminate it
+    wb->buffer[wb->len] = '\0';
+    buffer_overflow_check(wb);
 }
 
 // generate a date, the fastest possible way...
 void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
 {
-       //         10        20        30      = 35
-       // 01234567890123456789012345678901234
-       // 2014-04-01 03:28:20
+    //         10        20        30      = 35
+    // 01234567890123456789012345678901234
+    // 2014-04-01 03:28:20
 
-       buffer_need_bytes(wb, 36);
+    buffer_need_bytes(wb, 36);
 
-       char *b = &wb->buffer[wb->len];
+    char *b = &wb->buffer[wb->len];
   char *p = b;
 
   *p++ = '0' + year / 1000; year %= 1000;
@@ -310,56 +310,56 @@ void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minute
   *p++ = '0' + seconds % 10;
   *p = '\0';
 
-       wb->len += (size_t)(p - b);
+    wb->len += (size_t)(p - b);
 
-       // terminate it
-       wb->buffer[wb->len] = '\0';
-       buffer_overflow_check(wb);
+    // terminate it
+    wb->buffer[wb->len] = '\0';
+    buffer_overflow_check(wb);
 }
 
 BUFFER *buffer_create(size_t size)
 {
-       BUFFER *b;
+    BUFFER *b;
 
-       debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
+    debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
 
-       b = callocz(1, sizeof(BUFFER));
-       b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-       b->buffer[0] = '\0';
-       b->size = size;
-       b->contenttype = CT_TEXT_PLAIN;
-       buffer_overflow_init(b);
-       buffer_overflow_check(b);
+    b = callocz(1, sizeof(BUFFER));
+    b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
+    b->buffer[0] = '\0';
+    b->size = size;
+    b->contenttype = CT_TEXT_PLAIN;
+    buffer_overflow_init(b);
+    buffer_overflow_check(b);
 
-       return(b);
+    return(b);
 }
 
 void buffer_free(BUFFER *b)
 {
-       buffer_overflow_check(b);
+    buffer_overflow_check(b);
 
-       debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
+    debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
 
-       freez(b->buffer);
-       freez(b);
+    freez(b->buffer);
+    freez(b);
 }
 
 void buffer_increase(BUFFER *b, size_t free_size_required)
 {
-       buffer_overflow_check(b);
+    buffer_overflow_check(b);
 
-       size_t left = b->size - b->len;
+    size_t left = b->size - b->len;
 
-       if(left >= free_size_required) return;
+    if(left >= free_size_required) return;
 
-       size_t increase = free_size_required - left;
-       if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
+    size_t increase = free_size_required - left;
+    if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
 
-       debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
+    debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
 
-       b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-       b->size += increase;
+    b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
+    b->size += increase;
 
-       buffer_overflow_init(b);
-       buffer_overflow_check(b);
+    buffer_overflow_init(b);
+    buffer_overflow_check(b);
 }
index 0370491e2828f8c685a2b5bb5ffe9567ed39f1ea..c4cd0563212c0a835baa93b8517081213c68af02 100644 (file)
@@ -4,40 +4,40 @@
 #define WEB_DATA_LENGTH_INCREASE_STEP 1024
 
 typedef struct web_buffer {
-       size_t size;            // allocation size of buffer
-       size_t len;             // current data length in buffer
-       char *buffer;   // the buffer
-       uint8_t contenttype;
-       uint8_t options;
-       time_t date;    // the date this content has been generated
+    size_t size;        // allocation size of buffer
+    size_t len;     // current data length in buffer
+    char *buffer;   // the buffer
+    uint8_t contenttype;
+    uint8_t options;
+    time_t date;    // the date this content has been generated
 } BUFFER;
 
 // options
-#define WB_CONTENT_CACHEABLE                   1
-#define WB_CONTENT_NO_CACHEABLE                        2
+#define WB_CONTENT_CACHEABLE            1
+#define WB_CONTENT_NO_CACHEABLE         2
 
 // content-types
-#define CT_APPLICATION_JSON                            1
-#define CT_TEXT_PLAIN                                  2
-#define CT_TEXT_HTML                                   3
-#define CT_APPLICATION_X_JAVASCRIPT            4
-#define CT_TEXT_CSS                                            5
-#define CT_TEXT_XML                                            6
-#define CT_APPLICATION_XML                             7
-#define CT_TEXT_XSL                                            8
-#define CT_APPLICATION_OCTET_STREAM            9
-#define CT_APPLICATION_X_FONT_TRUETYPE 10
-#define CT_APPLICATION_X_FONT_OPENTYPE 11
-#define CT_APPLICATION_FONT_WOFF               12
-#define CT_APPLICATION_FONT_WOFF2              13
-#define CT_APPLICATION_VND_MS_FONTOBJ  14
-#define CT_IMAGE_SVG_XML                               15
-#define CT_IMAGE_PNG                                   16
-#define CT_IMAGE_JPG                                   17
-#define CT_IMAGE_GIF                                   18
-#define CT_IMAGE_XICON                                 19
-#define CT_IMAGE_ICNS                                  20
-#define CT_IMAGE_BMP                                   21
+#define CT_APPLICATION_JSON             1
+#define CT_TEXT_PLAIN                   2
+#define CT_TEXT_HTML                    3
+#define CT_APPLICATION_X_JAVASCRIPT     4
+#define CT_TEXT_CSS                     5
+#define CT_TEXT_XML                     6
+#define CT_APPLICATION_XML              7
+#define CT_TEXT_XSL                     8
+#define CT_APPLICATION_OCTET_STREAM     9
+#define CT_APPLICATION_X_FONT_TRUETYPE  10
+#define CT_APPLICATION_X_FONT_OPENTYPE  11
+#define CT_APPLICATION_FONT_WOFF        12
+#define CT_APPLICATION_FONT_WOFF2       13
+#define CT_APPLICATION_VND_MS_FONTOBJ   14
+#define CT_IMAGE_SVG_XML                15
+#define CT_IMAGE_PNG                    16
+#define CT_IMAGE_JPG                    17
+#define CT_IMAGE_GIF                    18
+#define CT_IMAGE_XICON                  19
+#define CT_IMAGE_ICNS                   20
+#define CT_IMAGE_BMP                    21
 
 #define buffer_strlen(wb) ((wb)->len)
 extern const char *buffer_tostring(BUFFER *wb);
index 087c79a3f037cf6850f4a285adf7913b285494f5..daabee3df759e6bc9ac82aa4b8e2d4c523e672b3 100644 (file)
 */
 
 double verdana11_widths[256] = {
-       [0] = 0.0,
-       [1] = 0.0,
-       [2] = 0.0,
-       [3] = 0.0,
-       [4] = 0.0,
-       [5] = 0.0,
-       [6] = 0.0,
-       [7] = 0.0,
-       [8] = 0.0,
-       [9] = 0.0,
-       [10] = 0.0,
-       [11] = 0.0,
-       [12] = 0.0,
-       [13] = 0.0,
-       [14] = 0.0,
-       [15] = 0.0,
-       [16] = 0.0,
-       [17] = 0.0,
-       [18] = 0.0,
-       [19] = 0.0,
-       [20] = 0.0,
-       [21] = 0.0,
-       [22] = 0.0,
-       [23] = 0.0,
-       [24] = 0.0,
-       [25] = 0.0,
-       [26] = 0.0,
-       [27] = 0.0,
-       [28] = 0.0,
-       [29] = 0.0,
-       [30] = 0.0,
-       [31] = 0.0,
-       [32] = 3.8671874999999996, //
-       [33] = 4.3291015625, // !
-       [34] = 5.048828125, // "
-       [35] = 9.001953125, // #
-       [36] = 6.9931640625, // $
-       [37] = 11.837890625, // %
-       [38] = 7.992187499999999, // &
-       [39] = 2.9541015625, // '
-       [40] = 4.9951171875, // (
-       [41] = 4.9951171875, // )
-       [42] = 6.9931640625, // *
-       [43] = 9.001953125, // +
-       [44] = 4.00146484375, // ,
-       [45] = 4.9951171875, // -
-       [46] = 4.00146484375, // .
-       [47] = 4.9951171875, // /
-       [48] = 6.9931640625, // 0
-       [49] = 6.9931640625, // 1
-       [50] = 6.9931640625, // 2
-       [51] = 6.9931640625, // 3
-       [52] = 6.9931640625, // 4
-       [53] = 6.9931640625, // 5
-       [54] = 6.9931640625, // 6
-       [55] = 6.9931640625, // 7
-       [56] = 6.9931640625, // 8
-       [57] = 6.9931640625, // 9
-       [58] = 4.9951171875, // :
-       [59] = 4.9951171875, // ;
-       [60] = 9.001953125, // <
-       [61] = 9.001953125, // =
-       [62] = 9.001953125, // >
-       [63] = 5.99951171875, // ?
-       [64] = 11.0, // @
-       [65] = 7.51953125, // A
-       [66] = 7.541015625, // B
-       [67] = 7.680664062499999, // C
-       [68] = 8.4755859375, // D
-       [69] = 6.95556640625, // E
-       [70] = 6.32177734375, // F
-       [71] = 8.529296875, // G
-       [72] = 8.26611328125, // H
-       [73] = 4.6298828125, // I
-       [74] = 5.00048828125, // J
-       [75] = 7.62158203125, // K
-       [76] = 6.123046875, // L
-       [77] = 9.2705078125, // M
-       [78] = 8.228515625, // N
-       [79] = 8.658203125, // O
-       [80] = 6.63330078125, // P
-       [81] = 8.658203125, // Q
-       [82] = 7.6484375, // R
-       [83] = 7.51953125, // S
-       [84] = 6.7783203125, // T
-       [85] = 8.05126953125, // U
-       [86] = 7.51953125, // V
-       [87] = 10.87646484375, // W
-       [88] = 7.53564453125, // X
-       [89] = 6.767578125, // Y
-       [90] = 7.53564453125, // Z
-       [91] = 4.9951171875, // [
-       [92] = 4.9951171875, // backslash
-       [93] = 4.9951171875, // ]
-       [94] = 9.001953125, // ^
-       [95] = 6.9931640625, // _
-       [96] = 6.9931640625, // `
-       [97] = 6.6064453125, // a
-       [98] = 6.853515625, // b
-       [99] = 5.73095703125, // c
-       [100] = 6.853515625, // d
-       [101] = 6.552734375, // e
-       [102] = 3.8671874999999996, // f
-       [103] = 6.853515625, // g
-       [104] = 6.9609375, // h
-       [105] = 3.0185546875, // i
-       [106] = 3.78662109375, // j
-       [107] = 6.509765625, // k
-       [108] = 3.0185546875, // l
-       [109] = 10.69921875, // m
-       [110] = 6.9609375, // n
-       [111] = 6.67626953125, // o
-       [112] = 6.853515625, // p
-       [113] = 6.853515625, // q
-       [114] = 4.6943359375, // r
-       [115] = 5.73095703125, // s
-       [116] = 4.33447265625, // t
-       [117] = 6.9609375, // u
-       [118] = 6.509765625, // v
-       [119] = 9.001953125, // w
-       [120] = 6.509765625, // x
-       [121] = 6.509765625, // y
-       [122] = 5.779296875, // z
-       [123] = 6.982421875, // {
-       [124] = 4.9951171875, // |
-       [125] = 6.982421875, // }
-       [126] = 9.001953125, // ~
-       [127] = 0.0,
-       [128] = 0.0,
-       [129] = 0.0,
-       [130] = 0.0,
-       [131] = 0.0,
-       [132] = 0.0,
-       [133] = 0.0,
-       [134] = 0.0,
-       [135] = 0.0,
-       [136] = 0.0,
-       [137] = 0.0,
-       [138] = 0.0,
-       [139] = 0.0,
-       [140] = 0.0,
-       [141] = 0.0,
-       [142] = 0.0,
-       [143] = 0.0,
-       [144] = 0.0,
-       [145] = 0.0,
-       [146] = 0.0,
-       [147] = 0.0,
-       [148] = 0.0,
-       [149] = 0.0,
-       [150] = 0.0,
-       [151] = 0.0,
-       [152] = 0.0,
-       [153] = 0.0,
-       [154] = 0.0,
-       [155] = 0.0,
-       [156] = 0.0,
-       [157] = 0.0,
-       [158] = 0.0,
-       [159] = 0.0,
-       [160] = 0.0,
-       [161] = 0.0,
-       [162] = 0.0,
-       [163] = 0.0,
-       [164] = 0.0,
-       [165] = 0.0,
-       [166] = 0.0,
-       [167] = 0.0,
-       [168] = 0.0,
-       [169] = 0.0,
-       [170] = 0.0,
-       [171] = 0.0,
-       [172] = 0.0,
-       [173] = 0.0,
-       [174] = 0.0,
-       [175] = 0.0,
-       [176] = 0.0,
-       [177] = 0.0,
-       [178] = 0.0,
-       [179] = 0.0,
-       [180] = 0.0,
-       [181] = 0.0,
-       [182] = 0.0,
-       [183] = 0.0,
-       [184] = 0.0,
-       [185] = 0.0,
-       [186] = 0.0,
-       [187] = 0.0,
-       [188] = 0.0,
-       [189] = 0.0,
-       [190] = 0.0,
-       [191] = 0.0,
-       [192] = 0.0,
-       [193] = 0.0,
-       [194] = 0.0,
-       [195] = 0.0,
-       [196] = 0.0,
-       [197] = 0.0,
-       [198] = 0.0,
-       [199] = 0.0,
-       [200] = 0.0,
-       [201] = 0.0,
-       [202] = 0.0,
-       [203] = 0.0,
-       [204] = 0.0,
-       [205] = 0.0,
-       [206] = 0.0,
-       [207] = 0.0,
-       [208] = 0.0,
-       [209] = 0.0,
-       [210] = 0.0,
-       [211] = 0.0,
-       [212] = 0.0,
-       [213] = 0.0,
-       [214] = 0.0,
-       [215] = 0.0,
-       [216] = 0.0,
-       [217] = 0.0,
-       [218] = 0.0,
-       [219] = 0.0,
-       [220] = 0.0,
-       [221] = 0.0,
-       [222] = 0.0,
-       [223] = 0.0,
-       [224] = 0.0,
-       [225] = 0.0,
-       [226] = 0.0,
-       [227] = 0.0,
-       [228] = 0.0,
-       [229] = 0.0,
-       [230] = 0.0,
-       [231] = 0.0,
-       [232] = 0.0,
-       [233] = 0.0,
-       [234] = 0.0,
-       [235] = 0.0,
-       [236] = 0.0,
-       [237] = 0.0,
-       [238] = 0.0,
-       [239] = 0.0,
-       [240] = 0.0,
-       [241] = 0.0,
-       [242] = 0.0,
-       [243] = 0.0,
-       [244] = 0.0,
-       [245] = 0.0,
-       [246] = 0.0,
-       [247] = 0.0,
-       [248] = 0.0,
-       [249] = 0.0,
-       [250] = 0.0,
-       [251] = 0.0,
-       [252] = 0.0,
-       [253] = 0.0,
-       [254] = 0.0,
-       [255] = 0.0
+    [0] = 0.0,
+    [1] = 0.0,
+    [2] = 0.0,
+    [3] = 0.0,
+    [4] = 0.0,
+    [5] = 0.0,
+    [6] = 0.0,
+    [7] = 0.0,
+    [8] = 0.0,
+    [9] = 0.0,
+    [10] = 0.0,
+    [11] = 0.0,
+    [12] = 0.0,
+    [13] = 0.0,
+    [14] = 0.0,
+    [15] = 0.0,
+    [16] = 0.0,
+    [17] = 0.0,
+    [18] = 0.0,
+    [19] = 0.0,
+    [20] = 0.0,
+    [21] = 0.0,
+    [22] = 0.0,
+    [23] = 0.0,
+    [24] = 0.0,
+    [25] = 0.0,
+    [26] = 0.0,
+    [27] = 0.0,
+    [28] = 0.0,
+    [29] = 0.0,
+    [30] = 0.0,
+    [31] = 0.0,
+    [32] = 3.8671874999999996, //
+    [33] = 4.3291015625, // !
+    [34] = 5.048828125, // "
+    [35] = 9.001953125, // #
+    [36] = 6.9931640625, // $
+    [37] = 11.837890625, // %
+    [38] = 7.992187499999999, // &
+    [39] = 2.9541015625, // '
+    [40] = 4.9951171875, // (
+    [41] = 4.9951171875, // )
+    [42] = 6.9931640625, // *
+    [43] = 9.001953125, // +
+    [44] = 4.00146484375, // ,
+    [45] = 4.9951171875, // -
+    [46] = 4.00146484375, // .
+    [47] = 4.9951171875, // /
+    [48] = 6.9931640625, // 0
+    [49] = 6.9931640625, // 1
+    [50] = 6.9931640625, // 2
+    [51] = 6.9931640625, // 3
+    [52] = 6.9931640625, // 4
+    [53] = 6.9931640625, // 5
+    [54] = 6.9931640625, // 6
+    [55] = 6.9931640625, // 7
+    [56] = 6.9931640625, // 8
+    [57] = 6.9931640625, // 9
+    [58] = 4.9951171875, // :
+    [59] = 4.9951171875, // ;
+    [60] = 9.001953125, // <
+    [61] = 9.001953125, // =
+    [62] = 9.001953125, // >
+    [63] = 5.99951171875, // ?
+    [64] = 11.0, // @
+    [65] = 7.51953125, // A
+    [66] = 7.541015625, // B
+    [67] = 7.680664062499999, // C
+    [68] = 8.4755859375, // D
+    [69] = 6.95556640625, // E
+    [70] = 6.32177734375, // F
+    [71] = 8.529296875, // G
+    [72] = 8.26611328125, // H
+    [73] = 4.6298828125, // I
+    [74] = 5.00048828125, // J
+    [75] = 7.62158203125, // K
+    [76] = 6.123046875, // L
+    [77] = 9.2705078125, // M
+    [78] = 8.228515625, // N
+    [79] = 8.658203125, // O
+    [80] = 6.63330078125, // P
+    [81] = 8.658203125, // Q
+    [82] = 7.6484375, // R
+    [83] = 7.51953125, // S
+    [84] = 6.7783203125, // T
+    [85] = 8.05126953125, // U
+    [86] = 7.51953125, // V
+    [87] = 10.87646484375, // W
+    [88] = 7.53564453125, // X
+    [89] = 6.767578125, // Y
+    [90] = 7.53564453125, // Z
+    [91] = 4.9951171875, // [
+    [92] = 4.9951171875, // backslash
+    [93] = 4.9951171875, // ]
+    [94] = 9.001953125, // ^
+    [95] = 6.9931640625, // _
+    [96] = 6.9931640625, // `
+    [97] = 6.6064453125, // a
+    [98] = 6.853515625, // b
+    [99] = 5.73095703125, // c
+    [100] = 6.853515625, // d
+    [101] = 6.552734375, // e
+    [102] = 3.8671874999999996, // f
+    [103] = 6.853515625, // g
+    [104] = 6.9609375, // h
+    [105] = 3.0185546875, // i
+    [106] = 3.78662109375, // j
+    [107] = 6.509765625, // k
+    [108] = 3.0185546875, // l
+    [109] = 10.69921875, // m
+    [110] = 6.9609375, // n
+    [111] = 6.67626953125, // o
+    [112] = 6.853515625, // p
+    [113] = 6.853515625, // q
+    [114] = 4.6943359375, // r
+    [115] = 5.73095703125, // s
+    [116] = 4.33447265625, // t
+    [117] = 6.9609375, // u
+    [118] = 6.509765625, // v
+    [119] = 9.001953125, // w
+    [120] = 6.509765625, // x
+    [121] = 6.509765625, // y
+    [122] = 5.779296875, // z
+    [123] = 6.982421875, // {
+    [124] = 4.9951171875, // |
+    [125] = 6.982421875, // }
+    [126] = 9.001953125, // ~
+    [127] = 0.0,
+    [128] = 0.0,
+    [129] = 0.0,
+    [130] = 0.0,
+    [131] = 0.0,
+    [132] = 0.0,
+    [133] = 0.0,
+    [134] = 0.0,
+    [135] = 0.0,
+    [136] = 0.0,
+    [137] = 0.0,
+    [138] = 0.0,
+    [139] = 0.0,
+    [140] = 0.0,
+    [141] = 0.0,
+    [142] = 0.0,
+    [143] = 0.0,
+    [144] = 0.0,
+    [145] = 0.0,
+    [146] = 0.0,
+    [147] = 0.0,
+    [148] = 0.0,
+    [149] = 0.0,
+    [150] = 0.0,
+    [151] = 0.0,
+    [152] = 0.0,
+    [153] = 0.0,
+    [154] = 0.0,
+    [155] = 0.0,
+    [156] = 0.0,
+    [157] = 0.0,
+    [158] = 0.0,
+    [159] = 0.0,
+    [160] = 0.0,
+    [161] = 0.0,
+    [162] = 0.0,
+    [163] = 0.0,
+    [164] = 0.0,
+    [165] = 0.0,
+    [166] = 0.0,
+    [167] = 0.0,
+    [168] = 0.0,
+    [169] = 0.0,
+    [170] = 0.0,
+    [171] = 0.0,
+    [172] = 0.0,
+    [173] = 0.0,
+    [174] = 0.0,
+    [175] = 0.0,
+    [176] = 0.0,
+    [177] = 0.0,
+    [178] = 0.0,
+    [179] = 0.0,
+    [180] = 0.0,
+    [181] = 0.0,
+    [182] = 0.0,
+    [183] = 0.0,
+    [184] = 0.0,
+    [185] = 0.0,
+    [186] = 0.0,
+    [187] = 0.0,
+    [188] = 0.0,
+    [189] = 0.0,
+    [190] = 0.0,
+    [191] = 0.0,
+    [192] = 0.0,
+    [193] = 0.0,
+    [194] = 0.0,
+    [195] = 0.0,
+    [196] = 0.0,
+    [197] = 0.0,
+    [198] = 0.0,
+    [199] = 0.0,
+    [200] = 0.0,
+    [201] = 0.0,
+    [202] = 0.0,
+    [203] = 0.0,
+    [204] = 0.0,
+    [205] = 0.0,
+    [206] = 0.0,
+    [207] = 0.0,
+    [208] = 0.0,
+    [209] = 0.0,
+    [210] = 0.0,
+    [211] = 0.0,
+    [212] = 0.0,
+    [213] = 0.0,
+    [214] = 0.0,
+    [215] = 0.0,
+    [216] = 0.0,
+    [217] = 0.0,
+    [218] = 0.0,
+    [219] = 0.0,
+    [220] = 0.0,
+    [221] = 0.0,
+    [222] = 0.0,
+    [223] = 0.0,
+    [224] = 0.0,
+    [225] = 0.0,
+    [226] = 0.0,
+    [227] = 0.0,
+    [228] = 0.0,
+    [229] = 0.0,
+    [230] = 0.0,
+    [231] = 0.0,
+    [232] = 0.0,
+    [233] = 0.0,
+    [234] = 0.0,
+    [235] = 0.0,
+    [236] = 0.0,
+    [237] = 0.0,
+    [238] = 0.0,
+    [239] = 0.0,
+    [240] = 0.0,
+    [241] = 0.0,
+    [242] = 0.0,
+    [243] = 0.0,
+    [244] = 0.0,
+    [245] = 0.0,
+    [246] = 0.0,
+    [247] = 0.0,
+    [248] = 0.0,
+    [249] = 0.0,
+    [250] = 0.0,
+    [251] = 0.0,
+    [252] = 0.0,
+    [253] = 0.0,
+    [254] = 0.0,
+    [255] = 0.0
 };
 
 // find the width of the string using the verdana 11points font
 // re-write the string in place, skiping zero-length characters
 static inline int verdana11_width(char *s) {
-       double w = 0.0;
-       char *d = s;
-
-       while(*s) {
-               double t = verdana11_widths[(unsigned char)*s];
-               if(t == 0.0)
-                       s++;
-               else {
-                       w += t + VERDANA_KERNING;
-                       if(d != s)
-                               *d++ = *s++;
-                       else
-                               d = ++s;
-               }
-       }
-
-       *d = '\0';
-       w -= VERDANA_KERNING;
-       return ceil(w);
+    double w = 0.0;
+    char *d = s;
+
+    while(*s) {
+        double t = verdana11_widths[(unsigned char)*s];
+        if(t == 0.0)
+            s++;
+        else {
+            w += t + VERDANA_KERNING;
+            if(d != s)
+                *d++ = *s++;
+            else
+                d = ++s;
+        }
+    }
+
+    *d = '\0';
+    w -= VERDANA_KERNING;
+    return ceil(w);
 }
 
 static inline size_t escape_xmlz(char *dst, const char *src, size_t len) {
-       size_t i = len;
-
-       // required escapes from
-       // https://github.com/badges/shields/blob/master/badge.js
-       while(*src && i) {
-               switch(*src) {
-                       case '\\':
-                               *dst++ = '/';
-                               src++;
-                               i--;
-                               break;
-
-                       case '&':
-                               if(i > 5) {
-                                       strcpy(dst, "&amp;");
-                                       i -= 5;
-                                       dst += 5;
-                                       src++;
-                               }
-                               else goto cleanup;
-                               break;
-
-                       case '<':
-                               if(i > 4) {
-                                       strcpy(dst, "&lt;");
-                                       i -= 4;
-                                       dst += 4;
-                                       src++;
-                               }
-                               else goto cleanup;
-                               break;
-
-                       case '>':
-                               if(i > 4) {
-                                       strcpy(dst, "&gt;");
-                                       i -= 4;
-                                       dst += 4;
-                                       src++;
-                               }
-                               else goto cleanup;
-                               break;
-
-                       case '"':
-                               if(i > 6) {
-                                       strcpy(dst, "&quot;");
-                                       i -= 6;
-                                       dst += 6;
-                                       src++;
-                               }
-                               else goto cleanup;
-                               break;
-
-                       case '\'':
-                               if(i > 6) {
-                                       strcpy(dst, "&apos;");
-                                       i -= 6;
-                                       dst += 6;
-                                       src++;
-                               }
-                               else goto cleanup;
-                               break;
-
-                       default:
-                               i--;
-                               *dst++ = *src++;
-                               break;
-               }
-       }
+    size_t i = len;
+
+    // required escapes from
+    // https://github.com/badges/shields/blob/master/badge.js
+    while(*src && i) {
+        switch(*src) {
+            case '\\':
+                *dst++ = '/';
+                src++;
+                i--;
+                break;
+
+            case '&':
+                if(i > 5) {
+                    strcpy(dst, "&amp;");
+                    i -= 5;
+                    dst += 5;
+                    src++;
+                }
+                else goto cleanup;
+                break;
+
+            case '<':
+                if(i > 4) {
+                    strcpy(dst, "&lt;");
+                    i -= 4;
+                    dst += 4;
+                    src++;
+                }
+                else goto cleanup;
+                break;
+
+            case '>':
+                if(i > 4) {
+                    strcpy(dst, "&gt;");
+                    i -= 4;
+                    dst += 4;
+                    src++;
+                }
+                else goto cleanup;
+                break;
+
+            case '"':
+                if(i > 6) {
+                    strcpy(dst, "&quot;");
+                    i -= 6;
+                    dst += 6;
+                    src++;
+                }
+                else goto cleanup;
+                break;
+
+            case '\'':
+                if(i > 6) {
+                    strcpy(dst, "&apos;");
+                    i -= 6;
+                    dst += 6;
+                    src++;
+                }
+                else goto cleanup;
+                break;
+
+            default:
+                i--;
+                *dst++ = *src++;
+                break;
+        }
+    }
 
 cleanup:
-       *dst = '\0';
-       return len - i;
+    *dst = '\0';
+    return len - i;
 }
 
 static inline const char *fix_units(const char *units) {
-       if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
-       if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
-       return units;
+    if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
+    if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
+    return units;
 }
 
 static inline const char *color_map(const char *color) {
-       // colors from:
-       // https://github.com/badges/shields/blob/master/colorscheme.json
-            if(!strcmp(color, "brightgreen")) return "#4c1";
-       else if(!strcmp(color, "green"))       return "#97CA00";
-       else if(!strcmp(color, "yellow"))      return "#dfb317";
-       else if(!strcmp(color, "yellowgreen")) return "#a4a61d";
-       else if(!strcmp(color, "orange"))      return "#fe7d37";
-       else if(!strcmp(color, "red"))         return "#e05d44";
-       else if(!strcmp(color, "blue"))        return "#007ec6";
-       else if(!strcmp(color, "grey"))        return "#555";
-       else if(!strcmp(color, "gray"))        return "#555";
-       else if(!strcmp(color, "lightgrey"))   return "#9f9f9f";
-       else if(!strcmp(color, "lightgray"))   return "#9f9f9f";
-       return color;
+    // colors from:
+    // https://github.com/badges/shields/blob/master/colorscheme.json
+         if(!strcmp(color, "brightgreen")) return "#4c1";
+    else if(!strcmp(color, "green"))       return "#97CA00";
+    else if(!strcmp(color, "yellow"))      return "#dfb317";
+    else if(!strcmp(color, "yellowgreen")) return "#a4a61d";
+    else if(!strcmp(color, "orange"))      return "#fe7d37";
+    else if(!strcmp(color, "red"))         return "#e05d44";
+    else if(!strcmp(color, "blue"))        return "#007ec6";
+    else if(!strcmp(color, "grey"))        return "#555";
+    else if(!strcmp(color, "gray"))        return "#555";
+    else if(!strcmp(color, "lightgrey"))   return "#9f9f9f";
+    else if(!strcmp(color, "lightgray"))   return "#9f9f9f";
+    return color;
 }
 
 static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) {
-       char color_buffer[256 + 1] = "";
-       char value_buffer[256 + 1] = "";
-       char comparison = '>';
-
-       // example input:
-       // color<max|color>min|color:null...
-
-       const char *c = color;
-       while(*c) {
-               char *dc = color_buffer, *dv = NULL;
-               size_t ci = 0, vi = 0;
-
-               const char *t = c;
-
-               while(*t && *t != '|') {
-                       switch(*t) {
-                               case ':':
-                                       comparison = '=';
-                                       dv = value_buffer;
-                                       break;
-
-                               case '}':
-                               case ')':
-                               case '>':
-                                       if(t[1] == '=') {
-                                               comparison = ')';
-                                               t++;
-                                       }
-                                       else
-                                               comparison = '>';
-                                       dv = value_buffer;
-                                       break;
-
-                               case '{':
-                               case '(':
-                               case '<':
-                                       if(t[1] == '=') {
-                                               comparison = '(';
-                                               t++;
-                                       }
-                                       else
-                                               comparison = '<';
-                                       dv = value_buffer;
-                                       break;
-
-                               default:
-                                       if(dv) {
-                                               if(vi < 256) {
-                                                       vi++;
-                                                       *dv++ = *t;
-                                               }
-                                       }
-                                       else {
-                                               if(ci < 256) {
-                                                       ci++;
-                                                       *dc++ = *t;
-                                               }
-                                       }
-                                       break;
-                       }
-
-                       t++;
-               }
-
-               // prepare for next iteration
-               if(*t == '|') t++;
-               c = t;
-
-               // do the math
-               *dc = '\0';
-               if(dv) {
-                       *dv = '\0';
-
-                       if(value_is_null) {
-                               if(!*value_buffer || !strcmp(value_buffer, "null"))
-                                       break;
-                       }
-                       else {
-                               calculated_number v = strtold(value_buffer, NULL);
-
-                                    if(comparison == '<' && value < v) break;
-                               else if(comparison == '(' && value <= v) break;
-                               else if(comparison == '>' && value > v) break;
-                               else if(comparison == ')' && value >= v) break;
-                               else if(comparison == '=' && value == v) break;
-                       }
-               }
-               else
-                       break;
-       }
-
-       const char *b;
-       if(color_buffer[0])
-               b = color_buffer;
-       else
-               b = color;
-
-       strncpyz(final, b, len);
+    char color_buffer[256 + 1] = "";
+    char value_buffer[256 + 1] = "";
+    char comparison = '>';
+
+    // example input:
+    // color<max|color>min|color:null...
+
+    const char *c = color;
+    while(*c) {
+        char *dc = color_buffer, *dv = NULL;
+        size_t ci = 0, vi = 0;
+
+        const char *t = c;
+
+        while(*t && *t != '|') {
+            switch(*t) {
+                case ':':
+                    comparison = '=';
+                    dv = value_buffer;
+                    break;
+
+                case '}':
+                case ')':
+                case '>':
+                    if(t[1] == '=') {
+                        comparison = ')';
+                        t++;
+                    }
+                    else
+                        comparison = '>';
+                    dv = value_buffer;
+                    break;
+
+                case '{':
+                case '(':
+                case '<':
+                    if(t[1] == '=') {
+                        comparison = '(';
+                        t++;
+                    }
+                    else
+                        comparison = '<';
+                    dv = value_buffer;
+                    break;
+
+                default:
+                    if(dv) {
+                        if(vi < 256) {
+                            vi++;
+                            *dv++ = *t;
+                        }
+                    }
+                    else {
+                        if(ci < 256) {
+                            ci++;
+                            *dc++ = *t;
+                        }
+                    }
+                    break;
+            }
+
+            t++;
+        }
+
+        // prepare for next iteration
+        if(*t == '|') t++;
+        c = t;
+
+        // do the math
+        *dc = '\0';
+        if(dv) {
+            *dv = '\0';
+
+            if(value_is_null) {
+                if(!*value_buffer || !strcmp(value_buffer, "null"))
+                    break;
+            }
+            else {
+                calculated_number v = strtold(value_buffer, NULL);
+
+                     if(comparison == '<' && value < v) break;
+                else if(comparison == '(' && value <= v) break;
+                else if(comparison == '>' && value > v) break;
+                else if(comparison == ')' && value >= v) break;
+                else if(comparison == '=' && value == v) break;
+            }
+        }
+        else
+            break;
+    }
+
+    const char *b;
+    if(color_buffer[0])
+        b = color_buffer;
+    else
+        b = color;
+
+    strncpyz(final, b, len);
 }
 
 void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision) {
-       char label_buffer[256 + 1], value_string[512 + 1], value_color_buffer[256 + 1];
-       char label_escaped[256 + 1], value_escaped[512 + 1], label_color_escaped[256 + 1], value_color_escaped[256 + 1];
-       int label_width, value_width, total_width;
-
-       if(!label_color || !*label_color) label_color = "#555";
-       if(!value_color || !*value_color) value_color = (value_is_null)?"#999":"#4c1";
-
-       units = fix_units(units);
-       calc_colorz(value_color, value_color_buffer, 256, value, value_is_null);
-
-       char *separator = "";
-       if(isalnum(*units)) separator = " ";
-
-       if(value_is_null)
-               strcpy(value_string, "-");
-       else if(precision < 0) {
-               calculated_number abs = (value < (calculated_number)0)?-value:value;
-               if(abs > (calculated_number)1000.0)      snprintfz(value_string, 512, "%0.0Lf%s%s", (long double)value, separator, units);
-               else if(abs > (calculated_number)100.0)  snprintfz(value_string, 512, "%0.1Lf%s%s", (long double)value, separator, units);
-               else if(abs > (calculated_number)1.0)    snprintfz(value_string, 512, "%0.2Lf%s%s", (long double)value, separator, units);
-               else if(abs > (calculated_number)0.1)    snprintfz(value_string, 512, "%0.3Lf%s%s", (long double)value, separator, units);
-               else                                     snprintfz(value_string, 512, "%0.4Lf%s%s", (long double)value, separator, units);
-       }
-       else {
-               if(precision > 50) precision = 50;
-               snprintfz(value_string, 512, "%0.*Lf%s%s", precision, (long double)value, separator, units);
-       }
-
-       // we need to copy the label, since verdana11_width may write to it
-       strncpyz(label_buffer, label, 256);
-
-       label_width = verdana11_width(label_buffer) + (BADGE_HORIZONTAL_PADDING * 2);
-       value_width = verdana11_width(value_string) + (BADGE_HORIZONTAL_PADDING * 2);
-       total_width = label_width + value_width;
-
-       escape_xmlz(label_escaped, label_buffer, 256);
-       escape_xmlz(value_escaped, value_string, 256);
-       escape_xmlz(label_color_escaped, color_map(label_color), 256);
-       escape_xmlz(value_color_escaped, color_map(value_color_buffer), 256);
-
-       wb->contenttype = CT_IMAGE_SVG_XML;
-
-       // svg template from:
-       // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg
-       buffer_sprintf(wb,
-               "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\">"
-                       "<linearGradient id=\"smooth\" x2=\"0\" y2=\"100%%\">"
-                               "<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>"
-                               "<stop offset=\"1\" stop-opacity=\".1\"/>"
-                       "</linearGradient>"
-                       "<mask id=\"round\">"
-                               "<rect width=\"%d\" height=\"20\" rx=\"3\" fill=\"#fff\"/>"
-                       "</mask>"
-                       "<g mask=\"url(#round)\">"
-                               "<rect width=\"%d\" height=\"20\" fill=\"%s\"/>"
-                               "<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"%s\"/>"
-                               "<rect width=\"%d\" height=\"20\" fill=\"url(#smooth)\"/>"
-                       "</g>"
-                       "<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">"
-                               "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
-                               "<text x=\"%d\" y=\"14\">%s</text>"
-                               "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
-                               "<text x=\"%d\" y=\"14\">%s</text>"
-                       "</g>"
-               "</svg>",
-               total_width, total_width,
-               label_width, label_color_escaped,
-               label_width, value_width, value_color_escaped,
-               total_width,
-               label_width / 2, label_escaped,
-               label_width / 2, label_escaped,
-               label_width + value_width / 2 -1, value_escaped,
-               label_width + value_width / 2 -1, value_escaped);
+    char label_buffer[256 + 1], value_string[512 + 1], value_color_buffer[256 + 1];
+    char label_escaped[256 + 1], value_escaped[512 + 1], label_color_escaped[256 + 1], value_color_escaped[256 + 1];
+    int label_width, value_width, total_width;
+
+    if(!label_color || !*label_color) label_color = "#555";
+    if(!value_color || !*value_color) value_color = (value_is_null)?"#999":"#4c1";
+
+    units = fix_units(units);
+    calc_colorz(value_color, value_color_buffer, 256, value, value_is_null);
+
+    char *separator = "";
+    if(isalnum(*units)) separator = " ";
+
+    if(value_is_null)
+        strcpy(value_string, "-");
+    else if(precision < 0) {
+        calculated_number abs = (value < (calculated_number)0)?-value:value;
+        if(abs > (calculated_number)1000.0)      snprintfz(value_string, 512, "%0.0Lf%s%s", (long double)value, separator, units);
+        else if(abs > (calculated_number)100.0)  snprintfz(value_string, 512, "%0.1Lf%s%s", (long double)value, separator, units);
+        else if(abs > (calculated_number)1.0)    snprintfz(value_string, 512, "%0.2Lf%s%s", (long double)value, separator, units);
+        else if(abs > (calculated_number)0.1)    snprintfz(value_string, 512, "%0.3Lf%s%s", (long double)value, separator, units);
+        else                                     snprintfz(value_string, 512, "%0.4Lf%s%s", (long double)value, separator, units);
+    }
+    else {
+        if(precision > 50) precision = 50;
+        snprintfz(value_string, 512, "%0.*Lf%s%s", precision, (long double)value, separator, units);
+    }
+
+    // we need to copy the label, since verdana11_width may write to it
+    strncpyz(label_buffer, label, 256);
+
+    label_width = verdana11_width(label_buffer) + (BADGE_HORIZONTAL_PADDING * 2);
+    value_width = verdana11_width(value_string) + (BADGE_HORIZONTAL_PADDING * 2);
+    total_width = label_width + value_width;
+
+    escape_xmlz(label_escaped, label_buffer, 256);
+    escape_xmlz(value_escaped, value_string, 256);
+    escape_xmlz(label_color_escaped, color_map(label_color), 256);
+    escape_xmlz(value_color_escaped, color_map(value_color_buffer), 256);
+
+    wb->contenttype = CT_IMAGE_SVG_XML;
+
+    // svg template from:
+    // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg
+    buffer_sprintf(wb,
+        "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\">"
+            "<linearGradient id=\"smooth\" x2=\"0\" y2=\"100%%\">"
+                "<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>"
+                "<stop offset=\"1\" stop-opacity=\".1\"/>"
+            "</linearGradient>"
+            "<mask id=\"round\">"
+                "<rect width=\"%d\" height=\"20\" rx=\"3\" fill=\"#fff\"/>"
+            "</mask>"
+            "<g mask=\"url(#round)\">"
+                "<rect width=\"%d\" height=\"20\" fill=\"%s\"/>"
+                "<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"%s\"/>"
+                "<rect width=\"%d\" height=\"20\" fill=\"url(#smooth)\"/>"
+            "</g>"
+            "<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">"
+                "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
+                "<text x=\"%d\" y=\"14\">%s</text>"
+                "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
+                "<text x=\"%d\" y=\"14\">%s</text>"
+            "</g>"
+        "</svg>",
+        total_width, total_width,
+        label_width, label_color_escaped,
+        label_width, value_width, value_color_escaped,
+        total_width,
+        label_width / 2, label_escaped,
+        label_width / 2, label_escaped,
+        label_width + value_width / 2 -1, value_escaped,
+        label_width + value_width / 2 -1, value_escaped);
 }
index bf30095b9bcd43e067f6bde65c6eee8ef9fb0cb2..80c8e1c40e8acab5dd8546b4ffda8c76a9aab9dc 100644 (file)
@@ -16,125 +16,125 @@ unsigned long long web_clients_count = 0;
 
 inline int web_client_crock_socket(struct web_client *w) {
 #ifdef TCP_CORK
-       if(likely(!w->tcp_cork && w->ofd != -1)) {
-               w->tcp_cork = 1;
-               if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
-                       error("%llu: failed to enable TCP_CORK on socket.", w->id);
-                       w->tcp_cork = 0;
-                       return -1;
-               }
-       }
+    if(likely(!w->tcp_cork && w->ofd != -1)) {
+        w->tcp_cork = 1;
+        if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
+            error("%llu: failed to enable TCP_CORK on socket.", w->id);
+            w->tcp_cork = 0;
+            return -1;
+        }
+    }
 #endif /* TCP_CORK */
 
-       return 0;
+    return 0;
 }
 
 inline int web_client_uncrock_socket(struct web_client *w) {
 #ifdef TCP_CORK
-       if(likely(w->tcp_cork && w->ofd != -1)) {
-               w->tcp_cork = 0;
-               if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
-                       error("%llu: failed to disable TCP_CORK on socket.", w->id);
-                       w->tcp_cork = 1;
-                       return -1;
-               }
-       }
+    if(likely(w->tcp_cork && w->ofd != -1)) {
+        w->tcp_cork = 0;
+        if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
+            error("%llu: failed to disable TCP_CORK on socket.", w->id);
+            w->tcp_cork = 1;
+            return -1;
+        }
+    }
 #endif /* TCP_CORK */
 
-       return 0;
+    return 0;
 }
 
 struct web_client *web_client_create(int listener)
 {
-       struct web_client *w;
-
-       w = callocz(1, sizeof(struct web_client));
-       w->id = ++web_clients_count;
-       w->mode = WEB_CLIENT_MODE_NORMAL;
-
-       {
-               struct sockaddr *sadr;
-               socklen_t addrlen;
-
-               sadr = (struct sockaddr*) &w->clientaddr;
-               addrlen = sizeof(w->clientaddr);
-
-               w->ifd = accept4(listener, sadr, &addrlen, SOCK_NONBLOCK);
-               if (w->ifd == -1) {
-                       error("%llu: Cannot accept new incoming connection.", w->id);
-                       freez(w);
-                       return NULL;
-               }
-               w->ofd = w->ifd;
-
-               if(getnameinfo(sadr, addrlen, w->client_ip, NI_MAXHOST, w->client_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
-                       error("Cannot getnameinfo() on received client connection.");
-                       strncpyz(w->client_ip,   "UNKNOWN", NI_MAXHOST);
-                       strncpyz(w->client_port, "UNKNOWN", NI_MAXSERV);
-               }
-               w->client_ip[NI_MAXHOST]   = '\0';
-               w->client_port[NI_MAXSERV] = '\0';
-
-               switch(sadr->sa_family) {
-               case AF_INET:
-                       debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
-                       break;
-
-               case AF_INET6:
-                       if(strncmp(w->client_ip, "::ffff:", 7) == 0) {
-                               memmove(w->client_ip, &w->client_ip[7], strlen(&w->client_ip[7]) + 1);
-                               debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
-                       }
-                       else
-                               debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv6 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
-                       break;
-
-               default:
-                       debug(D_WEB_CLIENT_ACCESS, "%llu: New UNKNOWN web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
-                       break;
-               }
-
-               int flag = 1;
-               if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
-                       error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
-
-               flag = 1;
-               if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
-                       error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
-       }
-
-       w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
-       w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
-       w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
-       w->origin[0] = '*';
-       w->wait_receive = 1;
-
-       if(web_clients) web_clients->prev = w;
-       w->next = web_clients;
-       web_clients = w;
+    struct web_client *w;
+
+    w = callocz(1, sizeof(struct web_client));
+    w->id = ++web_clients_count;
+    w->mode = WEB_CLIENT_MODE_NORMAL;
+
+    {
+        struct sockaddr *sadr;
+        socklen_t addrlen;
+
+        sadr = (struct sockaddr*) &w->clientaddr;
+        addrlen = sizeof(w->clientaddr);
+
+        w->ifd = accept4(listener, sadr, &addrlen, SOCK_NONBLOCK);
+        if (w->ifd == -1) {
+            error("%llu: Cannot accept new incoming connection.", w->id);
+            freez(w);
+            return NULL;
+        }
+        w->ofd = w->ifd;
+
+        if(getnameinfo(sadr, addrlen, w->client_ip, NI_MAXHOST, w->client_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+            error("Cannot getnameinfo() on received client connection.");
+            strncpyz(w->client_ip,   "UNKNOWN", NI_MAXHOST);
+            strncpyz(w->client_port, "UNKNOWN", NI_MAXSERV);
+        }
+        w->client_ip[NI_MAXHOST]   = '\0';
+        w->client_port[NI_MAXSERV] = '\0';
+
+        switch(sadr->sa_family) {
+        case AF_INET:
+            debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
+            break;
+
+        case AF_INET6:
+            if(strncmp(w->client_ip, "::ffff:", 7) == 0) {
+                memmove(w->client_ip, &w->client_ip[7], strlen(&w->client_ip[7]) + 1);
+                debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
+            }
+            else
+                debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv6 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
+            break;
+
+        default:
+            debug(D_WEB_CLIENT_ACCESS, "%llu: New UNKNOWN web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
+            break;
+        }
+
+        int flag = 1;
+        if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
+            error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
+
+        flag = 1;
+        if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
+            error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
+    }
+
+    w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
+    w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
+    w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
+    w->origin[0] = '*';
+    w->wait_receive = 1;
+
+    if(web_clients) web_clients->prev = w;
+    w->next = web_clients;
+    web_clients = w;
 
     web_client_connected();
 
-       return(w);
+    return(w);
 }
 
 void web_client_reset(struct web_client *w) {
-       web_client_uncrock_socket(w);
+    web_client_uncrock_socket(w);
 
-       debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
+    debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
 
-       if(likely(w->last_url[0])) {
-               struct timeval tv;
-               gettimeofday(&tv, NULL);
+    if(likely(w->last_url[0])) {
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
 
-               size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
-               size_t sent = size;
+        size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
+        size_t sent = size;
 #ifdef NETDATA_WITH_ZLIB
-               if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
+        if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
 #endif
 
-               // --------------------------------------------------------------------
-               // global statistics
+        // --------------------------------------------------------------------
+        // global statistics
 
         finished_web_request_statistics(usec_dt(&tv, &w->tv_in),
                                         w->stats_received_bytes,
@@ -142,1439 +142,1439 @@ void web_client_reset(struct web_client *w) {
                                         size,
                                         sent);
 
-               w->stats_received_bytes = 0;
-               w->stats_sent_bytes = 0;
-
-
-               // --------------------------------------------------------------------
-               // access log
-
-               log_access("%llu: (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: %d '%s'",
-                                  w->id,
-                                  sent, size, -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0),
-                                  usec_dt(&w->tv_ready, &w->tv_in) / 1000.0,
-                                  usec_dt(&tv, &w->tv_ready) / 1000.0,
-                                  usec_dt(&tv, &w->tv_in) / 1000.0,
-                                  (w->mode == WEB_CLIENT_MODE_FILECOPY) ? "filecopy" : ((w->mode == WEB_CLIENT_MODE_OPTIONS)
-                                                                                                                                                ? "options" : "data"),
-                                  w->response.code,
-                                  w->last_url
-               );
-       }
-
-       if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
-               if(w->ifd != w->ofd) {
-                       debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
-                       if(w->ifd != -1) close(w->ifd);
-                       w->ifd = w->ofd;
-               }
-       }
-
-       w->last_url[0] = '\0';
-       w->cookie1[0] = '\0';
-       w->cookie2[0] = '\0';
-       w->origin[0] = '*';
-       w->origin[1] = '\0';
-
-       w->mode = WEB_CLIENT_MODE_NORMAL;
-
-       w->tcp_cork = 0;
-       w->donottrack = 0;
-       w->tracking_required = 0;
-       w->keepalive = 0;
-       w->decoded_url[0] = '\0';
-
-       buffer_reset(w->response.header_output);
-       buffer_reset(w->response.header);
-       buffer_reset(w->response.data);
-       w->response.rlen = 0;
-       w->response.sent = 0;
-       w->response.code = 0;
-
-       w->wait_receive = 1;
-       w->wait_send = 0;
-
-       w->response.zoutput = 0;
-
-       // if we had enabled compression, release it
+        w->stats_received_bytes = 0;
+        w->stats_sent_bytes = 0;
+
+
+        // --------------------------------------------------------------------
+        // access log
+
+        log_access("%llu: (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: %d '%s'",
+                   w->id,
+                   sent, size, -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0),
+                   usec_dt(&w->tv_ready, &w->tv_in) / 1000.0,
+                   usec_dt(&tv, &w->tv_ready) / 1000.0,
+                   usec_dt(&tv, &w->tv_in) / 1000.0,
+                   (w->mode == WEB_CLIENT_MODE_FILECOPY) ? "filecopy" : ((w->mode == WEB_CLIENT_MODE_OPTIONS)
+                                                                         ? "options" : "data"),
+                   w->response.code,
+                   w->last_url
+        );
+    }
+
+    if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
+        if(w->ifd != w->ofd) {
+            debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
+            if(w->ifd != -1) close(w->ifd);
+            w->ifd = w->ofd;
+        }
+    }
+
+    w->last_url[0] = '\0';
+    w->cookie1[0] = '\0';
+    w->cookie2[0] = '\0';
+    w->origin[0] = '*';
+    w->origin[1] = '\0';
+
+    w->mode = WEB_CLIENT_MODE_NORMAL;
+
+    w->tcp_cork = 0;
+    w->donottrack = 0;
+    w->tracking_required = 0;
+    w->keepalive = 0;
+    w->decoded_url[0] = '\0';
+
+    buffer_reset(w->response.header_output);
+    buffer_reset(w->response.header);
+    buffer_reset(w->response.data);
+    w->response.rlen = 0;
+    w->response.sent = 0;
+    w->response.code = 0;
+
+    w->wait_receive = 1;
+    w->wait_send = 0;
+
+    w->response.zoutput = 0;
+
+    // if we had enabled compression, release it
 #ifdef NETDATA_WITH_ZLIB
-       if(w->response.zinitialized) {
-               debug(D_DEFLATE, "%llu: Freeing compression resources.", w->id);
-               deflateEnd(&w->response.zstream);
-               w->response.zsent = 0;
-               w->response.zhave = 0;
-               w->response.zstream.avail_in = 0;
-               w->response.zstream.avail_out = 0;
-               w->response.zstream.total_in = 0;
-               w->response.zstream.total_out = 0;
-               w->response.zinitialized = 0;
-       }
+    if(w->response.zinitialized) {
+        debug(D_DEFLATE, "%llu: Freeing compression resources.", w->id);
+        deflateEnd(&w->response.zstream);
+        w->response.zsent = 0;
+        w->response.zhave = 0;
+        w->response.zstream.avail_in = 0;
+        w->response.zstream.avail_out = 0;
+        w->response.zstream.total_in = 0;
+        w->response.zstream.total_out = 0;
+        w->response.zinitialized = 0;
+    }
 #endif // NETDATA_WITH_ZLIB
 }
 
 struct web_client *web_client_free(struct web_client *w) {
-       web_client_reset(w);
+    web_client_reset(w);
 
-       struct web_client *n = w->next;
-       if(w == web_clients) web_clients = n;
+    struct web_client *n = w->next;
+    if(w == web_clients) web_clients = n;
 
-       debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
+    debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
 
-       if(w->prev)     w->prev->next = w->next;
-       if(w->next) w->next->prev = w->prev;
-       if(w->response.header_output) buffer_free(w->response.header_output);
-       if(w->response.header) buffer_free(w->response.header);
-       if(w->response.data) buffer_free(w->response.data);
-       if(w->ifd != -1) close(w->ifd);
-       if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
-       freez(w);
+    if(w->prev) w->prev->next = w->next;
+    if(w->next) w->next->prev = w->prev;
+    if(w->response.header_output) buffer_free(w->response.header_output);
+    if(w->response.header) buffer_free(w->response.header);
+    if(w->response.data) buffer_free(w->response.data);
+    if(w->ifd != -1) close(w->ifd);
+    if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
+    freez(w);
 
     web_client_disconnected();
 
-       return(n);
+    return(n);
 }
 
 uid_t web_files_uid(void) {
-       static char *web_owner = NULL;
-       static uid_t owner_uid = 0;
-
-       if(unlikely(!web_owner)) {
-               web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
-               if(!web_owner || !*web_owner)
-                       owner_uid = geteuid();
-               else {
-                       // getpwnam() is not thread safe,
-                       // but we have called this function once
-                       // while single threaded
-                       struct passwd *pw = getpwnam(web_owner);
-                       if(!pw) {
-                               error("User '%s' is not present. Ignoring option.", web_owner);
-                               owner_uid = geteuid();
-                       }
-                       else {
-                               debug(D_WEB_CLIENT, "Web files owner set to %s.", web_owner);
-                               owner_uid = pw->pw_uid;
-                       }
-               }
-       }
-
-       return(owner_uid);
+    static char *web_owner = NULL;
+    static uid_t owner_uid = 0;
+
+    if(unlikely(!web_owner)) {
+        web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
+        if(!web_owner || !*web_owner)
+            owner_uid = geteuid();
+        else {
+            // getpwnam() is not thread safe,
+            // but we have called this function once
+            // while single threaded
+            struct passwd *pw = getpwnam(web_owner);
+            if(!pw) {
+                error("User '%s' is not present. Ignoring option.", web_owner);
+                owner_uid = geteuid();
+            }
+            else {
+                debug(D_WEB_CLIENT, "Web files owner set to %s.", web_owner);
+                owner_uid = pw->pw_uid;
+            }
+        }
+    }
+
+    return(owner_uid);
 }
 
 gid_t web_files_gid(void) {
-       static char *web_group = NULL;
-       static gid_t owner_gid = 0;
-
-       if(unlikely(!web_group)) {
-               web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
-               if(!web_group || !*web_group)
-                       owner_gid = getegid();
-               else {
-                       // getgrnam() is not thread safe,
-                       // but we have called this function once
-                       // while single threaded
-                       struct group *gr = getgrnam(web_group);
-                       if(!gr) {
-                               error("Group '%s' is not present. Ignoring option.", web_group);
-                               owner_gid = getegid();
-                       }
-                       else {
-                               debug(D_WEB_CLIENT, "Web files group set to %s.", web_group);
-                               owner_gid = gr->gr_gid;
-                       }
-               }
-       }
-
-       return(owner_gid);
+    static char *web_group = NULL;
+    static gid_t owner_gid = 0;
+
+    if(unlikely(!web_group)) {
+        web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
+        if(!web_group || !*web_group)
+            owner_gid = getegid();
+        else {
+            // getgrnam() is not thread safe,
+            // but we have called this function once
+            // while single threaded
+            struct group *gr = getgrnam(web_group);
+            if(!gr) {
+                error("Group '%s' is not present. Ignoring option.", web_group);
+                owner_gid = getegid();
+            }
+            else {
+                debug(D_WEB_CLIENT, "Web files group set to %s.", web_group);
+                owner_gid = gr->gr_gid;
+            }
+        }
+    }
+
+    return(owner_gid);
 }
 
 int mysendfile(struct web_client *w, char *filename)
 {
-       static char *web_dir = NULL;
-
-       // initialize our static data
-       if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
-
-       debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
-
-       // skip leading slashes
-       while (*filename == '/') filename++;
-
-       // if the filename contain known paths, skip them
-       if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0)
-               filename = &filename[strlen(WEB_PATH_FILE) + 1];
-
-       char *s;
-       for(s = filename; *s ;s++) {
-               if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
-                       debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
-                       buffer_sprintf(w->response.data, "File '%s' cannot be served. Filename contains invalid character '%c'", filename, *s);
-                       return 400;
-               }
-       }
-
-       // if the filename contains a .. refuse to serve it
-       if(strstr(filename, "..") != 0) {
-               debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
-               buffer_sprintf(w->response.data, "File '%s' cannot be served. Relative filenames with '..' in them are not supported.", filename);
-               return 400;
-       }
-
-       // access the file
-       char webfilename[FILENAME_MAX + 1];
-       snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
-
-       // check if the file exists
-       struct stat stat;
-       if(lstat(webfilename, &stat) != 0) {
-               debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
-               buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", webfilename);
-               return 404;
-       }
-
-       // check if the file is owned by expected user
-       if(stat.st_uid != web_files_uid()) {
-               error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
-               buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
-               return 403;
-       }
-
-       // check if the file is owned by expected group
-       if(stat.st_gid != web_files_gid()) {
-               error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
-               buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
-               return 403;
-       }
-
-       if((stat.st_mode & S_IFMT) == S_IFDIR) {
-               snprintfz(webfilename, FILENAME_MAX, "%s/index.html", filename);
-               return mysendfile(w, webfilename);
-       }
-
-       if((stat.st_mode & S_IFMT) != S_IFREG) {
-               error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
-               buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
-               return 403;
-       }
-
-       // open the file
-       w->ifd = open(webfilename, O_NONBLOCK, O_RDONLY);
-       if(w->ifd == -1) {
-               w->ifd = w->ofd;
-
-               if(errno == EBUSY || errno == EAGAIN) {
-                       error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
-                       buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
-                       buffer_sprintf(w->response.data, "The file '%s' is currently busy. Please try again later.", webfilename);
-                       return 307;
-               }
-               else {
-                       error("%llu: Cannot open file '%s'.", w->id, webfilename);
-                       buffer_sprintf(w->response.data, "Cannot open file '%s'.", webfilename);
-                       return 404;
-               }
-       }
-       if(fcntl(w->ifd, F_SETFL, O_NONBLOCK) < 0)
-               error("%llu: Cannot set O_NONBLOCK on file '%s'.", w->id, webfilename);
-
-       // pick a Content-Type for the file
-                if(strstr(filename, ".html") != NULL)  w->response.data->contenttype = CT_TEXT_HTML;
-       else if(strstr(filename, ".js")   != NULL)      w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-       else if(strstr(filename, ".css")  != NULL)      w->response.data->contenttype = CT_TEXT_CSS;
-       else if(strstr(filename, ".xml")  != NULL)      w->response.data->contenttype = CT_TEXT_XML;
-       else if(strstr(filename, ".xsl")  != NULL)      w->response.data->contenttype = CT_TEXT_XSL;
-       else if(strstr(filename, ".txt")  != NULL)  w->response.data->contenttype = CT_TEXT_PLAIN;
-       else if(strstr(filename, ".svg")  != NULL)  w->response.data->contenttype = CT_IMAGE_SVG_XML;
-       else if(strstr(filename, ".ttf")  != NULL)  w->response.data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
-       else if(strstr(filename, ".otf")  != NULL)  w->response.data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
-       else if(strstr(filename, ".woff2")!= NULL)  w->response.data->contenttype = CT_APPLICATION_FONT_WOFF2;
-       else if(strstr(filename, ".woff") != NULL)  w->response.data->contenttype = CT_APPLICATION_FONT_WOFF;
-       else if(strstr(filename, ".eot")  != NULL)  w->response.data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
-       else if(strstr(filename, ".png")  != NULL)  w->response.data->contenttype = CT_IMAGE_PNG;
-       else if(strstr(filename, ".jpg")  != NULL)  w->response.data->contenttype = CT_IMAGE_JPG;
-       else if(strstr(filename, ".jpeg") != NULL)  w->response.data->contenttype = CT_IMAGE_JPG;
-       else if(strstr(filename, ".gif")  != NULL)  w->response.data->contenttype = CT_IMAGE_GIF;
-       else if(strstr(filename, ".bmp")  != NULL)  w->response.data->contenttype = CT_IMAGE_BMP;
-       else if(strstr(filename, ".ico")  != NULL)  w->response.data->contenttype = CT_IMAGE_XICON;
-       else if(strstr(filename, ".icns") != NULL)  w->response.data->contenttype = CT_IMAGE_ICNS;
-       else w->response.data->contenttype = CT_APPLICATION_OCTET_STREAM;
-
-       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
-
-       w->mode = WEB_CLIENT_MODE_FILECOPY;
-       w->wait_receive = 1;
-       w->wait_send = 0;
-       buffer_flush(w->response.data);
-       w->response.rlen = stat.st_size;
-       w->response.data->date = stat.st_mtim.tv_sec;
-
-       return 200;
+    static char *web_dir = NULL;
+
+    // initialize our static data
+    if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
+
+    debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
+
+    // skip leading slashes
+    while (*filename == '/') filename++;
+
+    // if the filename contain known paths, skip them
+    if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0)
+        filename = &filename[strlen(WEB_PATH_FILE) + 1];
+
+    char *s;
+    for(s = filename; *s ;s++) {
+        if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
+            debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+            buffer_sprintf(w->response.data, "File '%s' cannot be served. Filename contains invalid character '%c'", filename, *s);
+            return 400;
+        }
+    }
+
+    // if the filename contains a .. refuse to serve it
+    if(strstr(filename, "..") != 0) {
+        debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
+        buffer_sprintf(w->response.data, "File '%s' cannot be served. Relative filenames with '..' in them are not supported.", filename);
+        return 400;
+    }
+
+    // access the file
+    char webfilename[FILENAME_MAX + 1];
+    snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
+
+    // check if the file exists
+    struct stat stat;
+    if(lstat(webfilename, &stat) != 0) {
+        debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
+        buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", webfilename);
+        return 404;
+    }
+
+    // check if the file is owned by expected user
+    if(stat.st_uid != web_files_uid()) {
+        error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
+        buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
+        return 403;
+    }
+
+    // check if the file is owned by expected group
+    if(stat.st_gid != web_files_gid()) {
+        error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
+        buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
+        return 403;
+    }
+
+    if((stat.st_mode & S_IFMT) == S_IFDIR) {
+        snprintfz(webfilename, FILENAME_MAX, "%s/index.html", filename);
+        return mysendfile(w, webfilename);
+    }
+
+    if((stat.st_mode & S_IFMT) != S_IFREG) {
+        error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
+        buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
+        return 403;
+    }
+
+    // open the file
+    w->ifd = open(webfilename, O_NONBLOCK, O_RDONLY);
+    if(w->ifd == -1) {
+        w->ifd = w->ofd;
+
+        if(errno == EBUSY || errno == EAGAIN) {
+            error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
+            buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
+            buffer_sprintf(w->response.data, "The file '%s' is currently busy. Please try again later.", webfilename);
+            return 307;
+        }
+        else {
+            error("%llu: Cannot open file '%s'.", w->id, webfilename);
+            buffer_sprintf(w->response.data, "Cannot open file '%s'.", webfilename);
+            return 404;
+        }
+    }
+    if(fcntl(w->ifd, F_SETFL, O_NONBLOCK) < 0)
+        error("%llu: Cannot set O_NONBLOCK on file '%s'.", w->id, webfilename);
+
+    // pick a Content-Type for the file
+         if(strstr(filename, ".html") != NULL)  w->response.data->contenttype = CT_TEXT_HTML;
+    else if(strstr(filename, ".js")   != NULL)  w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+    else if(strstr(filename, ".css")  != NULL)  w->response.data->contenttype = CT_TEXT_CSS;
+    else if(strstr(filename, ".xml")  != NULL)  w->response.data->contenttype = CT_TEXT_XML;
+    else if(strstr(filename, ".xsl")  != NULL)  w->response.data->contenttype = CT_TEXT_XSL;
+    else if(strstr(filename, ".txt")  != NULL)  w->response.data->contenttype = CT_TEXT_PLAIN;
+    else if(strstr(filename, ".svg")  != NULL)  w->response.data->contenttype = CT_IMAGE_SVG_XML;
+    else if(strstr(filename, ".ttf")  != NULL)  w->response.data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
+    else if(strstr(filename, ".otf")  != NULL)  w->response.data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
+    else if(strstr(filename, ".woff2")!= NULL)  w->response.data->contenttype = CT_APPLICATION_FONT_WOFF2;
+    else if(strstr(filename, ".woff") != NULL)  w->response.data->contenttype = CT_APPLICATION_FONT_WOFF;
+    else if(strstr(filename, ".eot")  != NULL)  w->response.data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
+    else if(strstr(filename, ".png")  != NULL)  w->response.data->contenttype = CT_IMAGE_PNG;
+    else if(strstr(filename, ".jpg")  != NULL)  w->response.data->contenttype = CT_IMAGE_JPG;
+    else if(strstr(filename, ".jpeg") != NULL)  w->response.data->contenttype = CT_IMAGE_JPG;
+    else if(strstr(filename, ".gif")  != NULL)  w->response.data->contenttype = CT_IMAGE_GIF;
+    else if(strstr(filename, ".bmp")  != NULL)  w->response.data->contenttype = CT_IMAGE_BMP;
+    else if(strstr(filename, ".ico")  != NULL)  w->response.data->contenttype = CT_IMAGE_XICON;
+    else if(strstr(filename, ".icns") != NULL)  w->response.data->contenttype = CT_IMAGE_ICNS;
+    else w->response.data->contenttype = CT_APPLICATION_OCTET_STREAM;
+
+    debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
+
+    w->mode = WEB_CLIENT_MODE_FILECOPY;
+    w->wait_receive = 1;
+    w->wait_send = 0;
+    buffer_flush(w->response.data);
+    w->response.rlen = stat.st_size;
+    w->response.data->date = stat.st_mtim.tv_sec;
+
+    return 200;
 }
 
 
 #ifdef NETDATA_WITH_ZLIB
 void web_client_enable_deflate(struct web_client *w, int gzip) {
-       if(unlikely(w->response.zinitialized)) {
-               error("%llu: Compression has already be initialized for this client.", w->id);
-               return;
-       }
-
-       if(unlikely(w->response.sent)) {
-               error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
-               return;
-       }
-
-       w->response.zstream.zalloc = Z_NULL;
-       w->response.zstream.zfree = Z_NULL;
-       w->response.zstream.opaque = Z_NULL;
-
-       w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
-       w->response.zstream.avail_in = 0;
-       w->response.zstream.total_in = 0;
-
-       w->response.zstream.next_out = w->response.zbuffer;
-       w->response.zstream.avail_out = 0;
-       w->response.zstream.total_out = 0;
-
-       w->response.zstream.zalloc = Z_NULL;
-       w->response.zstream.zfree = Z_NULL;
-       w->response.zstream.opaque = Z_NULL;
-
-//     if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
-//             error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
-//             return;
-//     }
-
-       // Select GZIP compression: windowbits = 15 + 16 = 31
-       if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) {
-               error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
-               return;
-       }
-
-       w->response.zsent = 0;
-       w->response.zoutput = 1;
-       w->response.zinitialized = 1;
-
-       debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
+    if(unlikely(w->response.zinitialized)) {
+        error("%llu: Compression has already be initialized for this client.", w->id);
+        return;
+    }
+
+    if(unlikely(w->response.sent)) {
+        error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
+        return;
+    }
+
+    w->response.zstream.zalloc = Z_NULL;
+    w->response.zstream.zfree = Z_NULL;
+    w->response.zstream.opaque = Z_NULL;
+
+    w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
+    w->response.zstream.avail_in = 0;
+    w->response.zstream.total_in = 0;
+
+    w->response.zstream.next_out = w->response.zbuffer;
+    w->response.zstream.avail_out = 0;
+    w->response.zstream.total_out = 0;
+
+    w->response.zstream.zalloc = Z_NULL;
+    w->response.zstream.zfree = Z_NULL;
+    w->response.zstream.opaque = Z_NULL;
+
+//  if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
+//      error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
+//      return;
+//  }
+
+    // Select GZIP compression: windowbits = 15 + 16 = 31
+    if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) {
+        error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
+        return;
+    }
+
+    w->response.zsent = 0;
+    w->response.zoutput = 1;
+    w->response.zinitialized = 1;
+
+    debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
 }
 #endif // NETDATA_WITH_ZLIB
 
 uint32_t web_client_api_request_v1_data_options(char *o)
 {
-       uint32_t ret = 0x00000000;
-       char *tok;
-
-       while(o && *o && (tok = mystrsep(&o, ", |"))) {
-               if(!*tok) continue;
-
-               if(!strcmp(tok, "nonzero"))
-                       ret |= RRDR_OPTION_NONZERO;
-               else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
-                       ret |= RRDR_OPTION_REVERSED;
-               else if(!strcmp(tok, "jsonwrap"))
-                       ret |= RRDR_OPTION_JSON_WRAP;
-               else if(!strcmp(tok, "min2max"))
-                       ret |= RRDR_OPTION_MIN2MAX;
-               else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
-                       ret |= RRDR_OPTION_MILLISECONDS;
-               else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
-                       ret |= RRDR_OPTION_ABSOLUTE;
-               else if(!strcmp(tok, "seconds"))
-                       ret |= RRDR_OPTION_SECONDS;
-               else if(!strcmp(tok, "null2zero"))
-                       ret |= RRDR_OPTION_NULL2ZERO;
-               else if(!strcmp(tok, "objectrows"))
-                       ret |= RRDR_OPTION_OBJECTSROWS;
-               else if(!strcmp(tok, "google_json"))
-                       ret |= RRDR_OPTION_GOOGLE_JSON;
-               else if(!strcmp(tok, "percentage"))
-                       ret |= RRDR_OPTION_PERCENTAGE;
-               else if(!strcmp(tok, "unaligned"))
-                       ret |= RRDR_OPTION_NOT_ALIGNED;
-       }
-
-       return ret;
+    uint32_t ret = 0x00000000;
+    char *tok;
+
+    while(o && *o && (tok = mystrsep(&o, ", |"))) {
+        if(!*tok) continue;
+
+        if(!strcmp(tok, "nonzero"))
+            ret |= RRDR_OPTION_NONZERO;
+        else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
+            ret |= RRDR_OPTION_REVERSED;
+        else if(!strcmp(tok, "jsonwrap"))
+            ret |= RRDR_OPTION_JSON_WRAP;
+        else if(!strcmp(tok, "min2max"))
+            ret |= RRDR_OPTION_MIN2MAX;
+        else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
+            ret |= RRDR_OPTION_MILLISECONDS;
+        else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
+            ret |= RRDR_OPTION_ABSOLUTE;
+        else if(!strcmp(tok, "seconds"))
+            ret |= RRDR_OPTION_SECONDS;
+        else if(!strcmp(tok, "null2zero"))
+            ret |= RRDR_OPTION_NULL2ZERO;
+        else if(!strcmp(tok, "objectrows"))
+            ret |= RRDR_OPTION_OBJECTSROWS;
+        else if(!strcmp(tok, "google_json"))
+            ret |= RRDR_OPTION_GOOGLE_JSON;
+        else if(!strcmp(tok, "percentage"))
+            ret |= RRDR_OPTION_PERCENTAGE;
+        else if(!strcmp(tok, "unaligned"))
+            ret |= RRDR_OPTION_NOT_ALIGNED;
+    }
+
+    return ret;
 }
 
 uint32_t web_client_api_request_v1_data_format(char *name)
 {
-       if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
-               return DATASOURCE_DATATABLE_JSON;
+    if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
+        return DATASOURCE_DATATABLE_JSON;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
-               return DATASOURCE_DATATABLE_JSONP;
+    else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
+        return DATASOURCE_DATATABLE_JSONP;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
-               return DATASOURCE_JSON;
+    else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
+        return DATASOURCE_JSON;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
-               return DATASOURCE_JSONP;
+    else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
+        return DATASOURCE_JSONP;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
-               return DATASOURCE_SSV;
+    else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
+        return DATASOURCE_SSV;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
-               return DATASOURCE_CSV;
+    else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
+        return DATASOURCE_CSV;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
-               return DATASOURCE_TSV;
+    else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
+        return DATASOURCE_TSV;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
-               return DATASOURCE_HTML;
+    else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
+        return DATASOURCE_HTML;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
-               return DATASOURCE_JS_ARRAY;
+    else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
+        return DATASOURCE_JS_ARRAY;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
-               return DATASOURCE_SSV_COMMA;
+    else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
+        return DATASOURCE_SSV_COMMA;
 
-       else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
-               return DATASOURCE_CSV_JSON_ARRAY;
+    else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
+        return DATASOURCE_CSV_JSON_ARRAY;
 
-       return DATASOURCE_JSON;
+    return DATASOURCE_JSON;
 }
 
 uint32_t web_client_api_request_v1_data_google_format(char *name)
 {
-       if(!strcmp(name, "json"))
-               return DATASOURCE_DATATABLE_JSONP;
+    if(!strcmp(name, "json"))
+        return DATASOURCE_DATATABLE_JSONP;
 
-       else if(!strcmp(name, "html"))
-               return DATASOURCE_HTML;
+    else if(!strcmp(name, "html"))
+        return DATASOURCE_HTML;
 
-       else if(!strcmp(name, "csv"))
-               return DATASOURCE_CSV;
+    else if(!strcmp(name, "csv"))
+        return DATASOURCE_CSV;
 
-       else if(!strcmp(name, "tsv-excel"))
-               return DATASOURCE_TSV;
+    else if(!strcmp(name, "tsv-excel"))
+        return DATASOURCE_TSV;
 
-       return DATASOURCE_JSON;
+    return DATASOURCE_JSON;
 }
 
 int web_client_api_request_v1_data_group(char *name, int def)
 {
-       if(!strcmp(name, "max"))
-               return GROUP_MAX;
+    if(!strcmp(name, "max"))
+        return GROUP_MAX;
 
-       else if(!strcmp(name, "average"))
-               return GROUP_AVERAGE;
+    else if(!strcmp(name, "average"))
+        return GROUP_AVERAGE;
 
-       else if(!strcmp(name, "sum"))
-               return GROUP_SUM;
+    else if(!strcmp(name, "sum"))
+        return GROUP_SUM;
 
-       else if(!strcmp(name, "incremental-sum"))
-               return GROUP_INCREMENTAL_SUM;
+    else if(!strcmp(name, "incremental-sum"))
+        return GROUP_INCREMENTAL_SUM;
 
-       return def;
+    return def;
 }
 
 int web_client_api_request_v1_charts(struct web_client *w, char *url)
 {
-       if(url) { ; }
+    if(url) { ; }
 
-       buffer_flush(w->response.data);
-       w->response.data->contenttype = CT_APPLICATION_JSON;
-       rrd_stats_api_v1_charts(w->response.data);
-       return 200;
+    buffer_flush(w->response.data);
+    w->response.data->contenttype = CT_APPLICATION_JSON;
+    rrd_stats_api_v1_charts(w->response.data);
+    return 200;
 }
 
 int web_client_api_request_v1_chart(struct web_client *w, char *url)
 {
-       int ret = 400;
-       char *chart = NULL;
-
-       buffer_flush(w->response.data);
-
-       while(url) {
-               char *value = mystrsep(&url, "?&[]");
-               if(!value || !*value) continue;
-
-               char *name = mystrsep(&value, "=");
-               if(!name || !*name) continue;
-               if(!value || !*value) continue;
-
-               // name and value are now the parameters
-               // they are not null and not empty
-
-               if(!strcmp(name, "chart")) chart = value;
-               //else {
-               ///     buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
-               //      goto cleanup;
-               //}
-       }
-
-       if(!chart || !*chart) {
-               buffer_sprintf(w->response.data, "No chart id is given at the request.");
-               goto cleanup;
-       }
-
-       RRDSET *st = rrdset_find(chart);
-       if(!st) st = rrdset_find_byname(chart);
-       if(!st) {
-               buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
-               ret = 404;
-               goto cleanup;
-       }
-
-       w->response.data->contenttype = CT_APPLICATION_JSON;
-       rrd_stats_api_v1_chart(st, w->response.data);
-       return 200;
+    int ret = 400;
+    char *chart = NULL;
+
+    buffer_flush(w->response.data);
+
+    while(url) {
+        char *value = mystrsep(&url, "?&[]");
+        if(!value || !*value) continue;
+
+        char *name = mystrsep(&value, "=");
+        if(!name || !*name) continue;
+        if(!value || !*value) continue;
+
+        // name and value are now the parameters
+        // they are not null and not empty
+
+        if(!strcmp(name, "chart")) chart = value;
+        //else {
+        /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
+        //  goto cleanup;
+        //}
+    }
+
+    if(!chart || !*chart) {
+        buffer_sprintf(w->response.data, "No chart id is given at the request.");
+        goto cleanup;
+    }
+
+    RRDSET *st = rrdset_find(chart);
+    if(!st) st = rrdset_find_byname(chart);
+    if(!st) {
+        buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
+        ret = 404;
+        goto cleanup;
+    }
+
+    w->response.data->contenttype = CT_APPLICATION_JSON;
+    rrd_stats_api_v1_chart(st, w->response.data);
+    return 200;
 
 cleanup:
-       return ret;
+    return ret;
 }
 
 int web_client_api_v1_badge(struct web_client *w, char *url) {
-       int ret = 400;
-       buffer_flush(w->response.data);
-
-       BUFFER *dimensions = NULL;
-       
-       const char *chart = NULL
-                       , *before_str = NULL
-                       , *after_str = NULL
-                       , *points_str = NULL
-                       , *multiply_str = NULL
-                       , *divide_str = NULL
-                       , *label = NULL
-                       , *units = NULL
-                       , *label_color = NULL
-                       , *value_color = NULL
-                       , *refresh_str = NULL
-                       , *precision_str = NULL;
-
-       int group = GROUP_AVERAGE;
-       uint32_t options = 0x00000000;
-
-       while(url) {
-               char *value = mystrsep(&url, "/?&[]");
-               if(!value || !*value) continue;
-
-               char *name = mystrsep(&value, "=");
-               if(!name || !*name) continue;
-               if(!value || !*value) continue;
-
-               debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
-
-               // name and value are now the parameters
-               // they are not null and not empty
-
-               if(!strcmp(name, "chart")) chart = value;
-               else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
-                       if(!dimensions)
-                               dimensions = buffer_create(100);
+    int ret = 400;
+    buffer_flush(w->response.data);
+
+    BUFFER *dimensions = NULL;
+    
+    const char *chart = NULL
+            , *before_str = NULL
+            , *after_str = NULL
+            , *points_str = NULL
+            , *multiply_str = NULL
+            , *divide_str = NULL
+            , *label = NULL
+            , *units = NULL
+            , *label_color = NULL
+            , *value_color = NULL
+            , *refresh_str = NULL
+            , *precision_str = NULL;
+
+    int group = GROUP_AVERAGE;
+    uint32_t options = 0x00000000;
+
+    while(url) {
+        char *value = mystrsep(&url, "/?&[]");
+        if(!value || !*value) continue;
+
+        char *name = mystrsep(&value, "=");
+        if(!name || !*name) continue;
+        if(!value || !*value) continue;
+
+        debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
+
+        // name and value are now the parameters
+        // they are not null and not empty
+
+        if(!strcmp(name, "chart")) chart = value;
+        else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+            if(!dimensions)
+                dimensions = buffer_create(100);
 
             buffer_strcat(dimensions, "|");
             buffer_strcat(dimensions, value);
-               }
-               else if(!strcmp(name, "after")) after_str = value;
-               else if(!strcmp(name, "before")) before_str = value;
-               else if(!strcmp(name, "points")) points_str = value;
-               else if(!strcmp(name, "group")) {
-                       group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
-               }
-               else if(!strcmp(name, "options")) {
-                       options |= web_client_api_request_v1_data_options(value);
-               }
-               else if(!strcmp(name, "label")) label = value;
-               else if(!strcmp(name, "units")) units = value;
-               else if(!strcmp(name, "label_color")) label_color = value;
-               else if(!strcmp(name, "value_color")) value_color = value;
-               else if(!strcmp(name, "multiply")) multiply_str = value;
-               else if(!strcmp(name, "divide")) divide_str = value;
-               else if(!strcmp(name, "refresh")) refresh_str = value;
-               else if(!strcmp(name, "precision")) precision_str = value;
-       }
-
-       if(!chart || !*chart) {
-               buffer_sprintf(w->response.data, "No chart id is given at the request.");
-               goto cleanup;
-       }
-
-       RRDSET *st = rrdset_find(chart);
-       if(!st) st = rrdset_find_byname(chart);
-       if(!st) {
-               buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
-               ret = 200;
-               goto cleanup;
-       }
-
-       long long multiply  = (multiply_str  && *multiply_str )?atol(multiply_str):1;
-       long long divide    = (divide_str    && *divide_str   )?atol(divide_str):1;
-       long long before    = (before_str    && *before_str   )?atol(before_str):0;
-       long long after     = (after_str     && *after_str    )?atol(after_str):-st->update_every;
-       int       points    = (points_str    && *points_str   )?atoi(points_str):1;
-       int       precision = (precision_str && *precision_str)?atoi(precision_str):-1;
-
-       if(!multiply) multiply = 1;
-       if(!divide) divide = 1;
-
-       int refresh = 0;
-       if(refresh_str && *refresh_str) {
-               if(!strcmp(refresh_str, "auto")) {
-                       if(options & RRDR_OPTION_NOT_ALIGNED)
-                               refresh = st->update_every;
-                       else {
-                               refresh = (before - after);
-                               if(refresh < 0) refresh = -refresh;
-                       }
-               }
-               else {
-                       refresh = atoi(refresh_str);
-                       if(refresh < 0) refresh = -refresh;
-               }
-       }
-
-       if(!label) {
-               if(dimensions) {
-                       const char *dim = buffer_tostring(dimensions);
-                       if(*dim == '|') dim++;
-                       label = dim;
-               }
-               else
-                       label = st->name;
-       }
-       if(!units) {
-               if(options & RRDR_OPTION_PERCENTAGE)
-                       units="%";
-               else
-                       units = st->units;
-       }
-
-       debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
-                       , w->id
-                       , chart
-                       , (dimensions)?buffer_tostring(dimensions):""
-                       , after
-                       , before
-                       , points
-                       , group
-                       , options
-                       );
-
-       time_t latest_timestamp = 0;
-       int value_is_null = 1;
-       calculated_number n = 0;
-       ret = 500;
-
-       // if the collected value is too old, don't calculate its value
-       if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
-               ret = rrd2value(st, w->response.data, &n, dimensions, points, after, before, group, options, &latest_timestamp, &value_is_null);
-
-       // if the value cannot be calculated, show empty badge
-       if(ret != 200) {
-               value_is_null = 1;
-               n = 0;
-               ret = 200;
-       }
-       else if(refresh > 0)
-               buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
-
-       // render the badge
-       buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
+        }
+        else if(!strcmp(name, "after")) after_str = value;
+        else if(!strcmp(name, "before")) before_str = value;
+        else if(!strcmp(name, "points")) points_str = value;
+        else if(!strcmp(name, "group")) {
+            group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+        }
+        else if(!strcmp(name, "options")) {
+            options |= web_client_api_request_v1_data_options(value);
+        }
+        else if(!strcmp(name, "label")) label = value;
+        else if(!strcmp(name, "units")) units = value;
+        else if(!strcmp(name, "label_color")) label_color = value;
+        else if(!strcmp(name, "value_color")) value_color = value;
+        else if(!strcmp(name, "multiply")) multiply_str = value;
+        else if(!strcmp(name, "divide")) divide_str = value;
+        else if(!strcmp(name, "refresh")) refresh_str = value;
+        else if(!strcmp(name, "precision")) precision_str = value;
+    }
+
+    if(!chart || !*chart) {
+        buffer_sprintf(w->response.data, "No chart id is given at the request.");
+        goto cleanup;
+    }
+
+    RRDSET *st = rrdset_find(chart);
+    if(!st) st = rrdset_find_byname(chart);
+    if(!st) {
+        buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
+        ret = 200;
+        goto cleanup;
+    }
+
+    long long multiply  = (multiply_str  && *multiply_str )?atol(multiply_str):1;
+    long long divide    = (divide_str    && *divide_str   )?atol(divide_str):1;
+    long long before    = (before_str    && *before_str   )?atol(before_str):0;
+    long long after     = (after_str     && *after_str    )?atol(after_str):-st->update_every;
+    int       points    = (points_str    && *points_str   )?atoi(points_str):1;
+    int       precision = (precision_str && *precision_str)?atoi(precision_str):-1;
+
+    if(!multiply) multiply = 1;
+    if(!divide) divide = 1;
+
+    int refresh = 0;
+    if(refresh_str && *refresh_str) {
+        if(!strcmp(refresh_str, "auto")) {
+            if(options & RRDR_OPTION_NOT_ALIGNED)
+                refresh = st->update_every;
+            else {
+                refresh = (before - after);
+                if(refresh < 0) refresh = -refresh;
+            }
+        }
+        else {
+            refresh = atoi(refresh_str);
+            if(refresh < 0) refresh = -refresh;
+        }
+    }
+
+    if(!label) {
+        if(dimensions) {
+            const char *dim = buffer_tostring(dimensions);
+            if(*dim == '|') dim++;
+            label = dim;
+        }
+        else
+            label = st->name;
+    }
+    if(!units) {
+        if(options & RRDR_OPTION_PERCENTAGE)
+            units="%";
+        else
+            units = st->units;
+    }
+
+    debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
+            , w->id
+            , chart
+            , (dimensions)?buffer_tostring(dimensions):""
+            , after
+            , before
+            , points
+            , group
+            , options
+            );
+
+    time_t latest_timestamp = 0;
+    int value_is_null = 1;
+    calculated_number n = 0;
+    ret = 500;
+
+    // if the collected value is too old, don't calculate its value
+    if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
+        ret = rrd2value(st, w->response.data, &n, dimensions, points, after, before, group, options, &latest_timestamp, &value_is_null);
+
+    // if the value cannot be calculated, show empty badge
+    if(ret != 200) {
+        value_is_null = 1;
+        n = 0;
+        ret = 200;
+    }
+    else if(refresh > 0)
+        buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
+
+    // render the badge
+    buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
 
 cleanup:
-       if(dimensions)
-               buffer_free(dimensions);
-       return ret;
+    if(dimensions)
+        buffer_free(dimensions);
+    return ret;
 }
 
 // returns the HTTP code
 int web_client_api_request_v1_data(struct web_client *w, char *url)
 {
-       debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
+    debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
 
-       int ret = 400;
-       BUFFER *dimensions = NULL;
+    int ret = 400;
+    BUFFER *dimensions = NULL;
 
-       buffer_flush(w->response.data);
+    buffer_flush(w->response.data);
 
-       char    *google_version = "0.6",
-                       *google_reqId = "0",
-                       *google_sig = "0",
-                       *google_out = "json",
-                       *responseHandler = NULL,
-                       *outFileName = NULL;
+    char    *google_version = "0.6",
+            *google_reqId = "0",
+            *google_sig = "0",
+            *google_out = "json",
+            *responseHandler = NULL,
+            *outFileName = NULL;
 
-       time_t last_timestamp_in_data = 0, google_timestamp = 0;
+    time_t last_timestamp_in_data = 0, google_timestamp = 0;
 
-       char *chart = NULL
-                       , *before_str = NULL
-                       , *after_str = NULL
-                       , *points_str = NULL;
+    char *chart = NULL
+            , *before_str = NULL
+            , *after_str = NULL
+            , *points_str = NULL;
 
-       int group = GROUP_AVERAGE;
-       uint32_t format = DATASOURCE_JSON;
-       uint32_t options = 0x00000000;
+    int group = GROUP_AVERAGE;
+    uint32_t format = DATASOURCE_JSON;
+    uint32_t options = 0x00000000;
 
-       while(url) {
-               char *value = mystrsep(&url, "?&[]");
-               if(!value || !*value) continue;
+    while(url) {
+        char *value = mystrsep(&url, "?&[]");
+        if(!value || !*value) continue;
 
-               char *name = mystrsep(&value, "=");
-               if(!name || !*name) continue;
-               if(!value || !*value) continue;
+        char *name = mystrsep(&value, "=");
+        if(!name || !*name) continue;
+        if(!value || !*value) continue;
 
-               debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
+        debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
 
-               // name and value are now the parameters
-               // they are not null and not empty
+        // name and value are now the parameters
+        // they are not null and not empty
 
-               if(!strcmp(name, "chart")) chart = value;
-               else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
-                       if(!dimensions) dimensions = buffer_create(100);
+        if(!strcmp(name, "chart")) chart = value;
+        else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
+            if(!dimensions) dimensions = buffer_create(100);
             buffer_strcat(dimensions, "|");
             buffer_strcat(dimensions, value);
-               }
-               else if(!strcmp(name, "after")) after_str = value;
-               else if(!strcmp(name, "before")) before_str = value;
-               else if(!strcmp(name, "points")) points_str = value;
-               else if(!strcmp(name, "group")) {
-                       group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
-               }
-               else if(!strcmp(name, "format")) {
-                       format = web_client_api_request_v1_data_format(value);
-               }
-               else if(!strcmp(name, "options")) {
-                       options |= web_client_api_request_v1_data_options(value);
-               }
-               else if(!strcmp(name, "callback")) {
-                       responseHandler = value;
-               }
-               else if(!strcmp(name, "filename")) {
-                       outFileName = value;
-               }
-               else if(!strcmp(name, "tqx")) {
-                       // parse Google Visualization API options
-                       // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
-                       char *tqx_name, *tqx_value;
-
-                       while(value) {
-                               tqx_value = mystrsep(&value, ";");
-                               if(!tqx_value || !*tqx_value) continue;
-
-                               tqx_name = mystrsep(&tqx_value, ":");
-                               if(!tqx_name || !*tqx_name) continue;
-                               if(!tqx_value || !*tqx_value) continue;
-
-                               if(!strcmp(tqx_name, "version"))
-                                       google_version = tqx_value;
-                               else if(!strcmp(tqx_name, "reqId"))
-                                       google_reqId = tqx_value;
-                               else if(!strcmp(tqx_name, "sig")) {
-                                       google_sig = tqx_value;
-                                       google_timestamp = strtoul(google_sig, NULL, 0);
-                               }
-                               else if(!strcmp(tqx_name, "out")) {
-                                       google_out = tqx_value;
-                                       format = web_client_api_request_v1_data_google_format(google_out);
-                               }
-                               else if(!strcmp(tqx_name, "responseHandler"))
-                                       responseHandler = tqx_value;
-                               else if(!strcmp(tqx_name, "outFileName"))
-                                       outFileName = tqx_value;
-                       }
-               }
-       }
-
-       if(!chart || !*chart) {
-               buffer_sprintf(w->response.data, "No chart id is given at the request.");
-               goto cleanup;
-       }
-
-       RRDSET *st = rrdset_find(chart);
-       if(!st) st = rrdset_find_byname(chart);
-       if(!st) {
-               buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
-               ret = 404;
-               goto cleanup;
-       }
-
-       long long before = (before_str && *before_str)?atol(before_str):0;
-       long long after  = (after_str  && *after_str) ?atol(after_str):0;
-       int       points = (points_str && *points_str)?atoi(points_str):0;
-
-       debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
-                       , w->id
-                       , chart
-                       , (dimensions)?buffer_tostring(dimensions):""
-                       , after
-                       , before
-                       , points
-                       , group
-                       , format
-                       , options
-                       );
-
-       if(outFileName && *outFileName) {
-               buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
-               debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
-       }
-
-       if(format == DATASOURCE_DATATABLE_JSONP) {
-               if(responseHandler == NULL)
-                       responseHandler = "google.visualization.Query.setResponse";
-
-               debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
-                               w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
-                       );
-
-               buffer_sprintf(w->response.data,
-                       "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
-                       responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
-       }
-       else if(format == DATASOURCE_JSONP) {
-               if(responseHandler == NULL)
-                       responseHandler = "callback";
-
-               buffer_strcat(w->response.data, responseHandler);
-               buffer_strcat(w->response.data, "(");
-       }
-
-       ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
-
-       if(format == DATASOURCE_DATATABLE_JSONP) {
-               if(google_timestamp < last_timestamp_in_data)
-                       buffer_strcat(w->response.data, "});");
-
-               else {
-                       // the client already has the latest data
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data,
-                               "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
-                               responseHandler, google_version, google_reqId);
-               }
-       }
-       else if(format == DATASOURCE_JSONP)
-               buffer_strcat(w->response.data, ");");
+        }
+        else if(!strcmp(name, "after")) after_str = value;
+        else if(!strcmp(name, "before")) before_str = value;
+        else if(!strcmp(name, "points")) points_str = value;
+        else if(!strcmp(name, "group")) {
+            group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
+        }
+        else if(!strcmp(name, "format")) {
+            format = web_client_api_request_v1_data_format(value);
+        }
+        else if(!strcmp(name, "options")) {
+            options |= web_client_api_request_v1_data_options(value);
+        }
+        else if(!strcmp(name, "callback")) {
+            responseHandler = value;
+        }
+        else if(!strcmp(name, "filename")) {
+            outFileName = value;
+        }
+        else if(!strcmp(name, "tqx")) {
+            // parse Google Visualization API options
+            // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
+            char *tqx_name, *tqx_value;
+
+            while(value) {
+                tqx_value = mystrsep(&value, ";");
+                if(!tqx_value || !*tqx_value) continue;
+
+                tqx_name = mystrsep(&tqx_value, ":");
+                if(!tqx_name || !*tqx_name) continue;
+                if(!tqx_value || !*tqx_value) continue;
+
+                if(!strcmp(tqx_name, "version"))
+                    google_version = tqx_value;
+                else if(!strcmp(tqx_name, "reqId"))
+                    google_reqId = tqx_value;
+                else if(!strcmp(tqx_name, "sig")) {
+                    google_sig = tqx_value;
+                    google_timestamp = strtoul(google_sig, NULL, 0);
+                }
+                else if(!strcmp(tqx_name, "out")) {
+                    google_out = tqx_value;
+                    format = web_client_api_request_v1_data_google_format(google_out);
+                }
+                else if(!strcmp(tqx_name, "responseHandler"))
+                    responseHandler = tqx_value;
+                else if(!strcmp(tqx_name, "outFileName"))
+                    outFileName = tqx_value;
+            }
+        }
+    }
+
+    if(!chart || !*chart) {
+        buffer_sprintf(w->response.data, "No chart id is given at the request.");
+        goto cleanup;
+    }
+
+    RRDSET *st = rrdset_find(chart);
+    if(!st) st = rrdset_find_byname(chart);
+    if(!st) {
+        buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
+        ret = 404;
+        goto cleanup;
+    }
+
+    long long before = (before_str && *before_str)?atol(before_str):0;
+    long long after  = (after_str  && *after_str) ?atol(after_str):0;
+    int       points = (points_str && *points_str)?atoi(points_str):0;
+
+    debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
+            , w->id
+            , chart
+            , (dimensions)?buffer_tostring(dimensions):""
+            , after
+            , before
+            , points
+            , group
+            , format
+            , options
+            );
+
+    if(outFileName && *outFileName) {
+        buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
+        debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
+    }
+
+    if(format == DATASOURCE_DATATABLE_JSONP) {
+        if(responseHandler == NULL)
+            responseHandler = "google.visualization.Query.setResponse";
+
+        debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+                w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
+            );
+
+        buffer_sprintf(w->response.data,
+            "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+            responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+    }
+    else if(format == DATASOURCE_JSONP) {
+        if(responseHandler == NULL)
+            responseHandler = "callback";
+
+        buffer_strcat(w->response.data, responseHandler);
+        buffer_strcat(w->response.data, "(");
+    }
+
+    ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
+
+    if(format == DATASOURCE_DATATABLE_JSONP) {
+        if(google_timestamp < last_timestamp_in_data)
+            buffer_strcat(w->response.data, "});");
+
+        else {
+            // the client already has the latest data
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data,
+                "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+                responseHandler, google_version, google_reqId);
+        }
+    }
+    else if(format == DATASOURCE_JSONP)
+        buffer_strcat(w->response.data, ");");
 
 cleanup:
-       if(dimensions) buffer_free(dimensions);
-       return ret;
+    if(dimensions) buffer_free(dimensions);
+    return ret;
 }
 
 int web_client_api_request_v1_registry(struct web_client *w, char *url)
 {
-       static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
-                       hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
-                       hash_to = 0 /*, hash_redirects = 0 */;
-
-       if(unlikely(!hash_action)) {
-               hash_action = simple_hash("action");
-               hash_access = simple_hash("access");
-               hash_hello = simple_hash("hello");
-               hash_delete = simple_hash("delete");
-               hash_search = simple_hash("search");
-               hash_switch = simple_hash("switch");
-               hash_machine = simple_hash("machine");
-               hash_url = simple_hash("url");
-               hash_name = simple_hash("name");
-               hash_delete_url = simple_hash("delete_url");
-               hash_for = simple_hash("for");
-               hash_to = simple_hash("to");
+    static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
+            hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
+            hash_to = 0 /*, hash_redirects = 0 */;
+
+    if(unlikely(!hash_action)) {
+        hash_action = simple_hash("action");
+        hash_access = simple_hash("access");
+        hash_hello = simple_hash("hello");
+        hash_delete = simple_hash("delete");
+        hash_search = simple_hash("search");
+        hash_switch = simple_hash("switch");
+        hash_machine = simple_hash("machine");
+        hash_url = simple_hash("url");
+        hash_name = simple_hash("name");
+        hash_delete_url = simple_hash("delete_url");
+        hash_for = simple_hash("for");
+        hash_to = simple_hash("to");
 /*
-               hash_redirects = simple_hash("redirects");
+        hash_redirects = simple_hash("redirects");
 */
-       }
-
-       char person_guid[36 + 1] = "";
-
-       debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
-
-       // FIXME
-       // The browser may send multiple cookies with our id
-       
-       char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
-       if(cookie)
-               strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
-
-       char action = '\0';
-       char *machine_guid = NULL,
-                       *machine_url = NULL,
-                       *url_name = NULL,
-                       *search_machine_guid = NULL,
-                       *delete_url = NULL,
-                       *to_person_guid = NULL;
+    }
+
+    char person_guid[36 + 1] = "";
+
+    debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
+
+    // FIXME
+    // The browser may send multiple cookies with our id
+    
+    char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
+    if(cookie)
+        strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
+
+    char action = '\0';
+    char *machine_guid = NULL,
+            *machine_url = NULL,
+            *url_name = NULL,
+            *search_machine_guid = NULL,
+            *delete_url = NULL,
+            *to_person_guid = NULL;
 /*
-       int redirects = 0;
+    int redirects = 0;
 */
 
-       while(url) {
-               char *value = mystrsep(&url, "?&[]");
-               if (!value || !*value) continue;
+    while(url) {
+        char *value = mystrsep(&url, "?&[]");
+        if (!value || !*value) continue;
 
-               char *name = mystrsep(&value, "=");
-               if (!name || !*name) continue;
-               if (!value || !*value) continue;
+        char *name = mystrsep(&value, "=");
+        if (!name || !*name) continue;
+        if (!value || !*value) continue;
 
-               debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
+        debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
 
-               uint32_t hash = simple_hash(name);
+        uint32_t hash = simple_hash(name);
 
-               if(hash == hash_action && !strcmp(name, "action")) {
-                       uint32_t vhash = simple_hash(value);
+        if(hash == hash_action && !strcmp(name, "action")) {
+            uint32_t vhash = simple_hash(value);
 
-                       if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
-                       else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
-                       else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
-                       else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
-                       else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
+            if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
+            else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
+            else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
+            else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
+            else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
 #ifdef NETDATA_INTERNAL_CHECKS
             else error("unknown registry action '%s'", value);
 #endif /* NETDATA_INTERNAL_CHECKS */
-               }
+        }
 /*
-               else if(hash == hash_redirects && !strcmp(name, "redirects"))
-                       redirects = atoi(value);
+        else if(hash == hash_redirects && !strcmp(name, "redirects"))
+            redirects = atoi(value);
 */
-               else if(hash == hash_machine && !strcmp(name, "machine"))
-                       machine_guid = value;
-
-               else if(hash == hash_url && !strcmp(name, "url"))
-                       machine_url = value;
-
-               else if(action == 'A') {
-                       if(hash == hash_name && !strcmp(name, "name"))
-                               url_name = value;
-               }
-               else if(action == 'D') {
-                       if(hash == hash_delete_url && !strcmp(name, "delete_url"))
-                               delete_url = value;
-               }
-               else if(action == 'S') {
-                       if(hash == hash_for && !strcmp(name, "for"))
-                               search_machine_guid = value;
-               }
-               else if(action == 'W') {
-                       if(hash == hash_to && !strcmp(name, "to"))
-                               to_person_guid = value;
-               }
+        else if(hash == hash_machine && !strcmp(name, "machine"))
+            machine_guid = value;
+
+        else if(hash == hash_url && !strcmp(name, "url"))
+            machine_url = value;
+
+        else if(action == 'A') {
+            if(hash == hash_name && !strcmp(name, "name"))
+                url_name = value;
+        }
+        else if(action == 'D') {
+            if(hash == hash_delete_url && !strcmp(name, "delete_url"))
+                delete_url = value;
+        }
+        else if(action == 'S') {
+            if(hash == hash_for && !strcmp(name, "for"))
+                search_machine_guid = value;
+        }
+        else if(action == 'W') {
+            if(hash == hash_to && !strcmp(name, "to"))
+                to_person_guid = value;
+        }
 #ifdef NETDATA_INTERNAL_CHECKS
-               else error("unused registry URL parameter '%s' with value '%s'", name, value);
+        else error("unused registry URL parameter '%s' with value '%s'", name, value);
 #endif /* NETDATA_INTERNAL_CHECKS */
-       }
-
-       if(web_donotrack_comply && w->donottrack) {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
-               return 400;
-       }
-
-       if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
-                                          machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
-               return 400;
-       }
-       else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
-                                          machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
-               return 400;
-       }
-       else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
-                                          machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
-               return 400;
-       }
-       else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
-                                          machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
-               return 400;
-       }
-
-       switch(action) {
-               case 'A':
-                       w->tracking_required = 1;
-                       if(registry_verify_cookies_redirects() > 0 && (!cookie || !person_guid[0])) {
-                               buffer_flush(w->response.data);
-
-                               registry_set_cookie(w, "give-me-back-this-cookie-please");
-                               w->response.data->contenttype = CT_APPLICATION_JSON;
-                               buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry_to_announce());
-                               return 200;
+    }
+
+    if(web_donotrack_comply && w->donottrack) {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
+        return 400;
+    }
+
+    if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
+                       machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
+        return 400;
+    }
+    else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
+                       machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
+        return 400;
+    }
+    else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
+                       machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
+        return 400;
+    }
+    else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
+                       machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
+        return 400;
+    }
+
+    switch(action) {
+        case 'A':
+            w->tracking_required = 1;
+            if(registry_verify_cookies_redirects() > 0 && (!cookie || !person_guid[0])) {
+                buffer_flush(w->response.data);
+
+                registry_set_cookie(w, "give-me-back-this-cookie-please");
+                w->response.data->contenttype = CT_APPLICATION_JSON;
+                buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry_to_announce());
+                return 200;
 
 /*
  * it seems that web browsers are ignoring 307 (Moved Temporarily)
  * under certain conditions, when using CORS
  * so this is commented and we use application level redirects instead
  *
-                               redirects++;
-
-                               if(redirects > registry_verify_cookies_redirects()) {
-                                       buffer_flush(w->response.data);
-                                       buffer_sprintf(w->response.data, "Your browser does not support cookies");
-                                       return 400;
-                               }
-
-                               char *encoded_url = url_encode(machine_url);
-                               if(!encoded_url) {
-                                       error("%llu: Cannot URL encode string '%s'", w->id, machine_url);
-                                       return 500;
-                               }
-
-                               char *encoded_name = url_encode(url_name);
-                               if(!encoded_name) {
-                                       free(encoded_url);
-                                       error("%llu: Cannot URL encode string '%s'", w->id, url_name);
-                                       return 500;
-                               }
-
-                               char *encoded_guid = url_encode(machine_guid);
-                               if(!encoded_guid) {
-                                       free(encoded_url);
-                                       free(encoded_name);
-                                       error("%llu: Cannot URL encode string '%s'", w->id, machine_guid);
-                                       return 500;
-                               }
-
-                               buffer_sprintf(w->response.header, "Location: %s/api/v1/registry?action=access&machine=%s&name=%s&url=%s&redirects=%d\r\n",
-                                                          registry_to_announce(), encoded_guid, encoded_name, encoded_url, redirects);
-
-                               free(encoded_guid);
-                               free(encoded_name);
-                               free(encoded_url);
-                               return 307
+                redirects++;
+
+                if(redirects > registry_verify_cookies_redirects()) {
+                    buffer_flush(w->response.data);
+                    buffer_sprintf(w->response.data, "Your browser does not support cookies");
+                    return 400;
+                }
+
+                char *encoded_url = url_encode(machine_url);
+                if(!encoded_url) {
+                    error("%llu: Cannot URL encode string '%s'", w->id, machine_url);
+                    return 500;
+                }
+
+                char *encoded_name = url_encode(url_name);
+                if(!encoded_name) {
+                    free(encoded_url);
+                    error("%llu: Cannot URL encode string '%s'", w->id, url_name);
+                    return 500;
+                }
+
+                char *encoded_guid = url_encode(machine_guid);
+                if(!encoded_guid) {
+                    free(encoded_url);
+                    free(encoded_name);
+                    error("%llu: Cannot URL encode string '%s'", w->id, machine_guid);
+                    return 500;
+                }
+
+                buffer_sprintf(w->response.header, "Location: %s/api/v1/registry?action=access&machine=%s&name=%s&url=%s&redirects=%d\r\n",
+                               registry_to_announce(), encoded_guid, encoded_name, encoded_url, redirects);
+
+                free(encoded_guid);
+                free(encoded_name);
+                free(encoded_url);
+                return 307
 */
-                       }
-                       return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, time(NULL));
+            }
+            return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, time(NULL));
 
-               case 'D':
-                       w->tracking_required = 1;
-                       return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, time(NULL));
+        case 'D':
+            w->tracking_required = 1;
+            return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, time(NULL));
 
-               case 'S':
-                       w->tracking_required = 1;
-                       return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL));
+        case 'S':
+            w->tracking_required = 1;
+            return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL));
 
-               case 'W':
-                       w->tracking_required = 1;
-                       return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, time(NULL));
+        case 'W':
+            w->tracking_required = 1;
+            return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, time(NULL));
 
-               case 'H':
-                       return registry_request_hello_json(w);
+        case 'H':
+            return registry_request_hello_json(w);
 
-               default:
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
-                       return 400;
-       }
+        default:
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
+            return 400;
+    }
 
-       buffer_flush(w->response.data);
-       buffer_sprintf(w->response.data, "Invalid or no registry action.");
-       return 400;
+    buffer_flush(w->response.data);
+    buffer_sprintf(w->response.data, "Invalid or no registry action.");
+    return 400;
 }
 
 int web_client_api_request_v1(struct web_client *w, char *url) {
-       static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0;
-
-       if(unlikely(hash_data == 0)) {
-               hash_data = simple_hash("data");
-               hash_chart = simple_hash("chart");
-               hash_charts = simple_hash("charts");
-               hash_registry = simple_hash("registry");
-               hash_badge = simple_hash("badge.svg");
-       }
-
-       // get the command
-       char *tok = mystrsep(&url, "/?&");
-       if(tok && *tok) {
-               debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
-               uint32_t hash = simple_hash(tok);
-
-               if(hash == hash_data && !strcmp(tok, "data"))
-                       return web_client_api_request_v1_data(w, url);
-
-               else if(hash == hash_chart && !strcmp(tok, "chart"))
-                       return web_client_api_request_v1_chart(w, url);
-
-               else if(hash == hash_charts && !strcmp(tok, "charts"))
-                       return web_client_api_request_v1_charts(w, url);
-
-               else if(hash == hash_registry && !strcmp(tok, "registry"))
-                       return web_client_api_request_v1_registry(w, url);
-
-               else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
-                       return web_client_api_v1_badge(w, url);
-
-               else {
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
-                       return 404;
-               }
-       }
-       else {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "API v1 command?");
-               return 400;
-       }
+    static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0;
+
+    if(unlikely(hash_data == 0)) {
+        hash_data = simple_hash("data");
+        hash_chart = simple_hash("chart");
+        hash_charts = simple_hash("charts");
+        hash_registry = simple_hash("registry");
+        hash_badge = simple_hash("badge.svg");
+    }
+
+    // get the command
+    char *tok = mystrsep(&url, "/?&");
+    if(tok && *tok) {
+        debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
+        uint32_t hash = simple_hash(tok);
+
+        if(hash == hash_data && !strcmp(tok, "data"))
+            return web_client_api_request_v1_data(w, url);
+
+        else if(hash == hash_chart && !strcmp(tok, "chart"))
+            return web_client_api_request_v1_chart(w, url);
+
+        else if(hash == hash_charts && !strcmp(tok, "charts"))
+            return web_client_api_request_v1_charts(w, url);
+
+        else if(hash == hash_registry && !strcmp(tok, "registry"))
+            return web_client_api_request_v1_registry(w, url);
+
+        else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
+            return web_client_api_v1_badge(w, url);
+
+        else {
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
+            return 404;
+        }
+    }
+    else {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "API v1 command?");
+        return 400;
+    }
 }
 
 int web_client_api_request(struct web_client *w, char *url)
 {
-       // get the api version
-       char *tok = mystrsep(&url, "/?&");
-       if(tok && *tok) {
-               debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
-               if(strcmp(tok, "v1") == 0)
-                       return web_client_api_request_v1(w, url);
-               else {
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
-                       return 404;
-               }
-       }
-       else {
-               buffer_flush(w->response.data);
-               buffer_sprintf(w->response.data, "Which API version?");
-               return 400;
-       }
+    // get the api version
+    char *tok = mystrsep(&url, "/?&");
+    if(tok && *tok) {
+        debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
+        if(strcmp(tok, "v1") == 0)
+            return web_client_api_request_v1(w, url);
+        else {
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
+            return 404;
+        }
+    }
+    else {
+        buffer_flush(w->response.data);
+        buffer_sprintf(w->response.data, "Which API version?");
+        return 400;
+    }
 }
 
 int web_client_api_old_data_request(struct web_client *w, char *url, int datasource_type)
 {
-       RRDSET *st = NULL;
-
-       char *args = strchr(url, '?');
-       if(args) {
-               *args='\0';
-               args = &args[1];
-       }
-
-       // get the name of the data to show
-       char *tok = mystrsep(&url, "/");
-       if(!tok) tok = "";
-
-       // do we have such a data set?
-       if(*tok) {
-               debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-               st = rrdset_find_byname(tok);
-               if(!st) st = rrdset_find(tok);
-       }
-
-       if(!st) {
-               // we don't have it
-               // try to send a file with that name
-               buffer_flush(w->response.data);
-               return(mysendfile(w, tok));
-       }
-
-       // we have it
-       debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
-
-       // how many entries does the client want?
-       int lines = rrd_default_history_entries;
-       int group_count = 1;
-       time_t after = 0, before = 0;
-       int group_method = GROUP_AVERAGE;
-       int nonzero = 0;
-
-       if(url) {
-               // parse the lines required
-               tok = mystrsep(&url, "/");
-               if(tok) lines = atoi(tok);
-               if(lines < 1) lines = 1;
-       }
-       if(url) {
-               // parse the group count required
-               tok = mystrsep(&url, "/");
-               if(tok && *tok) group_count = atoi(tok);
-               if(group_count < 1) group_count = 1;
-               //if(group_count > save_history / 20) group_count = save_history / 20;
-       }
-       if(url) {
-               // parse the grouping method required
-               tok = mystrsep(&url, "/");
-               if(tok && *tok) {
-                       if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
-                       else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
-                       else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
-                       else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
-               }
-       }
-       if(url) {
-               // parse after time
-               tok = mystrsep(&url, "/");
-               if(tok && *tok) after = strtoul(tok, NULL, 10);
-               if(after < 0) after = 0;
-       }
-       if(url) {
-               // parse before time
-               tok = mystrsep(&url, "/");
-               if(tok && *tok) before = strtoul(tok, NULL, 10);
-               if(before < 0) before = 0;
-       }
-       if(url) {
-               // parse nonzero
-               tok = mystrsep(&url, "/");
-               if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
-       }
-
-       w->response.data->contenttype = CT_APPLICATION_JSON;
-       buffer_flush(w->response.data);
-
-       char *google_version = "0.6";
-       char *google_reqId = "0";
-       char *google_sig = "0";
-       char *google_out = "json";
-       char *google_responseHandler = "google.visualization.Query.setResponse";
-       char *google_outFileName = NULL;
-       time_t last_timestamp_in_data = 0;
-       if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
-
-               w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
-
-               while(args) {
-                       tok = mystrsep(&args, "&");
-                       if(tok && *tok) {
-                               char *name = mystrsep(&tok, "=");
-                               if(name && *name && strcmp(name, "tqx") == 0) {
-                                       char *key = mystrsep(&tok, ":");
-                                       char *value = mystrsep(&tok, ";");
-                                       if(key && value && *key && *value) {
-                                               if(strcmp(key, "version") == 0)
-                                                       google_version = value;
-
-                                               else if(strcmp(key, "reqId") == 0)
-                                                       google_reqId = value;
-
-                                               else if(strcmp(key, "sig") == 0)
-                                                       google_sig = value;
-
-                                               else if(strcmp(key, "out") == 0)
-                                                       google_out = value;
-
-                                               else if(strcmp(key, "responseHandler") == 0)
-                                                       google_responseHandler = value;
-
-                                               else if(strcmp(key, "outFileName") == 0)
-                                                       google_outFileName = value;
-                                       }
-                               }
-                       }
-               }
-
-               debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
-                       w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
-                       );
-
-               if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
-                       last_timestamp_in_data = strtoul(google_sig, NULL, 0);
-
-                       // check the client wants json
-                       if(strcmp(google_out, "json") != 0) {
-                               buffer_sprintf(w->response.data,
-                                       "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
-                                       google_responseHandler, google_version, google_reqId, google_out);
-                                       return 200;
-                       }
-               }
-       }
-
-       if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
-               buffer_sprintf(w->response.data,
-                       "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
-                       google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
-       }
-
-       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
-               w->id, st->name, st->id, lines, group_count, group_method, after, before);
-
-       time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
-
-       if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
-               if(timestamp_in_data > last_timestamp_in_data)
-                       buffer_strcat(w->response.data, "});");
-
-               else {
-                       // the client already has the latest data
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data,
-                               "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
-                               google_responseHandler, google_version, google_reqId);
-               }
-       }
-
-       return 200;
+    RRDSET *st = NULL;
+
+    char *args = strchr(url, '?');
+    if(args) {
+        *args='\0';
+        args = &args[1];
+    }
+
+    // get the name of the data to show
+    char *tok = mystrsep(&url, "/");
+    if(!tok) tok = "";
+
+    // do we have such a data set?
+    if(*tok) {
+        debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+        st = rrdset_find_byname(tok);
+        if(!st) st = rrdset_find(tok);
+    }
+
+    if(!st) {
+        // we don't have it
+        // try to send a file with that name
+        buffer_flush(w->response.data);
+        return(mysendfile(w, tok));
+    }
+
+    // we have it
+    debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
+
+    // how many entries does the client want?
+    int lines = rrd_default_history_entries;
+    int group_count = 1;
+    time_t after = 0, before = 0;
+    int group_method = GROUP_AVERAGE;
+    int nonzero = 0;
+
+    if(url) {
+        // parse the lines required
+        tok = mystrsep(&url, "/");
+        if(tok) lines = atoi(tok);
+        if(lines < 1) lines = 1;
+    }
+    if(url) {
+        // parse the group count required
+        tok = mystrsep(&url, "/");
+        if(tok && *tok) group_count = atoi(tok);
+        if(group_count < 1) group_count = 1;
+        //if(group_count > save_history / 20) group_count = save_history / 20;
+    }
+    if(url) {
+        // parse the grouping method required
+        tok = mystrsep(&url, "/");
+        if(tok && *tok) {
+            if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
+            else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
+            else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
+            else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
+        }
+    }
+    if(url) {
+        // parse after time
+        tok = mystrsep(&url, "/");
+        if(tok && *tok) after = strtoul(tok, NULL, 10);
+        if(after < 0) after = 0;
+    }
+    if(url) {
+        // parse before time
+        tok = mystrsep(&url, "/");
+        if(tok && *tok) before = strtoul(tok, NULL, 10);
+        if(before < 0) before = 0;
+    }
+    if(url) {
+        // parse nonzero
+        tok = mystrsep(&url, "/");
+        if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
+    }
+
+    w->response.data->contenttype = CT_APPLICATION_JSON;
+    buffer_flush(w->response.data);
+
+    char *google_version = "0.6";
+    char *google_reqId = "0";
+    char *google_sig = "0";
+    char *google_out = "json";
+    char *google_responseHandler = "google.visualization.Query.setResponse";
+    char *google_outFileName = NULL;
+    time_t last_timestamp_in_data = 0;
+    if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
+
+        w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
+
+        while(args) {
+            tok = mystrsep(&args, "&");
+            if(tok && *tok) {
+                char *name = mystrsep(&tok, "=");
+                if(name && *name && strcmp(name, "tqx") == 0) {
+                    char *key = mystrsep(&tok, ":");
+                    char *value = mystrsep(&tok, ";");
+                    if(key && value && *key && *value) {
+                        if(strcmp(key, "version") == 0)
+                            google_version = value;
+
+                        else if(strcmp(key, "reqId") == 0)
+                            google_reqId = value;
+
+                        else if(strcmp(key, "sig") == 0)
+                            google_sig = value;
+
+                        else if(strcmp(key, "out") == 0)
+                            google_out = value;
+
+                        else if(strcmp(key, "responseHandler") == 0)
+                            google_responseHandler = value;
+
+                        else if(strcmp(key, "outFileName") == 0)
+                            google_outFileName = value;
+                    }
+                }
+            }
+        }
+
+        debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
+            w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
+            );
+
+        if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+            last_timestamp_in_data = strtoul(google_sig, NULL, 0);
+
+            // check the client wants json
+            if(strcmp(google_out, "json") != 0) {
+                buffer_sprintf(w->response.data,
+                    "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
+                    google_responseHandler, google_version, google_reqId, google_out);
+                    return 200;
+            }
+        }
+    }
+
+    if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+        buffer_sprintf(w->response.data,
+            "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
+            google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
+    }
+
+    debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
+        w->id, st->name, st->id, lines, group_count, group_method, after, before);
+
+    time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
+
+    if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
+        if(timestamp_in_data > last_timestamp_in_data)
+            buffer_strcat(w->response.data, "});");
+
+        else {
+            // the client already has the latest data
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data,
+                "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
+                google_responseHandler, google_version, google_reqId);
+        }
+    }
+
+    return 200;
 }
 
 const char *web_content_type_to_string(uint8_t contenttype) {
-       switch(contenttype) {
-               case CT_TEXT_HTML:
-                       return "text/html; charset=utf-8";
+    switch(contenttype) {
+        case CT_TEXT_HTML:
+            return "text/html; charset=utf-8";
 
-               case CT_APPLICATION_XML:
-                       return "application/xml; charset=utf-8";
+        case CT_APPLICATION_XML:
+            return "application/xml; charset=utf-8";
 
-               case CT_APPLICATION_JSON:
-                       return "application/json; charset=utf-8";
+        case CT_APPLICATION_JSON:
+            return "application/json; charset=utf-8";
 
-               case CT_APPLICATION_X_JAVASCRIPT:
-                       return "application/x-javascript; charset=utf-8";
+        case CT_APPLICATION_X_JAVASCRIPT:
+            return "application/x-javascript; charset=utf-8";
 
-               case CT_TEXT_CSS:
-                       return "text/css; charset=utf-8";
+        case CT_TEXT_CSS:
+            return "text/css; charset=utf-8";
 
-               case CT_TEXT_XML:
-                       return "text/xml; charset=utf-8";
+        case CT_TEXT_XML:
+            return "text/xml; charset=utf-8";
 
-               case CT_TEXT_XSL:
-                       return "text/xsl; charset=utf-8";
+        case CT_TEXT_XSL:
+            return "text/xsl; charset=utf-8";
 
-               case CT_APPLICATION_OCTET_STREAM:
-                       return "application/octet-stream";
+        case CT_APPLICATION_OCTET_STREAM:
+            return "application/octet-stream";
 
-               case CT_IMAGE_SVG_XML:
-                       return "image/svg+xml";
+        case CT_IMAGE_SVG_XML:
+            return "image/svg+xml";
 
-               case CT_APPLICATION_X_FONT_TRUETYPE:
-                       return "application/x-font-truetype";
+        case CT_APPLICATION_X_FONT_TRUETYPE:
+            return "application/x-font-truetype";
 
-               case CT_APPLICATION_X_FONT_OPENTYPE:
-                       return "application/x-font-opentype";
+        case CT_APPLICATION_X_FONT_OPENTYPE:
+            return "application/x-font-opentype";
 
-               case CT_APPLICATION_FONT_WOFF:
-                       return "application/font-woff";
+        case CT_APPLICATION_FONT_WOFF:
+            return "application/font-woff";
 
-               case CT_APPLICATION_FONT_WOFF2:
-                       return "application/font-woff2";
+        case CT_APPLICATION_FONT_WOFF2:
+            return "application/font-woff2";
 
-               case CT_APPLICATION_VND_MS_FONTOBJ:
-                       return "application/vnd.ms-fontobject";
+        case CT_APPLICATION_VND_MS_FONTOBJ:
+            return "application/vnd.ms-fontobject";
 
-               case CT_IMAGE_PNG:
-                       return "image/png";
+        case CT_IMAGE_PNG:
+            return "image/png";
 
-               case CT_IMAGE_JPG:
-                       return "image/jpeg";
+        case CT_IMAGE_JPG:
+            return "image/jpeg";
 
-               case CT_IMAGE_GIF:
-                       return "image/gif";
+        case CT_IMAGE_GIF:
+            return "image/gif";
 
-               case CT_IMAGE_XICON:
-                       return "image/x-icon";
+        case CT_IMAGE_XICON:
+            return "image/x-icon";
 
-               case CT_IMAGE_BMP:
-                       return "image/bmp";
+        case CT_IMAGE_BMP:
+            return "image/bmp";
 
-               case CT_IMAGE_ICNS:
-                       return "image/icns";
+        case CT_IMAGE_ICNS:
+            return "image/icns";
 
-               default:
-               case CT_TEXT_PLAIN:
-                       return "text/plain; charset=utf-8";
-       }
+        default:
+        case CT_TEXT_PLAIN:
+            return "text/plain; charset=utf-8";
+    }
 }
 
 
 const char *web_response_code_to_string(int code) {
-       switch(code) {
-               case 200:
-                       return "OK";
+    switch(code) {
+        case 200:
+            return "OK";
 
-               case 307:
-                       return "Temporary Redirect";
+        case 307:
+            return "Temporary Redirect";
 
-               case 400:
-                       return "Bad Request";
+        case 400:
+            return "Bad Request";
 
-               case 403:
-                       return "Forbidden";
+        case 403:
+            return "Forbidden";
 
-               case 404:
-                       return "Not Found";
+        case 404:
+            return "Not Found";
 
-               case 412:
-                       return "Preconditions Failed";
+        case 412:
+            return "Preconditions Failed";
 
-               default:
-                       if(code >= 100 && code < 200)
-                               return "Informational";
+        default:
+            if(code >= 100 && code < 200)
+                return "Informational";
 
-                       if(code >= 200 && code < 300)
-                               return "Successful";
+            if(code >= 200 && code < 300)
+                return "Successful";
 
-                       if(code >= 300 && code < 400)
-                               return "Redirection";
+            if(code >= 300 && code < 400)
+                return "Redirection";
 
-                       if(code >= 400 && code < 500)
-                               return "Bad Request";
+            if(code >= 400 && code < 500)
+                return "Bad Request";
 
-                       if(code >= 500 && code < 600)
-                               return "Server Error";
+            if(code >= 500 && code < 600)
+                return "Server Error";
 
-                       return "Undefined Error";
-       }
+            return "Undefined Error";
+    }
 }
 
 static inline char *http_header_parse(struct web_client *w, char *s) {
-       static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0;
-
-       if(unlikely(!hash_origin)) {
-               hash_origin = simple_uhash("Origin");
-               hash_connection = simple_uhash("Connection");
-               hash_accept_encoding = simple_uhash("Accept-Encoding");
-               hash_donottrack = simple_uhash("DNT");
-       }
-
-       char *e = s;
-
-       // find the :
-       while(*e && *e != ':') e++;
-       if(!*e) return e;
-
-       // get the name
-       *e = '\0';
-
-       // find the value
-       char *v = e + 1, *ve;
-
-       // skip leading spaces from value
-       while(*v == ' ') v++;
-       ve = v;
-
-       // find the \r
-       while(*ve && *ve != '\r') ve++;
-       if(!*ve || ve[1] != '\n') {
-               *e = ':';
-               return ve;
-       }
-
-       // terminate the value
-       *ve = '\0';
-
-       // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
-       uint32_t hash = simple_uhash(s);
-
-       if(hash == hash_origin && !strcasecmp(s, "Origin"))
-               strncpyz(w->origin, v, ORIGIN_MAX);
-
-       else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
-               if(strcasestr(v, "keep-alive"))
-                       w->keepalive = 1;
-       }
-       else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
-               if(*v == '0') w->donottrack = 0;
-               else if(*v == '1') w->donottrack = 1;
-       }
+    static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0;
+
+    if(unlikely(!hash_origin)) {
+        hash_origin = simple_uhash("Origin");
+        hash_connection = simple_uhash("Connection");
+        hash_accept_encoding = simple_uhash("Accept-Encoding");
+        hash_donottrack = simple_uhash("DNT");
+    }
+
+    char *e = s;
+
+    // find the :
+    while(*e && *e != ':') e++;
+    if(!*e) return e;
+
+    // get the name
+    *e = '\0';
+
+    // find the value
+    char *v = e + 1, *ve;
+
+    // skip leading spaces from value
+    while(*v == ' ') v++;
+    ve = v;
+
+    // find the \r
+    while(*ve && *ve != '\r') ve++;
+    if(!*ve || ve[1] != '\n') {
+        *e = ':';
+        return ve;
+    }
+
+    // terminate the value
+    *ve = '\0';
+
+    // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
+    uint32_t hash = simple_uhash(s);
+
+    if(hash == hash_origin && !strcasecmp(s, "Origin"))
+        strncpyz(w->origin, v, ORIGIN_MAX);
+
+    else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
+        if(strcasestr(v, "keep-alive"))
+            w->keepalive = 1;
+    }
+    else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
+        if(*v == '0') w->donottrack = 0;
+        else if(*v == '1') w->donottrack = 1;
+    }
 #ifdef NETDATA_WITH_ZLIB
-       else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
-               if(web_enable_gzip) {
-                       if(strcasestr(v, "gzip"))
-                               web_client_enable_deflate(w, 1);
-                       //
-                       // does not seem to work
-                       // else if(strcasestr(v, "deflate"))
-                       //      web_client_enable_deflate(w, 0);
-               }
-       }
+    else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
+        if(web_enable_gzip) {
+            if(strcasestr(v, "gzip"))
+                web_client_enable_deflate(w, 1);
+            //
+            // does not seem to work
+            // else if(strcasestr(v, "deflate"))
+            //  web_client_enable_deflate(w, 0);
+        }
+    }
 #endif /* NETDATA_WITH_ZLIB */
 
-       *e = ':';
-       *ve = '\r';
-       return ve;
+    *e = ':';
+    *ve = '\r';
+    return ve;
 }
 
 // http_request_validate()
@@ -1584,760 +1584,760 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
 // < 0 : request is incomplete - wait for more data
 
 static inline int http_request_validate(struct web_client *w) {
-       char *s = w->response.data->buffer, *encoded_url = NULL;
-
-       // is is a valid request?
-       if(!strncmp(s, "GET ", 4)) {
-               encoded_url = s = &s[4];
-               w->mode = WEB_CLIENT_MODE_NORMAL;
-       }
-       else if(!strncmp(s, "OPTIONS ", 8)) {
-               encoded_url = s = &s[8];
-               w->mode = WEB_CLIENT_MODE_OPTIONS;
-       }
-       else {
-               w->wait_receive = 0;
-               return 1;
-       }
-
-       // find the SPACE + "HTTP/"
-       while(*s) {
-               // find the next space
-               while (*s && *s != ' ') s++;
-
-               // is it SPACE + "HTTP/" ?
-               if(*s && !strncmp(s, " HTTP/", 6)) break;
-               else s++;
-       }
-
-       // incomplete requests
-       if(unlikely(!*s)) {
-               w->wait_receive = 1;
-               return -2;
-       }
-
-       // we have the end of encoded_url - remember it
-       char *ue = s;
-
-       // make sure we have complete request
-       // complete requests contain: \r\n\r\n
-       while(*s) {
-               // find a line feed
-               while(*s && *s++ != '\r');
-
-               // did we reach the end?
-               if(unlikely(!*s)) break;
-
-               // is it \r\n ?
-               if(likely(*s++ == '\n')) {
-
-                       // is it again \r\n ? (header end)
-                       if(unlikely(*s == '\r' && s[1] == '\n')) {
-                               // a valid complete HTTP request found
-
-                               *ue = '\0';
-                               url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
-                               *ue = ' ';
-                               
-                               // copy the URL - we are going to overwrite parts of it
-                               // FIXME -- we should avoid it
-                               strncpyz(w->last_url, w->decoded_url, URL_MAX);
-
-                               w->wait_receive = 0;
-                               return 0;
-                       }
-
-                       // another header line
-                       s = http_header_parse(w, s);
-               }
-       }
-
-       // incomplete request
-       w->wait_receive = 1;
-       return -3;
+    char *s = w->response.data->buffer, *encoded_url = NULL;
+
+    // is is a valid request?
+    if(!strncmp(s, "GET ", 4)) {
+        encoded_url = s = &s[4];
+        w->mode = WEB_CLIENT_MODE_NORMAL;
+    }
+    else if(!strncmp(s, "OPTIONS ", 8)) {
+        encoded_url = s = &s[8];
+        w->mode = WEB_CLIENT_MODE_OPTIONS;
+    }
+    else {
+        w->wait_receive = 0;
+        return 1;
+    }
+
+    // find the SPACE + "HTTP/"
+    while(*s) {
+        // find the next space
+        while (*s && *s != ' ') s++;
+
+        // is it SPACE + "HTTP/" ?
+        if(*s && !strncmp(s, " HTTP/", 6)) break;
+        else s++;
+    }
+
+    // incomplete requests
+    if(unlikely(!*s)) {
+        w->wait_receive = 1;
+        return -2;
+    }
+
+    // we have the end of encoded_url - remember it
+    char *ue = s;
+
+    // make sure we have complete request
+    // complete requests contain: \r\n\r\n
+    while(*s) {
+        // find a line feed
+        while(*s && *s++ != '\r');
+
+        // did we reach the end?
+        if(unlikely(!*s)) break;
+
+        // is it \r\n ?
+        if(likely(*s++ == '\n')) {
+
+            // is it again \r\n ? (header end)
+            if(unlikely(*s == '\r' && s[1] == '\n')) {
+                // a valid complete HTTP request found
+
+                *ue = '\0';
+                url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
+                *ue = ' ';
+                
+                // copy the URL - we are going to overwrite parts of it
+                // FIXME -- we should avoid it
+                strncpyz(w->last_url, w->decoded_url, URL_MAX);
+
+                w->wait_receive = 0;
+                return 0;
+            }
+
+            // another header line
+            s = http_header_parse(w, s);
+        }
+    }
+
+    // incomplete request
+    w->wait_receive = 1;
+    return -3;
 }
 
 void web_client_process(struct web_client *w) {
-       static uint32_t hash_api = 0, hash_netdata_conf = 0, hash_data = 0, hash_datasource = 0, hash_graph = 0,
-                       hash_list = 0, hash_all_json = 0, hash_exit = 0, hash_debug = 0, hash_mirror = 0;
+    static uint32_t hash_api = 0, hash_netdata_conf = 0, hash_data = 0, hash_datasource = 0, hash_graph = 0,
+            hash_list = 0, hash_all_json = 0, hash_exit = 0, hash_debug = 0, hash_mirror = 0;
 
     // start timing us
     gettimeofday(&w->tv_in, NULL);
 
     if(unlikely(!hash_api)) {
-               hash_api = simple_hash("api");
-               hash_netdata_conf = simple_hash("netdata.conf");
-               hash_data = simple_hash(WEB_PATH_DATA);
-               hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
-               hash_graph = simple_hash(WEB_PATH_GRAPH);
-               hash_list = simple_hash("list");
-               hash_all_json = simple_hash("all.json");
-               hash_exit = simple_hash("exit");
-               hash_debug = simple_hash("debug");
-               hash_mirror = simple_hash("mirror");
-       }
-
-       int code = 500;
-       ssize_t bytes;
-
-       int what_to_do = http_request_validate(w);
-
-       // wait for more data
-       if(what_to_do < 0) {
-               if(w->response.data->len > TOO_BIG_REQUEST) {
-                       strcpy(w->last_url, "too big request");
-
-                       debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
-
-                       code = 400;
-                       buffer_flush(w->response.data);
-                       buffer_sprintf(w->response.data, "Received request is too big  (%zu bytes).\r\n", w->response.data->len);
-               }
-               else {
-                       // wait for more data
-                       return;
-               }
-       }
-       else if(what_to_do > 0) {
-               // strcpy(w->last_url, "not a valid request");
-
-               debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
-
-               code = 500;
-               buffer_flush(w->response.data);
-               buffer_strcat(w->response.data, "I don't understand you...\r\n");
-       }
-       else { // what_to_do == 0
-               if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
-                       code = 200;
-                       w->response.data->contenttype = CT_TEXT_PLAIN;
-                       buffer_flush(w->response.data);
-                       buffer_strcat(w->response.data, "OK");
-               }
-               else {
-                       char *url = w->decoded_url;
-                       char *tok = mystrsep(&url, "/?");
-                       if(tok && *tok) {
-                               uint32_t hash = simple_hash(tok);
-                               debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
-
-                               if(hash == hash_api && strcmp(tok, "api") == 0) {
-                                       // the client is requesting api access
-                                       code = web_client_api_request(w, url);
-                               }
-                               else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
-                                       code = 200;
-                                       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
-
-                                       w->response.data->contenttype = CT_TEXT_PLAIN;
-                                       buffer_flush(w->response.data);
-                                       generate_config(w->response.data, 0);
-                               }
-                               else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
-                                       // the client is requesting rrd data -- OLD API
-                                       code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
-                               }
-                               else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
-                                       // the client is requesting google datasource -- OLD API
-                                       code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
-                               }
-                               else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
-                                       // the client is requesting an rrd graph -- OLD API
-
-                                       // get the name of the data to show
-                                       tok = mystrsep(&url, "/?&");
-                                       if(tok && *tok) {
-                                               debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
-                                               // do we have such a data set?
-                                               RRDSET *st = rrdset_find_byname(tok);
-                                               if(!st) st = rrdset_find(tok);
-                                               if(!st) {
-                                                       // we don't have it
-                                                       // try to send a file with that name
-                                                       buffer_flush(w->response.data);
-                                                       code = mysendfile(w, tok);
-                                               }
-                                               else {
-                                                       code = 200;
-                                                       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
-                                                       w->response.data->contenttype = CT_APPLICATION_JSON;
-                                                       buffer_flush(w->response.data);
-                                                       rrd_stats_graph_json(st, url, w->response.data);
-                                               }
-                                       }
-                                       else {
-                                               code = 400;
-                                               buffer_flush(w->response.data);
-                                               buffer_strcat(w->response.data, "Graph name?\r\n");
-                                       }
-                               }
-                               else if(hash == hash_list && strcmp(tok, "list") == 0) {
-                                       // OLD API
-                                       code = 200;
-
-                                       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
-
-                                       buffer_flush(w->response.data);
-                                       RRDSET *st = localhost.rrdset_root;
-
-                                       for ( ; st ; st = st->next )
-                                               buffer_sprintf(w->response.data, "%s\n", st->name);
-                               }
-                               else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
-                                       // OLD API
-                                       code = 200;
-                                       debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
-
-                                       w->response.data->contenttype = CT_APPLICATION_JSON;
-                                       buffer_flush(w->response.data);
-                                       rrd_stats_all_json(w->response.data);
-                               }
+        hash_api = simple_hash("api");
+        hash_netdata_conf = simple_hash("netdata.conf");
+        hash_data = simple_hash(WEB_PATH_DATA);
+        hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
+        hash_graph = simple_hash(WEB_PATH_GRAPH);
+        hash_list = simple_hash("list");
+        hash_all_json = simple_hash("all.json");
+        hash_exit = simple_hash("exit");
+        hash_debug = simple_hash("debug");
+        hash_mirror = simple_hash("mirror");
+    }
+
+    int code = 500;
+    ssize_t bytes;
+
+    int what_to_do = http_request_validate(w);
+
+    // wait for more data
+    if(what_to_do < 0) {
+        if(w->response.data->len > TOO_BIG_REQUEST) {
+            strcpy(w->last_url, "too big request");
+
+            debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
+
+            code = 400;
+            buffer_flush(w->response.data);
+            buffer_sprintf(w->response.data, "Received request is too big  (%zu bytes).\r\n", w->response.data->len);
+        }
+        else {
+            // wait for more data
+            return;
+        }
+    }
+    else if(what_to_do > 0) {
+        // strcpy(w->last_url, "not a valid request");
+
+        debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
+
+        code = 500;
+        buffer_flush(w->response.data);
+        buffer_strcat(w->response.data, "I don't understand you...\r\n");
+    }
+    else { // what_to_do == 0
+        if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
+            code = 200;
+            w->response.data->contenttype = CT_TEXT_PLAIN;
+            buffer_flush(w->response.data);
+            buffer_strcat(w->response.data, "OK");
+        }
+        else {
+            char *url = w->decoded_url;
+            char *tok = mystrsep(&url, "/?");
+            if(tok && *tok) {
+                uint32_t hash = simple_hash(tok);
+                debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
+
+                if(hash == hash_api && strcmp(tok, "api") == 0) {
+                    // the client is requesting api access
+                    code = web_client_api_request(w, url);
+                }
+                else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
+                    code = 200;
+                    debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
+
+                    w->response.data->contenttype = CT_TEXT_PLAIN;
+                    buffer_flush(w->response.data);
+                    generate_config(w->response.data, 0);
+                }
+                else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
+                    // the client is requesting rrd data -- OLD API
+                    code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
+                }
+                else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
+                    // the client is requesting google datasource -- OLD API
+                    code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
+                }
+                else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
+                    // the client is requesting an rrd graph -- OLD API
+
+                    // get the name of the data to show
+                    tok = mystrsep(&url, "/?&");
+                    if(tok && *tok) {
+                        debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+                        // do we have such a data set?
+                        RRDSET *st = rrdset_find_byname(tok);
+                        if(!st) st = rrdset_find(tok);
+                        if(!st) {
+                            // we don't have it
+                            // try to send a file with that name
+                            buffer_flush(w->response.data);
+                            code = mysendfile(w, tok);
+                        }
+                        else {
+                            code = 200;
+                            debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
+                            w->response.data->contenttype = CT_APPLICATION_JSON;
+                            buffer_flush(w->response.data);
+                            rrd_stats_graph_json(st, url, w->response.data);
+                        }
+                    }
+                    else {
+                        code = 400;
+                        buffer_flush(w->response.data);
+                        buffer_strcat(w->response.data, "Graph name?\r\n");
+                    }
+                }
+                else if(hash == hash_list && strcmp(tok, "list") == 0) {
+                    // OLD API
+                    code = 200;
+
+                    debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
+
+                    buffer_flush(w->response.data);
+                    RRDSET *st = localhost.rrdset_root;
+
+                    for ( ; st ; st = st->next )
+                        buffer_sprintf(w->response.data, "%s\n", st->name);
+                }
+                else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
+                    // OLD API
+                    code = 200;
+                    debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
+
+                    w->response.data->contenttype = CT_APPLICATION_JSON;
+                    buffer_flush(w->response.data);
+                    rrd_stats_all_json(w->response.data);
+                }
 #ifdef NETDATA_INTERNAL_CHECKS
-                               else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
-                                       code = 200;
-                                       w->response.data->contenttype = CT_TEXT_PLAIN;
-                                       buffer_flush(w->response.data);
-
-                                       if(!netdata_exit)
-                                               buffer_strcat(w->response.data, "ok, will do...");
-                                       else
-                                               buffer_strcat(w->response.data, "I am doing it already");
-
-                                       error("web request to exit received.");
-                                       netdata_cleanup_and_exit(0);
-                                       netdata_exit = 1;
-                               }
-                               else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
-                                       buffer_flush(w->response.data);
-
-                                       // get the name of the data to show
-                                       tok = mystrsep(&url, "/?&");
-                                       if(tok && *tok) {
-                                               debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
-
-                                               // do we have such a data set?
-                                               RRDSET *st = rrdset_find_byname(tok);
-                                               if(!st) st = rrdset_find(tok);
-                                               if(!st) {
-                                                       code = 404;
-                                                       buffer_sprintf(w->response.data, "Chart %s is not found.\r\n", tok);
-                                                       debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
-                                               }
-                                               else {
-                                                       code = 200;
-                                                       debug_flags |= D_RRD_STATS;
-                                                       st->debug = !st->debug;
-                                                       buffer_sprintf(w->response.data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
-                                                       debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
-                                               }
-                                       }
-                                       else {
-                                               code = 500;
-                                               buffer_flush(w->response.data);
-                                               buffer_strcat(w->response.data, "debug which chart?\r\n");
-                                       }
-                               }
-                               else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
-                                       code = 200;
-
-                                       debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
-
-                                       // replace the zero bytes with spaces
-                                       buffer_char_replace(w->response.data, '\0', ' ');
-
-                                       // just leave the buffer as is
-                                       // it will be copied back to the client
-                               }
-#endif /* NETDATA_INTERNAL_CHECKS */
-                               else {
-                                       char filename[FILENAME_MAX+1];
-                                       url = filename;
-                                       strncpyz(filename, w->last_url, FILENAME_MAX);
-                                       tok = mystrsep(&url, "?");
-                                       buffer_flush(w->response.data);
-                                       code = mysendfile(w, (tok && *tok)?tok:"/");
-                               }
-                       }
-                       else {
-                               char filename[FILENAME_MAX+1];
-                               url = filename;
-                               strncpyz(filename, w->last_url, FILENAME_MAX);
-                               tok = mystrsep(&url, "?");
-                               buffer_flush(w->response.data);
-                               code = mysendfile(w, (tok && *tok)?tok:"/");
-                       }
-               }
-       }
-
-       gettimeofday(&w->tv_ready, NULL);
-       w->response.data->date = time(NULL);
-       w->response.sent = 0;
-       w->response.code = code;
-
-       // prepare the HTTP response header
-       debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
-
-       const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
-       const char *code_msg = web_response_code_to_string(code);
-
-       char date[32];
-       struct tm tmbuf, *tm = gmtime_r(&w->response.data->date, &tmbuf);
-       strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm);
-
-       buffer_sprintf(w->response.header_output,
-               "HTTP/1.1 %d %s\r\n"
-               "Connection: %s\r\n"
-               "Server: NetData Embedded HTTP Server\r\n"
-               "Access-Control-Allow-Origin: %s\r\n"
-               "Access-Control-Allow-Credentials: true\r\n"
-               "Content-Type: %s\r\n"
-               "Date: %s\r\n"
-               , code, code_msg
-               , w->keepalive?"keep-alive":"close"
-               , w->origin
-               , content_type_string
-               , date
-               );
-
-       if(w->cookie1[0] || w->cookie2[0]) {
-               if(w->cookie1[0]) {
-                       buffer_sprintf(w->response.header_output,
-                          "Set-Cookie: %s\r\n",
-                          w->cookie1);
-               }
-
-               if(w->cookie2[0]) {
-                       buffer_sprintf(w->response.header_output,
-                          "Set-Cookie: %s\r\n",
-                          w->cookie2);
-               }
-
-               if(web_donotrack_comply)
-                       buffer_sprintf(w->response.header_output,
-                          "Tk: T;cookies\r\n");
-       }
-       else {
-               if(web_donotrack_comply) {
-                       if(w->tracking_required)
-                               buffer_sprintf(w->response.header_output,
-                                  "Tk: T;cookies\r\n");
-                       else
-                               buffer_sprintf(w->response.header_output,
-                                  "Tk: N\r\n");
-               }
-       }
-
-       if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
-               buffer_strcat(w->response.header_output,
-                       "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
-                       "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie\r\n"
-                       "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
-                       );
-       }
-
-       if(buffer_strlen(w->response.header))
-               buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
-
-       if(w->mode == WEB_CLIENT_MODE_NORMAL && (w->response.data->options & WB_CONTENT_NO_CACHEABLE)) {
-               buffer_sprintf(w->response.header_output,
-                       "Expires: %s\r\n"
-                       "Cache-Control: no-cache\r\n"
-                       , date);
-       }
-       else if(w->mode != WEB_CLIENT_MODE_OPTIONS) {
-               char edate[32];
-               time_t et = w->response.data->date + (86400 * 14);
-               struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
-               strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
-
-               buffer_sprintf(w->response.header_output,
-                       "Expires: %s\r\n"
-                       "Cache-Control: public\r\n"
-                       , edate);
-       }
-
-       // if we know the content length, put it
-       if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
-               buffer_sprintf(w->response.header_output,
-                       "Content-Length: %zu\r\n"
-                       , w->response.data->len? w->response.data->len: w->response.rlen
-                       );
-       else if(!w->response.zoutput)
-               w->keepalive = 0;       // content-length is required for keep-alive
-
-       if(w->response.zoutput) {
-               buffer_strcat(w->response.header_output,
-                       "Content-Encoding: gzip\r\n"
-                       "Transfer-Encoding: chunked\r\n"
-                       );
-       }
-
-       buffer_strcat(w->response.header_output, "\r\n");
-
-       // sent the HTTP header
-       debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
-                       , w->id
-                       , buffer_strlen(w->response.header_output)
-                       , buffer_tostring(w->response.header_output)
-                       );
-
-       web_client_crock_socket(w);
-
-       bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
-       if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
-               if(bytes > 0)
-                       w->stats_sent_bytes += bytes;
-
-               debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
-                       , w->id
-                       , buffer_strlen(w->response.header_output)
-                       , bytes);
-
-               WEB_CLIENT_IS_DEAD(w);
-               return;
-       }
-       else 
-               w->stats_sent_bytes += bytes;
-
-       // enable sending immediately if we have data
-       if(w->response.data->len) w->wait_send = 1;
-       else w->wait_send = 0;
-
-       // pretty logging
-       switch(w->mode) {
-               case WEB_CLIENT_MODE_OPTIONS:
-                       debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
-                       break;
-
-               case WEB_CLIENT_MODE_NORMAL:
-                       debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
-                       break;
-
-               case WEB_CLIENT_MODE_FILECOPY:
-                       if(w->response.rlen) {
-                               debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
-                               w->wait_receive = 1;
-
-                               /*
-                               // utilize the kernel sendfile() for copying the file to the socket.
-                               // this block of code can be commented, without anything missing.
-                               // when it is commented, the program will copy the data using async I/O.
-                               {
-                                       long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
-                                       if(len != w->response.data->rbytes)
-                                               error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
-                                       else
-                                               web_client_reset(w);
-                               }
-                               */
-                       }
-                       else
-                               debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id);
-                       break;
-
-               default:
-                       fatal("%llu: Unknown client mode %d.", w->id, w->mode);
-                       break;
-       }
+                else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
+                    code = 200;
+                    w->response.data->contenttype = CT_TEXT_PLAIN;
+                    buffer_flush(w->response.data);
+
+                    if(!netdata_exit)
+                        buffer_strcat(w->response.data, "ok, will do...");
+                    else
+                        buffer_strcat(w->response.data, "I am doing it already");
+
+                    error("web request to exit received.");
+                    netdata_cleanup_and_exit(0);
+                    netdata_exit = 1;
+                }
+                else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
+                    buffer_flush(w->response.data);
+
+                    // get the name of the data to show
+                    tok = mystrsep(&url, "/?&");
+                    if(tok && *tok) {
+                        debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
+
+                        // do we have such a data set?
+                        RRDSET *st = rrdset_find_byname(tok);
+                        if(!st) st = rrdset_find(tok);
+                        if(!st) {
+                            code = 404;
+                            buffer_sprintf(w->response.data, "Chart %s is not found.\r\n", tok);
+                            debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
+                        }
+                        else {
+                            code = 200;
+                            debug_flags |= D_RRD_STATS;
+                            st->debug = !st->debug;
+                            buffer_sprintf(w->response.data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
+                            debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
+                        }
+                    }
+                    else {
+                        code = 500;
+                        buffer_flush(w->response.data);
+                        buffer_strcat(w->response.data, "debug which chart?\r\n");
+                    }
+                }
+                else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
+                    code = 200;
+
+                    debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
+
+                    // replace the zero bytes with spaces
+                    buffer_char_replace(w->response.data, '\0', ' ');
+
+                    // just leave the buffer as is
+                    // it will be copied back to the client
+                }
+#endif  /* NETDATA_INTERNAL_CHECKS */
+                else {
+                    char filename[FILENAME_MAX+1];
+                    url = filename;
+                    strncpyz(filename, w->last_url, FILENAME_MAX);
+                    tok = mystrsep(&url, "?");
+                    buffer_flush(w->response.data);
+                    code = mysendfile(w, (tok && *tok)?tok:"/");
+                }
+            }
+            else {
+                char filename[FILENAME_MAX+1];
+                url = filename;
+                strncpyz(filename, w->last_url, FILENAME_MAX);
+                tok = mystrsep(&url, "?");
+                buffer_flush(w->response.data);
+                code = mysendfile(w, (tok && *tok)?tok:"/");
+            }
+        }
+    }
+
+    gettimeofday(&w->tv_ready, NULL);
+    w->response.data->date = time(NULL);
+    w->response.sent = 0;
+    w->response.code = code;
+
+    // prepare the HTTP response header
+    debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
+
+    const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
+    const char *code_msg = web_response_code_to_string(code);
+
+    char date[32];
+    struct tm tmbuf, *tm = gmtime_r(&w->response.data->date, &tmbuf);
+    strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm);
+
+    buffer_sprintf(w->response.header_output,
+        "HTTP/1.1 %d %s\r\n"
+        "Connection: %s\r\n"
+        "Server: NetData Embedded HTTP Server\r\n"
+        "Access-Control-Allow-Origin: %s\r\n"
+        "Access-Control-Allow-Credentials: true\r\n"
+        "Content-Type: %s\r\n"
+        "Date: %s\r\n"
+        , code, code_msg
+        , w->keepalive?"keep-alive":"close"
+        , w->origin
+        , content_type_string
+        , date
+        );
+
+    if(w->cookie1[0] || w->cookie2[0]) {
+        if(w->cookie1[0]) {
+            buffer_sprintf(w->response.header_output,
+               "Set-Cookie: %s\r\n",
+               w->cookie1);
+        }
+
+        if(w->cookie2[0]) {
+            buffer_sprintf(w->response.header_output,
+               "Set-Cookie: %s\r\n",
+               w->cookie2);
+        }
+
+        if(web_donotrack_comply)
+            buffer_sprintf(w->response.header_output,
+               "Tk: T;cookies\r\n");
+    }
+    else {
+        if(web_donotrack_comply) {
+            if(w->tracking_required)
+                buffer_sprintf(w->response.header_output,
+                   "Tk: T;cookies\r\n");
+            else
+                buffer_sprintf(w->response.header_output,
+                   "Tk: N\r\n");
+        }
+    }
+
+    if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
+        buffer_strcat(w->response.header_output,
+            "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
+            "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie\r\n"
+            "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
+            );
+    }
+
+    if(buffer_strlen(w->response.header))
+        buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
+
+    if(w->mode == WEB_CLIENT_MODE_NORMAL && (w->response.data->options & WB_CONTENT_NO_CACHEABLE)) {
+        buffer_sprintf(w->response.header_output,
+            "Expires: %s\r\n"
+            "Cache-Control: no-cache\r\n"
+            , date);
+    }
+    else if(w->mode != WEB_CLIENT_MODE_OPTIONS) {
+        char edate[32];
+        time_t et = w->response.data->date + (86400 * 14);
+        struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
+        strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
+
+        buffer_sprintf(w->response.header_output,
+            "Expires: %s\r\n"
+            "Cache-Control: public\r\n"
+            , edate);
+    }
+
+    // if we know the content length, put it
+    if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
+        buffer_sprintf(w->response.header_output,
+            "Content-Length: %zu\r\n"
+            , w->response.data->len? w->response.data->len: w->response.rlen
+            );
+    else if(!w->response.zoutput)
+        w->keepalive = 0;   // content-length is required for keep-alive
+
+    if(w->response.zoutput) {
+        buffer_strcat(w->response.header_output,
+            "Content-Encoding: gzip\r\n"
+            "Transfer-Encoding: chunked\r\n"
+            );
+    }
+
+    buffer_strcat(w->response.header_output, "\r\n");
+
+    // sent the HTTP header
+    debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
+            , w->id
+            , buffer_strlen(w->response.header_output)
+            , buffer_tostring(w->response.header_output)
+            );
+
+    web_client_crock_socket(w);
+
+    bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
+    if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
+        if(bytes > 0)
+            w->stats_sent_bytes += bytes;
+
+        debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
+            , w->id
+            , buffer_strlen(w->response.header_output)
+            , bytes);
+
+        WEB_CLIENT_IS_DEAD(w);
+        return;
+    }
+    else 
+        w->stats_sent_bytes += bytes;
+
+    // enable sending immediately if we have data
+    if(w->response.data->len) w->wait_send = 1;
+    else w->wait_send = 0;
+
+    // pretty logging
+    switch(w->mode) {
+        case WEB_CLIENT_MODE_OPTIONS:
+            debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
+            break;
+
+        case WEB_CLIENT_MODE_NORMAL:
+            debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
+            break;
+
+        case WEB_CLIENT_MODE_FILECOPY:
+            if(w->response.rlen) {
+                debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
+                w->wait_receive = 1;
+
+                /*
+                // utilize the kernel sendfile() for copying the file to the socket.
+                // this block of code can be commented, without anything missing.
+                // when it is commented, the program will copy the data using async I/O.
+                {
+                    long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
+                    if(len != w->response.data->rbytes)
+                        error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
+                    else
+                        web_client_reset(w);
+                }
+                */
+            }
+            else
+                debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id);
+            break;
+
+        default:
+            fatal("%llu: Unknown client mode %d.", w->id, w->mode);
+            break;
+    }
 }
 
 ssize_t web_client_send_chunk_header(struct web_client *w, size_t len)
 {
-       debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
-       char buf[24];
-       sprintf(buf, "%zX\r\n", len);
-       
-       ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
-       if(bytes > 0) {
-               debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
-               w->stats_sent_bytes += bytes;
-       }
-
-       else if(bytes == 0) {
-               debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return bytes;
+    debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
+    char buf[24];
+    sprintf(buf, "%zX\r\n", len);
+    
+    ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
+    if(bytes > 0) {
+        debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
+        w->stats_sent_bytes += bytes;
+    }
+
+    else if(bytes == 0) {
+        debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return bytes;
 }
 
 ssize_t web_client_send_chunk_close(struct web_client *w)
 {
-       //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
-
-       ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
-       if(bytes > 0) {
-               debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
-               w->stats_sent_bytes += bytes;
-       }
-
-       else if(bytes == 0) {
-               debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return bytes;
+    //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
+
+    ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
+    if(bytes > 0) {
+        debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
+        w->stats_sent_bytes += bytes;
+    }
+
+    else if(bytes == 0) {
+        debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return bytes;
 }
 
 ssize_t web_client_send_chunk_finalize(struct web_client *w)
 {
-       //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
-
-       ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
-       if(bytes > 0) {
-               debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
-               w->stats_sent_bytes += bytes;
-       }
-
-       else if(bytes == 0) {
-               debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return bytes;
+    //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
+
+    ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
+    if(bytes > 0) {
+        debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
+        w->stats_sent_bytes += bytes;
+    }
+
+    else if(bytes == 0) {
+        debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return bytes;
 }
 
 #ifdef NETDATA_WITH_ZLIB
 ssize_t web_client_send_deflate(struct web_client *w)
 {
-       ssize_t len = 0, t = 0;
-
-       // when using compression,
-       // w->response.sent is the amount of bytes passed through compression
-
-       debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
-               w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
-
-       if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
-               // there is nothing to send
-
-               debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
-
-               // finalize the chunk
-               if(w->response.sent != 0) {
-                       t = web_client_send_chunk_finalize(w);
-                       if(t < 0) return t;
-               }
-
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
-                       // we have to wait, more data will come
-                       debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
-                       w->wait_send = 0;
-                       return t;
-               }
-
-               if(unlikely(!w->keepalive)) {
-                       debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
-                       WEB_CLIENT_IS_DEAD(w);
-                       return t;
-               }
-
-               // reset the client
-               web_client_reset(w);
-               debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id);
-               return t;
-       }
-
-       if(w->response.zhave == w->response.zsent) {
-               // compress more input data
-
-               // close the previous open chunk
-               if(w->response.sent != 0) {
-                       t = web_client_send_chunk_close(w);
-                       if(t < 0) return t;
-               }
-
-               debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in);
-
-               // give the compressor all the data not passed through the compressor yet
-               if(w->response.data->len > w->response.sent) {
-                       w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in];
-                       w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent);
-               }
-
-               // reset the compressor output buffer
-               w->response.zstream.next_out = w->response.zbuffer;
-               w->response.zstream.avail_out = ZLIB_CHUNK;
-
-               // ask for FINISH if we have all the input
-               int flush = Z_SYNC_FLUSH;
-               if(w->mode == WEB_CLIENT_MODE_NORMAL
-                       || (w->mode == WEB_CLIENT_MODE_FILECOPY && !w->wait_receive && w->response.data->len == w->response.rlen)) {
-                       flush = Z_FINISH;
-                       debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
-               }
-               else {
-                       debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id);
-               }
-
-               // compress
-               if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
-                       error("%llu: Compression failed. Closing down client.", w->id);
-                       web_client_reset(w);
-                       return(-1);
-               }
-
-               w->response.zhave = ZLIB_CHUNK - w->response.zstream.avail_out;
-               w->response.zsent = 0;
-
-               // keep track of the bytes passed through the compressor
-               w->response.sent = w->response.data->len;
-
-               debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave);
-
-               // open a new chunk
-               ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave);
-               if(t2 < 0) return t2;
-               t += t2;
-       }
-       
-       debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
-
-       len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
-       if(len > 0) {
-               w->stats_sent_bytes += len;
-               w->response.zsent += len;
-               len += t;
-               debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len);
-       }
-       else if(len == 0) {
-               debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).",
-                       w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
-
-               WEB_CLIENT_IS_DEAD(w);
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return(len);
+    ssize_t len = 0, t = 0;
+
+    // when using compression,
+    // w->response.sent is the amount of bytes passed through compression
+
+    debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
+        w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
+
+    if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
+        // there is nothing to send
+
+        debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
+
+        // finalize the chunk
+        if(w->response.sent != 0) {
+            t = web_client_send_chunk_finalize(w);
+            if(t < 0) return t;
+        }
+
+        if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
+            // we have to wait, more data will come
+            debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
+            w->wait_send = 0;
+            return t;
+        }
+
+        if(unlikely(!w->keepalive)) {
+            debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
+            WEB_CLIENT_IS_DEAD(w);
+            return t;
+        }
+
+        // reset the client
+        web_client_reset(w);
+        debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id);
+        return t;
+    }
+
+    if(w->response.zhave == w->response.zsent) {
+        // compress more input data
+
+        // close the previous open chunk
+        if(w->response.sent != 0) {
+            t = web_client_send_chunk_close(w);
+            if(t < 0) return t;
+        }
+
+        debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in);
+
+        // give the compressor all the data not passed through the compressor yet
+        if(w->response.data->len > w->response.sent) {
+            w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in];
+            w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent);
+        }
+
+        // reset the compressor output buffer
+        w->response.zstream.next_out = w->response.zbuffer;
+        w->response.zstream.avail_out = ZLIB_CHUNK;
+
+        // ask for FINISH if we have all the input
+        int flush = Z_SYNC_FLUSH;
+        if(w->mode == WEB_CLIENT_MODE_NORMAL
+            || (w->mode == WEB_CLIENT_MODE_FILECOPY && !w->wait_receive && w->response.data->len == w->response.rlen)) {
+            flush = Z_FINISH;
+            debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
+        }
+        else {
+            debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id);
+        }
+
+        // compress
+        if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
+            error("%llu: Compression failed. Closing down client.", w->id);
+            web_client_reset(w);
+            return(-1);
+        }
+
+        w->response.zhave = ZLIB_CHUNK - w->response.zstream.avail_out;
+        w->response.zsent = 0;
+
+        // keep track of the bytes passed through the compressor
+        w->response.sent = w->response.data->len;
+
+        debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave);
+
+        // open a new chunk
+        ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave);
+        if(t2 < 0) return t2;
+        t += t2;
+    }
+    
+    debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
+
+    len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
+    if(len > 0) {
+        w->stats_sent_bytes += len;
+        w->response.zsent += len;
+        len += t;
+        debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len);
+    }
+    else if(len == 0) {
+        debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).",
+            w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
+
+        WEB_CLIENT_IS_DEAD(w);
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return(len);
 }
 #endif // NETDATA_WITH_ZLIB
 
 ssize_t web_client_send(struct web_client *w) {
 #ifdef NETDATA_WITH_ZLIB
-       if(likely(w->response.zoutput)) return web_client_send_deflate(w);
+    if(likely(w->response.zoutput)) return web_client_send_deflate(w);
 #endif // NETDATA_WITH_ZLIB
 
-       ssize_t bytes;
-
-       if(unlikely(w->response.data->len - w->response.sent == 0)) {
-               // there is nothing to send
-
-               debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
-
-               // there can be two cases for this
-               // A. we have done everything
-               // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
-
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
-                       // we have to wait, more data will come
-                       debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
-                       w->wait_send = 0;
-                       return 0;
-               }
-
-               if(unlikely(!w->keepalive)) {
-                       debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
-                       WEB_CLIENT_IS_DEAD(w);
-                       return 0;
-               }
-
-               web_client_reset(w);
-               debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id);
-               return 0;
-       }
-
-       bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
-       if(likely(bytes > 0)) {
-               w->stats_sent_bytes += bytes;
-               w->response.sent += bytes;
-               debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes);
-       }
-       else if(likely(bytes == 0)) {
-               debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return(bytes);
+    ssize_t bytes;
+
+    if(unlikely(w->response.data->len - w->response.sent == 0)) {
+        // there is nothing to send
+
+        debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
+
+        // there can be two cases for this
+        // A. we have done everything
+        // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
+
+        if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
+            // we have to wait, more data will come
+            debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
+            w->wait_send = 0;
+            return 0;
+        }
+
+        if(unlikely(!w->keepalive)) {
+            debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
+            WEB_CLIENT_IS_DEAD(w);
+            return 0;
+        }
+
+        web_client_reset(w);
+        debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id);
+        return 0;
+    }
+
+    bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
+    if(likely(bytes > 0)) {
+        w->stats_sent_bytes += bytes;
+        w->response.sent += bytes;
+        debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes);
+    }
+    else if(likely(bytes == 0)) {
+        debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return(bytes);
 }
 
 ssize_t web_client_receive(struct web_client *w)
 {
-       // do we have any space for more data?
-       buffer_need_bytes(w->response.data, WEB_REQUEST_LENGTH);
-
-       ssize_t left = w->response.data->size - w->response.data->len;
-       ssize_t bytes;
-
-       if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
-               bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
-       else
-               bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
-
-       if(likely(bytes > 0)) {
-               if(w->mode != WEB_CLIENT_MODE_FILECOPY)
-                       w->stats_received_bytes += bytes;
-
-               size_t old = w->response.data->len;
-               w->response.data->len += bytes;
-               w->response.data->buffer[w->response.data->len] = '\0';
-
-               debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
-               debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
-
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
-                       w->wait_send = 1;
-
-                       if(w->response.rlen && w->response.data->len >= w->response.rlen)
-                               w->wait_receive = 0;
-               }
-       }
-       else if(likely(bytes == 0)) {
-               debug(D_WEB_CLIENT, "%llu: Out of input data.", w->id);
-
-               // if we cannot read, it means we have an error on input.
-               // if however, we are copying a file from ifd to ofd, we should not return an error.
-               // in this case, the error should be generated when the file has been sent to the client.
-
-               if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
-                       // we are copying data from ifd to ofd
-                       // let it finish copying...
-                       w->wait_receive = 0;
-
-                       debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
-                       if(w->ifd != w->ofd) close(w->ifd);
-                       w->ifd = w->ofd;
-               }
-               else {
-                       debug(D_WEB_CLIENT, "%llu: failed to receive data.", w->id);
-                       WEB_CLIENT_IS_DEAD(w);
-               }
-       }
-       else {
-               debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id);
-               WEB_CLIENT_IS_DEAD(w);
-       }
-
-       return(bytes);
+    // do we have any space for more data?
+    buffer_need_bytes(w->response.data, WEB_REQUEST_LENGTH);
+
+    ssize_t left = w->response.data->size - w->response.data->len;
+    ssize_t bytes;
+
+    if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
+        bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
+    else
+        bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
+
+    if(likely(bytes > 0)) {
+        if(w->mode != WEB_CLIENT_MODE_FILECOPY)
+            w->stats_received_bytes += bytes;
+
+        size_t old = w->response.data->len;
+        w->response.data->len += bytes;
+        w->response.data->buffer[w->response.data->len] = '\0';
+
+        debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
+        debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
+
+        if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
+            w->wait_send = 1;
+
+            if(w->response.rlen && w->response.data->len >= w->response.rlen)
+                w->wait_receive = 0;
+        }
+    }
+    else if(likely(bytes == 0)) {
+        debug(D_WEB_CLIENT, "%llu: Out of input data.", w->id);
+
+        // if we cannot read, it means we have an error on input.
+        // if however, we are copying a file from ifd to ofd, we should not return an error.
+        // in this case, the error should be generated when the file has been sent to the client.
+
+        if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
+            // we are copying data from ifd to ofd
+            // let it finish copying...
+            w->wait_receive = 0;
+
+            debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
+            if(w->ifd != w->ofd) close(w->ifd);
+            w->ifd = w->ofd;
+        }
+        else {
+            debug(D_WEB_CLIENT, "%llu: failed to receive data.", w->id);
+            WEB_CLIENT_IS_DEAD(w);
+        }
+    }
+    else {
+        debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id);
+        WEB_CLIENT_IS_DEAD(w);
+    }
+
+    return(bytes);
 }
 
 
@@ -2351,131 +2351,131 @@ ssize_t web_client_receive(struct web_client *w)
 
 void *web_client_main(void *ptr)
 {
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
-
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
-
-       struct web_client *w = ptr;
-       struct pollfd fds[2], *ifd, *ofd;
-       int retval, fdmax = 0, timeout;
-
-       log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
-
-       for(;;) {
-               if(unlikely(w->dead)) {
-                       debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
-                       break;
-               }
-               else if(unlikely(!w->wait_receive && !w->wait_send)) {
-                       debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id);
-                       break;
-               }
-
-               if(unlikely(w->ifd < 0 || w->ofd < 0)) {
-                       error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd", w->id, w->ifd, w->ofd);
-                       break;
-               }
-
-               if(w->ifd == w->ofd) {
-                       fds[0].fd = w->ifd;
-                       fds[0].events = 0;
-                       fds[0].revents = 0;
-
-                       if(w->wait_receive) fds[0].events |= POLLIN;
-                       if(w->wait_send)    fds[0].events |= POLLOUT;
-
-                       fds[1].fd = -1;
-                       fds[1].events = 0;
-                       fds[1].revents = 0;
-
-                       ifd = ofd = &fds[0];
-
-                       fdmax = 1;
-               }
-               else {
-                       fds[0].fd = w->ifd;
-                       fds[0].events = 0;
-                       fds[0].revents = 0;
-                       if(w->wait_receive) fds[0].events |= POLLIN;
-                       ifd = &fds[0];
-
-                       fds[1].fd = w->ofd;
-                       fds[1].events = 0;
-                       fds[1].revents = 0;
-                       if(w->wait_send)    fds[1].events |= POLLOUT;
-                       ofd = &fds[1];
-
-                       fdmax = 2;
-               }
-
-               debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
-               errno = 0;
-               timeout = web_client_timeout * 1000;
-               retval = poll(fds, fdmax, timeout);
-
-               if(unlikely(retval == -1)) {
-                       if(errno == EAGAIN || errno == EINTR) {
-                               debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
-                               continue;
-                       }
-
-                       debug(D_WEB_CLIENT, "%llu: LISTENER: poll() failed (input fd = %d, output fd = %d). Closing client.", w->id, w->ifd, w->ofd);
-                       break;
-               }
-               else if(unlikely(!retval)) {
-                       debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
-                       break;
-               }
-
-               int used = 0;
-               if(w->wait_send && ofd->revents & POLLOUT) {
-                       used++;
-                       if(web_client_send(w) < 0) {
-                               debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
-                               break;
-                       }
-               }
-
-               if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
-                       used++;
-                       if(web_client_receive(w) < 0) {
-                               debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id);
-                               break;
-                       }
-
-                       if(w->mode == WEB_CLIENT_MODE_NORMAL) {
-                               debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
-                               web_client_process(w);
-                       }
-               }
-
-               if(unlikely(!used)) {
-                       debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on socket.", w->id);
-                       break;
-               }
-       }
-
-       web_client_reset(w);
-
-       log_access("%llu: %s port %s disconnected from thread task id %d", w->id, w->client_ip, w->client_port, gettid());
-       debug(D_WEB_CLIENT, "%llu: done...", w->id);
-
-       // close the sockets/files now
-       // to free file descriptors
-       if(w->ifd == w->ofd) {
-               if(w->ifd != -1) close(w->ifd);
-       }
-       else {
-               if(w->ifd != -1) close(w->ifd);
-               if(w->ofd != -1) close(w->ofd);
-       }
-       w->ifd = -1;
-       w->ofd = -1;
-
-       w->obsolete = 1;
-
-       pthread_exit(NULL);
-       return NULL;
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
+
+    struct web_client *w = ptr;
+    struct pollfd fds[2], *ifd, *ofd;
+    int retval, fdmax = 0, timeout;
+
+    log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
+
+    for(;;) {
+        if(unlikely(w->dead)) {
+            debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
+            break;
+        }
+        else if(unlikely(!w->wait_receive && !w->wait_send)) {
+            debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id);
+            break;
+        }
+
+        if(unlikely(w->ifd < 0 || w->ofd < 0)) {
+            error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd", w->id, w->ifd, w->ofd);
+            break;
+        }
+
+        if(w->ifd == w->ofd) {
+            fds[0].fd = w->ifd;
+            fds[0].events = 0;
+            fds[0].revents = 0;
+
+            if(w->wait_receive) fds[0].events |= POLLIN;
+            if(w->wait_send)    fds[0].events |= POLLOUT;
+
+            fds[1].fd = -1;
+            fds[1].events = 0;
+            fds[1].revents = 0;
+
+            ifd = ofd = &fds[0];
+
+            fdmax = 1;
+        }
+        else {
+            fds[0].fd = w->ifd;
+            fds[0].events = 0;
+            fds[0].revents = 0;
+            if(w->wait_receive) fds[0].events |= POLLIN;
+            ifd = &fds[0];
+
+            fds[1].fd = w->ofd;
+            fds[1].events = 0;
+            fds[1].revents = 0;
+            if(w->wait_send)    fds[1].events |= POLLOUT;
+            ofd = &fds[1];
+
+            fdmax = 2;
+        }
+
+        debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
+        errno = 0;
+        timeout = web_client_timeout * 1000;
+        retval = poll(fds, fdmax, timeout);
+
+        if(unlikely(retval == -1)) {
+            if(errno == EAGAIN || errno == EINTR) {
+                debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
+                continue;
+            }
+
+            debug(D_WEB_CLIENT, "%llu: LISTENER: poll() failed (input fd = %d, output fd = %d). Closing client.", w->id, w->ifd, w->ofd);
+            break;
+        }
+        else if(unlikely(!retval)) {
+            debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
+            break;
+        }
+
+        int used = 0;
+        if(w->wait_send && ofd->revents & POLLOUT) {
+            used++;
+            if(web_client_send(w) < 0) {
+                debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
+                break;
+            }
+        }
+
+        if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
+            used++;
+            if(web_client_receive(w) < 0) {
+                debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id);
+                break;
+            }
+
+            if(w->mode == WEB_CLIENT_MODE_NORMAL) {
+                debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
+                web_client_process(w);
+            }
+        }
+
+        if(unlikely(!used)) {
+            debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on socket.", w->id);
+            break;
+        }
+    }
+
+    web_client_reset(w);
+
+    log_access("%llu: %s port %s disconnected from thread task id %d", w->id, w->client_ip, w->client_port, gettid());
+    debug(D_WEB_CLIENT, "%llu: done...", w->id);
+
+    // close the sockets/files now
+    // to free file descriptors
+    if(w->ifd == w->ofd) {
+        if(w->ifd != -1) close(w->ifd);
+    }
+    else {
+        if(w->ifd != -1) close(w->ifd);
+        if(w->ofd != -1) close(w->ofd);
+    }
+    w->ifd = -1;
+    w->ofd = -1;
+
+    w->obsolete = 1;
+
+    pthread_exit(NULL);
+    return NULL;
 }
index 8254a033744d1c2eea5f51ac2fc486c518899557..862acf031a816a8ee77db6890d6a4b21f0ebe3ce 100644 (file)
@@ -8,83 +8,83 @@ extern int web_client_timeout;
 extern int web_enable_gzip, web_gzip_level, web_gzip_strategy, web_donotrack_comply;
 #endif /* NETDATA_WITH_ZLIB */
 
-#define WEB_CLIENT_MODE_NORMAL         0
-#define WEB_CLIENT_MODE_FILECOPY       1
-#define WEB_CLIENT_MODE_OPTIONS                2
+#define WEB_CLIENT_MODE_NORMAL      0
+#define WEB_CLIENT_MODE_FILECOPY    1
+#define WEB_CLIENT_MODE_OPTIONS     2
 
 #define URL_MAX 8192
-#define ZLIB_CHUNK     16384
+#define ZLIB_CHUNK  16384
 #define HTTP_RESPONSE_HEADER_SIZE 4096
 #define COOKIE_MAX 1024
 #define ORIGIN_MAX 1024
 
 struct response {
-       BUFFER *header;                                 // our response header
-       BUFFER *header_output;                  // internal use
-       BUFFER *data;                                   // our response data buffer
+    BUFFER *header;                 // our response header
+    BUFFER *header_output;          // internal use
+    BUFFER *data;                   // our response data buffer
 
-       int code;                                               // the HTTP response code
+    int code;                       // the HTTP response code
 
-       size_t rlen;                                    // if non-zero, the excepted size of ifd (input of firecopy)
-       size_t sent;                                    // current data length sent to output
+    size_t rlen;                    // if non-zero, the excepted size of ifd (input of firecopy)
+    size_t sent;                    // current data length sent to output
 
-       int zoutput;                                    // if set to 1, web_client_send() will send compressed data
+    int zoutput;                    // if set to 1, web_client_send() will send compressed data
 #ifdef NETDATA_WITH_ZLIB
-       z_stream zstream;                               // zlib stream for sending compressed output to client
-       Bytef zbuffer[ZLIB_CHUNK];              // temporary buffer for storing compressed output
-       size_t zsent;                                   // the compressed bytes we have sent to the client
-       size_t zhave;                                   // the compressed bytes that we have received from zlib
-       int zinitialized:1;
+    z_stream zstream;               // zlib stream for sending compressed output to client
+    Bytef zbuffer[ZLIB_CHUNK];      // temporary buffer for storing compressed output
+    size_t zsent;                   // the compressed bytes we have sent to the client
+    size_t zhave;                   // the compressed bytes that we have received from zlib
+    int zinitialized:1;
 #endif /* NETDATA_WITH_ZLIB */
 
 };
 
 struct web_client {
-       unsigned long long id;
+    unsigned long long id;
 
-       uint8_t obsolete:1;                                     // if set to 1, the listener will remove this client
-                                                                               // after setting this to 1, you should not touch
-                                                                               // this web_client
+    uint8_t obsolete:1;                 // if set to 1, the listener will remove this client
+                                        // after setting this to 1, you should not touch
+                                        // this web_client
 
-       uint8_t dead:1;                                         // if set to 1, this client is dead
+    uint8_t dead:1;                     // if set to 1, this client is dead
 
-       uint8_t keepalive:1;                            // if set to 1, the web client will be re-used
+    uint8_t keepalive:1;                // if set to 1, the web client will be re-used
 
-       uint8_t mode:3;                                         // the operational mode of the client
+    uint8_t mode:3;                     // the operational mode of the client
 
-       uint8_t wait_receive:1;                         // 1 = we are waiting more input data
-       uint8_t wait_send:1;                            // 1 = we have data to send to the client
+    uint8_t wait_receive:1;             // 1 = we are waiting more input data
+    uint8_t wait_send:1;                // 1 = we have data to send to the client
 
-       uint8_t donottrack:1;                           // 1 = we should not set cookies on this client
-       uint8_t tracking_required:1;            // 1 = if the request requires cookies
+    uint8_t donottrack:1;               // 1 = we should not set cookies on this client
+    uint8_t tracking_required:1;        // 1 = if the request requires cookies
 
-       int tcp_cork;                                           // 1 = we have a cork on the socket
+    int tcp_cork;                       // 1 = we have a cork on the socket
 
-       int ifd;
-       int ofd;
+    int ifd;
+    int ofd;
 
-       char client_ip[NI_MAXHOST+1];
-       char client_port[NI_MAXSERV+1];
+    char client_ip[NI_MAXHOST+1];
+    char client_port[NI_MAXSERV+1];
 
-       char decoded_url[URL_MAX + 1];  // we decode the URL in this buffer
-       char last_url[URL_MAX+1];               // we keep a copy of the decoded URL here
+    char decoded_url[URL_MAX + 1];  // we decode the URL in this buffer
+    char last_url[URL_MAX+1];       // we keep a copy of the decoded URL here
 
-       struct timeval tv_in, tv_ready;
+    struct timeval tv_in, tv_ready;
 
-       char cookie1[COOKIE_MAX+1];
-       char cookie2[COOKIE_MAX+1];
-       char origin[ORIGIN_MAX+1];
+    char cookie1[COOKIE_MAX+1];
+    char cookie2[COOKIE_MAX+1];
+    char origin[ORIGIN_MAX+1];
 
-       struct sockaddr_storage clientaddr;
-       struct response response;
+    struct sockaddr_storage clientaddr;
+    struct response response;
 
-       size_t stats_received_bytes;
-       size_t stats_sent_bytes;
+    size_t stats_received_bytes;
+    size_t stats_sent_bytes;
 
-       pthread_t thread;                               // the thread servicing this client
+    pthread_t thread;               // the thread servicing this client
 
-       struct web_client *prev;
-       struct web_client *next;
+    struct web_client *prev;
+    struct web_client *next;
 };
 
 #define WEB_CLIENT_IS_DEAD(w) (w)->dead=1
index 4bd3f91edc9dd13281e52a9e6d338b020008ab52..cf3687f3e6031779d8b17769730df8ffa739b594 100644 (file)
@@ -10,75 +10,75 @@ int web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
 #ifdef NETDATA_INTERNAL_CHECKS
 static void log_allocations(void)
 {
-       static int mem = 0;
+    static int mem = 0;
 
-       struct mallinfo mi;
+    struct mallinfo mi;
 
-       mi = mallinfo();
-       if(mi.uordblks > mem) {
-               int clients = 0;
-               struct web_client *w;
-               for(w = web_clients; w ; w = w->next) clients++;
+    mi = mallinfo();
+    if(mi.uordblks > mem) {
+        int clients = 0;
+        struct web_client *w;
+        for(w = web_clients; w ; w = w->next) clients++;
 
-               info("Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
-               mem = mi.uordblks;
-       }
+        info("Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
+        mem = mi.uordblks;
+    }
 }
 #endif
 
 #ifndef HAVE_ACCEPT4
 int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
-       int fd = accept(sock, addr, addrlen);
-       int newflags = 0;
-
-       if (fd < 0) return fd;
-
-       if (flags & SOCK_NONBLOCK) {
-               newflags |= O_NONBLOCK;
-               flags &= ~SOCK_NONBLOCK;
-       }
-
-       if (flags & SOCK_CLOEXEC) {
-               newflags |= O_CLOEXEC;
-               flags &= ~SOCK_CLOEXEC;
-       }
-
-       if (flags) {
-               errno = -EINVAL;
-               return -1;
-       }
-
-       if (fcntl(fd, F_SETFL, newflags) < 0) {
-               int saved_errno = errno;
-               close(fd);
-               errno = saved_errno;
-               return -1;
-       }
-
-       return fd;
+    int fd = accept(sock, addr, addrlen);
+    int newflags = 0;
+
+    if (fd < 0) return fd;
+
+    if (flags & SOCK_NONBLOCK) {
+        newflags |= O_NONBLOCK;
+        flags &= ~SOCK_NONBLOCK;
+    }
+
+    if (flags & SOCK_CLOEXEC) {
+        newflags |= O_CLOEXEC;
+        flags &= ~SOCK_CLOEXEC;
+    }
+
+    if (flags) {
+        errno = -EINVAL;
+        return -1;
+    }
+
+    if (fcntl(fd, F_SETFL, newflags) < 0) {
+        int saved_errno = errno;
+        close(fd);
+        errno = saved_errno;
+        return -1;
+    }
+
+    return fd;
 }
 #endif
 
 int create_listen_socket4(const char *ip, int port, int listen_backlog) {
-       int sock;
-       int sockopt = 1;
+    int sock;
+    int sockopt = 1;
 
-       debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
+    debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
 
-       sock = socket(AF_INET, SOCK_STREAM, 0);
-       if(sock < 0) {
-               error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if(sock < 0) {
+        error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
-       /* avoid "address already in use" */
-       if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
-               error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
+    /* avoid "address already in use" */
+    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
+        error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
 
-       struct sockaddr_in name;
-       memset(&name, 0, sizeof(struct sockaddr_in));
-       name.sin_family = AF_INET;
-       name.sin_port = htons (port);
+    struct sockaddr_in name;
+    memset(&name, 0, sizeof(struct sockaddr_in));
+    name.sin_family = AF_INET;
+    name.sin_port = htons (port);
 
     int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
     if(ret != 1) {
@@ -87,34 +87,34 @@ int create_listen_socket4(const char *ip, int port, int listen_backlog) {
         return -1;
     }
 
-       if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
-               close(sock);
-               error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+        close(sock);
+        error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
-       if(listen(sock, listen_backlog) < 0) {
-               close(sock);
-               fatal("IPv4 listen() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    if(listen(sock, listen_backlog) < 0) {
+        close(sock);
+        fatal("IPv4 listen() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
-       debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
-       return sock;
+    debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
+    return sock;
 }
 
 int create_listen_socket6(const char *ip, int port, int listen_backlog) {
-       int sock = -1;
-       int sockopt = 1;
+    int sock = -1;
+    int sockopt = 1;
     int ipv6only = 1;
 
-       debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
+    debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
 
-       sock = socket(AF_INET6, SOCK_STREAM, 0);
-       if (sock < 0) {
-               error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    sock = socket(AF_INET6, SOCK_STREAM, 0);
+    if (sock < 0) {
+        error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
     /* avoid "address already in use" */
     if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
@@ -125,9 +125,9 @@ int create_listen_socket6(const char *ip, int port, int listen_backlog) {
         error("Cannot set IPV6_V6ONLY on ip '%s' port's %d.", ip, port);
 
     struct sockaddr_in6 name;
-       memset(&name, 0, sizeof(struct sockaddr_in6));
-       name.sin6_family = AF_INET6;
-       name.sin6_port = htons ((uint16_t) port);
+    memset(&name, 0, sizeof(struct sockaddr_in6));
+    name.sin6_family = AF_INET6;
+    name.sin6_port = htons ((uint16_t) port);
 
     int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
     if(ret != 1) {
@@ -136,22 +136,22 @@ int create_listen_socket6(const char *ip, int port, int listen_backlog) {
         return -1;
     }
 
-       name.sin6_scope_id = 0;
+    name.sin6_scope_id = 0;
 
-       if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
-               close(sock);
-               error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+        close(sock);
+        error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
-       if (listen(sock, listen_backlog) < 0) {
-               close(sock);
-               error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
-               return -1;
-       }
+    if (listen(sock, listen_backlog) < 0) {
+        close(sock);
+        error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
+        return -1;
+    }
 
-       debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
-       return sock;
+    debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
+    return sock;
 }
 
 static inline int add_listen_socket(int fd, const char *ip, int port) {
@@ -275,13 +275,13 @@ static inline int bind_to_one(const char *definition, int default_port, int list
         }
     }
 
-       freeaddrinfo(result);
+    freeaddrinfo(result);
 
     return added;
 }
 
 int create_listen_sockets(void) {
-       listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
+    listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
 
     if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to"))
         config_rename("global", "bind socket to IP", "bind to");
@@ -290,11 +290,11 @@ int create_listen_sockets(void) {
         config_rename("global", "port", "default port");
 
     listen_port = (int) config_get_number("global", "default port", LISTEN_PORT);
-       if(listen_port < 1 || listen_port > 65535) {
-               error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
+    if(listen_port < 1 || listen_port > 65535) {
+        error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
         listen_port = (int) config_set_number("global", "default port", LISTEN_PORT);
-       }
-       debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
+    }
+    debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
 
     char *s = config_get("global", "bind to", "*");
     while(*s) {
@@ -319,27 +319,27 @@ int create_listen_sockets(void) {
     if(!listen_fds_count)
         fatal("Cannot listen on any socket. Exiting...");
 
-       return (int)listen_fds_count;
+    return (int)listen_fds_count;
 }
 
 // --------------------------------------------------------------------------------------
 // the main socket listener
 
 static inline void cleanup_web_clients(void) {
-       struct web_client *w;
-
-       for (w = web_clients; w;) {
-               if (w->obsolete) {
-                       debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
-                       // pthread_cancel(w->thread);
-                       // pthread_join(w->thread, NULL);
-                       w = web_client_free(w);
+    struct web_client *w;
+
+    for (w = web_clients; w;) {
+        if (w->obsolete) {
+            debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
+            // pthread_cancel(w->thread);
+            // pthread_join(w->thread, NULL);
+            w = web_client_free(w);
 #ifdef NETDATA_INTERNAL_CHECKS
-                       log_allocations();
+            log_allocations();
 #endif
-               }
-               else w = w->next;
-       }
+        }
+        else w = w->next;
+    }
 }
 
 // 1. it accepts new incoming requests on our port
@@ -350,252 +350,252 @@ static inline void cleanup_web_clients(void) {
 #define CLEANUP_EVERY_EVENTS 100
 
 void *socket_listen_main_multi_threaded(void *ptr) {
-       (void)ptr;
+    (void)ptr;
 
-       web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
-       info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
+    web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
+    info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
 
-       struct web_client *w;
-       int retval, counter = 0;
+    struct web_client *w;
+    int retval, counter = 0;
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       if(!listen_fds_count)
-               fatal("LISTENER: No sockets to listen to.");
+    if(!listen_fds_count)
+        fatal("LISTENER: No sockets to listen to.");
 
-       struct pollfd *fds = callocz(sizeof(struct pollfd), listen_fds_count);
+    struct pollfd *fds = callocz(sizeof(struct pollfd), listen_fds_count);
 
-       size_t i;
-       for(i = 0; i < listen_fds_count ;i++) {
-               fds[i].fd = listen_fds[i];
-               fds[i].events = POLLIN;
-               fds[i].revents = 0;
+    size_t i;
+    for(i = 0; i < listen_fds_count ;i++) {
+        fds[i].fd = listen_fds[i];
+        fds[i].events = POLLIN;
+        fds[i].revents = 0;
 
         info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN");
     }
 
-       int timeout = 10 * 1000;
-
-       for(;;) {
-               // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
-               retval = poll(fds, listen_fds_count, timeout);
-
-               if(unlikely(retval == -1)) {
-                       error("LISTENER: poll() failed.");
-                       continue;
-               }
-               else if(unlikely(!retval)) {
-                       debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
-                       counter = 0;
-                       cleanup_web_clients();
-                       continue;
-               }
-
-               for(i = 0 ; i < listen_fds_count ; i++) {
-                       short int revents = fds[i].revents;
-
-                       // check for new incoming connections
-                       if(revents & POLLIN || revents & POLLPRI) {
-                               fds[i].revents = 0;
-
-                               w = web_client_create(fds[i].fd);
-                               if(unlikely(!w)) {
-                                       // no need for error log - web_client_create already logged the error
-                                       continue;
-                               }
-
-                               if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
-                                       error("%llu: failed to create new thread for web client.", w->id);
-                                       w->obsolete = 1;
-                               }
-                               else if(pthread_detach(w->thread) != 0) {
-                                       error("%llu: Cannot request detach of newly created web client thread.", w->id);
-                                       w->obsolete = 1;
-                               }
-                       }
-               }
-
-               // cleanup unused clients
-               counter++;
-               if(counter >= CLEANUP_EVERY_EVENTS) {
-                       counter = 0;
-                       cleanup_web_clients();
-               }
-       }
-
-       debug(D_WEB_CLIENT, "LISTENER: exit!");
+    int timeout = 10 * 1000;
+
+    for(;;) {
+        // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
+        retval = poll(fds, listen_fds_count, timeout);
+
+        if(unlikely(retval == -1)) {
+            error("LISTENER: poll() failed.");
+            continue;
+        }
+        else if(unlikely(!retval)) {
+            debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
+            counter = 0;
+            cleanup_web_clients();
+            continue;
+        }
+
+        for(i = 0 ; i < listen_fds_count ; i++) {
+            short int revents = fds[i].revents;
+
+            // check for new incoming connections
+            if(revents & POLLIN || revents & POLLPRI) {
+                fds[i].revents = 0;
+
+                w = web_client_create(fds[i].fd);
+                if(unlikely(!w)) {
+                    // no need for error log - web_client_create already logged the error
+                    continue;
+                }
+
+                if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
+                    error("%llu: failed to create new thread for web client.", w->id);
+                    w->obsolete = 1;
+                }
+                else if(pthread_detach(w->thread) != 0) {
+                    error("%llu: Cannot request detach of newly created web client thread.", w->id);
+                    w->obsolete = 1;
+                }
+            }
+        }
+
+        // cleanup unused clients
+        counter++;
+        if(counter >= CLEANUP_EVERY_EVENTS) {
+            counter = 0;
+            cleanup_web_clients();
+        }
+    }
+
+    debug(D_WEB_CLIENT, "LISTENER: exit!");
     close_listen_sockets();
 
-       return NULL;
+    return NULL;
 }
 
 struct web_client *single_threaded_clients[FD_SETSIZE];
 
 static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) {
-       if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
-               return 1;
+    if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
+        return 1;
 
-       if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
-               error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE);
-               return 1;
-       }
+    if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
+        error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE);
+        return 1;
+    }
 
-       FD_SET(w->ifd, efds);
-       if(unlikely(*max < w->ifd)) *max = w->ifd;
+    FD_SET(w->ifd, efds);
+    if(unlikely(*max < w->ifd)) *max = w->ifd;
 
-       if(unlikely(w->ifd != w->ofd)) {
-               if(*max < w->ofd) *max = w->ofd;
-               FD_SET(w->ofd, efds);
-       }
+    if(unlikely(w->ifd != w->ofd)) {
+        if(*max < w->ofd) *max = w->ofd;
+        FD_SET(w->ofd, efds);
+    }
 
-       if(w->wait_receive) FD_SET(w->ifd, ifds);
-       if(w->wait_send)    FD_SET(w->ofd, ofds);
+    if(w->wait_receive) FD_SET(w->ifd, ifds);
+    if(w->wait_send)    FD_SET(w->ofd, ofds);
 
-       single_threaded_clients[w->ifd] = w;
-       single_threaded_clients[w->ofd] = w;
+    single_threaded_clients[w->ifd] = w;
+    single_threaded_clients[w->ofd] = w;
 
-       return 0;
+    return 0;
 }
 
 static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) {
-       FD_CLR(w->ifd, efds);
-       if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
+    FD_CLR(w->ifd, efds);
+    if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
 
-       if(w->wait_receive) FD_CLR(w->ifd, ifds);
-       if(w->wait_send)    FD_CLR(w->ofd, ofds);
+    if(w->wait_receive) FD_CLR(w->ifd, ifds);
+    if(w->wait_send)    FD_CLR(w->ofd, ofds);
 
-       single_threaded_clients[w->ifd] = NULL;
-       single_threaded_clients[w->ofd] = NULL;
+    single_threaded_clients[w->ifd] = NULL;
+    single_threaded_clients[w->ofd] = NULL;
 
-       if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
-               return 1;
+    if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
+        return 1;
 
-       return 0;
+    return 0;
 }
 
 void *socket_listen_main_single_threaded(void *ptr) {
-       (void)ptr;
+    (void)ptr;
 
-       web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
+    web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
 
-       info("Single-threaded WEB SERVER thread created with task id %d", gettid());
+    info("Single-threaded WEB SERVER thread created with task id %d", gettid());
 
-       struct web_client *w;
-       int retval;
+    struct web_client *w;
+    int retval;
 
-       if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-               error("Cannot set pthread cancel type to DEFERRED.");
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
 
-       if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-               error("Cannot set pthread cancel state to ENABLE.");
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
 
-       if(!listen_fds_count)
-               fatal("LISTENER: no listen sockets available.");
+    if(!listen_fds_count)
+        fatal("LISTENER: no listen sockets available.");
 
     size_t i;
     for(i = 0; i < FD_SETSIZE ; i++)
-               single_threaded_clients[i] = NULL;
+        single_threaded_clients[i] = NULL;
 
-       fd_set ifds, ofds, efds, rifds, rofds, refds;
-       FD_ZERO (&ifds);
-       FD_ZERO (&ofds);
-       FD_ZERO (&efds);
-       int fdmax = 0;
+    fd_set ifds, ofds, efds, rifds, rofds, refds;
+    FD_ZERO (&ifds);
+    FD_ZERO (&ofds);
+    FD_ZERO (&efds);
+    int fdmax = 0;
 
-       for(i = 0; i < listen_fds_count ; i++) {
-               if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
-                       fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);
+    for(i = 0; i < listen_fds_count ; i++) {
+        if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
+            fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);
 
         info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN");
 
-               FD_SET(listen_fds[i], &ifds);
-               FD_SET(listen_fds[i], &efds);
-               if(fdmax < listen_fds[i])
+        FD_SET(listen_fds[i], &ifds);
+        FD_SET(listen_fds[i], &efds);
+        if(fdmax < listen_fds[i])
             fdmax = listen_fds[i];
-       }
-
-       for(;;) {
-               debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
-
-               struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
-               rifds = ifds;
-               rofds = ofds;
-               refds = efds;
-               retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
-
-               if(unlikely(retval == -1)) {
-                       error("LISTENER: select() failed.");
-                       continue;
-               }
-               else if(likely(retval)) {
-                       debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
-
-                       for(i = 0; i < listen_fds_count ; i++) {
-                               if (FD_ISSET(listen_fds[i], &rifds)) {
-                                       debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
-                                       w = web_client_create(listen_fds[i]);
-                                       if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
-                                               web_client_free(w);
-                                       }
-                               }
-                       }
-
-                       for(i = 0 ; i <= (size_t)fdmax ; i++) {
-                               if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
-                                       continue;
-
-                               w = single_threaded_clients[i];
-                               if(unlikely(!w))
-                                       continue;
-
-                               if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
-                                       web_client_free(w);
-                                       continue;
-                               }
-
-                               if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
-                                       web_client_free(w);
-                                       continue;
-                               }
-
-                               if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
-                                       if (unlikely(web_client_receive(w) < 0)) {
-                                               web_client_free(w);
-                                               continue;
-                                       }
-
-                                       if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
-                                               debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
-                                               web_client_process(w);
-                                       }
-                               }
-
-                               if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
-                                       if (unlikely(web_client_send(w) < 0)) {
-                                               debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
-                                               web_client_free(w);
-                                               continue;
-                                       }
-                               }
-
-                               if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
-                                       web_client_free(w);
-                               }
-                       }
-               }
-               else {
-                       debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
+    }
+
+    for(;;) {
+        debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
+
+        struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
+        rifds = ifds;
+        rofds = ofds;
+        refds = efds;
+        retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
+
+        if(unlikely(retval == -1)) {
+            error("LISTENER: select() failed.");
+            continue;
+        }
+        else if(likely(retval)) {
+            debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
+
+            for(i = 0; i < listen_fds_count ; i++) {
+                if (FD_ISSET(listen_fds[i], &rifds)) {
+                    debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
+                    w = web_client_create(listen_fds[i]);
+                    if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
+                        web_client_free(w);
+                    }
+                }
+            }
+
+            for(i = 0 ; i <= (size_t)fdmax ; i++) {
+                if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
+                    continue;
+
+                w = single_threaded_clients[i];
+                if(unlikely(!w))
+                    continue;
+
+                if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
+                    web_client_free(w);
+                    continue;
+                }
+
+                if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
+                    web_client_free(w);
+                    continue;
+                }
+
+                if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
+                    if (unlikely(web_client_receive(w) < 0)) {
+                        web_client_free(w);
+                        continue;
+                    }
+
+                    if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
+                        debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
+                        web_client_process(w);
+                    }
+                }
+
+                if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
+                    if (unlikely(web_client_send(w) < 0)) {
+                        debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
+                        web_client_free(w);
+                        continue;
+                    }
+                }
+
+                if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
+                    web_client_free(w);
+                }
+            }
+        }
+        else {
+            debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
 #ifdef NETDATA_INTERNAL_CHECKS
-                       log_allocations();
+            log_allocations();
 #endif
-               }
-       }
+        }
+    }
 
-       debug(D_WEB_CLIENT, "LISTENER: exit!");
+    debug(D_WEB_CLIENT, "LISTENER: exit!");
     close_listen_sockets();
-       return NULL;
+    return NULL;
 }
index cea97761d2ffade9998483e1814c5430c5a99e7c..93adc5b28a847f0f5c961f3a56cea86aaae17b70 100644 (file)
@@ -1,10 +1,10 @@
 #ifndef NETDATA_WEB_SERVER_H
 #define NETDATA_WEB_SERVER_H 1
 
-#define WEB_PATH_FILE                          "file"
-#define WEB_PATH_DATA                          "data"
-#define WEB_PATH_DATASOURCE                    "datasource"
-#define WEB_PATH_GRAPH                         "graph"
+#define WEB_PATH_FILE               "file"
+#define WEB_PATH_DATA               "data"
+#define WEB_PATH_DATASOURCE         "datasource"
+#define WEB_PATH_GRAPH              "graph"
 
 #define LISTEN_PORT 19999
 #define LISTEN_BACKLOG 100