summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Weller <lhw@ring0.de>2016-04-21 12:27:39 +0000
committerLennart Weller <lhw@ring0.de>2016-04-21 12:27:39 +0000
commitedff5c9db775e6e4318f3ad007df78ecae456190 (patch)
tree3677e5fcbccc776c77dd0451e5be4711068bff46 /src
parentAdd postrm and TODO, update service (diff)
parentImported Upstream version 1.1.0 (diff)
downloadnetdata-edff5c9db775e6e4318f3ad007df78ecae456190.tar.xz
netdata-edff5c9db775e6e4318f3ad007df78ecae456190.zip
Merge tag 'upstream/1.1.0'
Upstream version 1.1.0
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.in873
-rw-r--r--[-rwxr-xr-x]src/appconfig.c4
-rw-r--r--[-rwxr-xr-x]src/appconfig.h0
-rw-r--r--[-rwxr-xr-x]src/apps_plugin.c1640
-rw-r--r--[-rwxr-xr-x]src/avl.c31
-rw-r--r--[-rwxr-xr-x]src/avl.h8
-rw-r--r--[-rwxr-xr-x]src/common.c266
-rw-r--r--[-rwxr-xr-x]src/common.h12
-rw-r--r--[-rwxr-xr-x]src/daemon.c88
-rw-r--r--[-rwxr-xr-x]src/daemon.h5
-rw-r--r--[-rwxr-xr-x]src/dictionary.c0
-rw-r--r--[-rwxr-xr-x]src/dictionary.h0
-rw-r--r--[-rwxr-xr-x]src/global_statistics.c0
-rw-r--r--[-rwxr-xr-x]src/global_statistics.h0
-rw-r--r--[-rwxr-xr-x]src/log.c87
-rw-r--r--[-rwxr-xr-x]src/log.h6
-rw-r--r--[-rwxr-xr-x]src/main.c103
-rw-r--r--[-rwxr-xr-x]src/main.h0
-rw-r--r--[-rwxr-xr-x]src/plugin_checks.c0
-rw-r--r--[-rwxr-xr-x]src/plugin_checks.h0
-rw-r--r--[-rwxr-xr-x]src/plugin_idlejitter.c0
-rw-r--r--[-rwxr-xr-x]src/plugin_idlejitter.h0
-rw-r--r--src/plugin_nfacct.c9
-rw-r--r--[-rwxr-xr-x]src/plugin_nfacct.h0
-rw-r--r--[-rwxr-xr-x]src/plugin_proc.c20
-rw-r--r--[-rwxr-xr-x]src/plugin_proc.h2
-rw-r--r--[-rwxr-xr-x]src/plugin_tc.c23
-rw-r--r--[-rwxr-xr-x]src/plugin_tc.h0
-rw-r--r--[-rwxr-xr-x]src/plugins_d.c7
-rw-r--r--[-rwxr-xr-x]src/plugins_d.h0
-rw-r--r--[-rwxr-xr-x]src/popen.c0
-rw-r--r--[-rwxr-xr-x]src/popen.h0
-rw-r--r--[-rwxr-xr-x]src/proc_diskstats.c84
-rw-r--r--[-rwxr-xr-x]src/proc_interrupts.c25
-rw-r--r--[-rwxr-xr-x]src/proc_loadavg.c0
-rw-r--r--[-rwxr-xr-x]src/proc_meminfo.c0
-rw-r--r--[-rwxr-xr-x]src/proc_net_dev.c0
-rw-r--r--[-rwxr-xr-x]src/proc_net_ip_vs_stats.c0
-rw-r--r--[-rwxr-xr-x]src/proc_net_netstat.c34
-rw-r--r--[-rwxr-xr-x]src/proc_net_snmp.c2
-rw-r--r--src/proc_net_snmp6.c1067
-rw-r--r--[-rwxr-xr-x]src/proc_net_stat_conntrack.c27
-rw-r--r--src/proc_net_stat_synproxy.c138
-rw-r--r--[-rwxr-xr-x]src/proc_softirqs.c25
-rw-r--r--[-rwxr-xr-x]src/proc_stat.c6
-rw-r--r--[-rwxr-xr-x]src/proc_sys_kernel_random_entropy_avail.c0
-rw-r--r--[-rwxr-xr-x]src/proc_vmstat.c3
-rw-r--r--[-rwxr-xr-x]src/procfile.c127
-rw-r--r--[-rwxr-xr-x]src/procfile.h3
-rw-r--r--[-rwxr-xr-x]src/rrd.c3
-rw-r--r--[-rwxr-xr-x]src/rrd.h0
-rw-r--r--[-rwxr-xr-x]src/rrd2json.c2
-rw-r--r--[-rwxr-xr-x]src/rrd2json.h0
-rw-r--r--[-rwxr-xr-x]src/storage_number.c0
-rw-r--r--[-rwxr-xr-x]src/storage_number.h0
-rw-r--r--[-rwxr-xr-x]src/sys_kernel_mm_ksm.c0
-rw-r--r--[-rwxr-xr-x]src/unit_test.c0
-rw-r--r--[-rwxr-xr-x]src/unit_test.h0
-rw-r--r--[-rwxr-xr-x]src/url.c6
-rw-r--r--[-rwxr-xr-x]src/url.h0
-rw-r--r--[-rwxr-xr-x]src/web_buffer.c0
-rw-r--r--[-rwxr-xr-x]src/web_buffer.h0
-rw-r--r--[-rwxr-xr-x]src/web_client.c370
-rw-r--r--[-rwxr-xr-x]src/web_client.h1
-rw-r--r--[-rwxr-xr-x]src/web_server.c147
-rw-r--r--[-rwxr-xr-x]src/web_server.h4
67 files changed, 4386 insertions, 875 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0c51bb54b..a6808f424 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,7 @@ AM_CPPFLAGS = \
-DCONFIG_DIR="\"$(configdir)\"" \
-DLOG_DIR="\"$(logdir)\"" \
-DPLUGINS_DIR="\"$(pluginsdir)\"" \
+ -DRUN_DIR="\"$(localstatedir)/run/netdata\"" \
-DWEB_DIR="\"$(webdir)\"" \
$(NULL)
AM_CFLAGS = \
@@ -47,7 +48,9 @@ netdata_SOURCES = \
proc_net_netstat.c \
proc_net_rpc_nfsd.c \
proc_net_snmp.c \
+ proc_net_snmp6.c \
proc_net_stat_conntrack.c \
+ proc_net_stat_synproxy.c \
proc_stat.c \
proc_sys_kernel_random_entropy_avail.c \
proc_vmstat.c \
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 000000000..20aa81ef0
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,873 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = netdata$(EXEEXT)
+plugins_PROGRAMS = apps.plugin$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(dist_cache_DATA) $(dist_log_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)"
+PROGRAMS = $(plugins_PROGRAMS) $(sbin_PROGRAMS)
+am_apps_plugin_OBJECTS = apps_plugin.$(OBJEXT) avl.$(OBJEXT) \
+ common.$(OBJEXT) log.$(OBJEXT) procfile.$(OBJEXT)
+apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS)
+apps_plugin_LDADD = $(LDADD)
+am_netdata_OBJECTS = appconfig.$(OBJEXT) avl.$(OBJEXT) \
+ common.$(OBJEXT) daemon.$(OBJEXT) dictionary.$(OBJEXT) \
+ global_statistics.$(OBJEXT) log.$(OBJEXT) main.$(OBJEXT) \
+ plugin_checks.$(OBJEXT) plugin_idlejitter.$(OBJEXT) \
+ plugin_nfacct.$(OBJEXT) plugin_proc.$(OBJEXT) \
+ plugin_tc.$(OBJEXT) plugins_d.$(OBJEXT) popen.$(OBJEXT) \
+ proc_diskstats.$(OBJEXT) proc_interrupts.$(OBJEXT) \
+ proc_softirqs.$(OBJEXT) proc_loadavg.$(OBJEXT) \
+ proc_meminfo.$(OBJEXT) proc_net_dev.$(OBJEXT) \
+ proc_net_ip_vs_stats.$(OBJEXT) proc_net_netstat.$(OBJEXT) \
+ proc_net_rpc_nfsd.$(OBJEXT) proc_net_snmp.$(OBJEXT) \
+ proc_net_snmp6.$(OBJEXT) proc_net_stat_conntrack.$(OBJEXT) \
+ proc_net_stat_synproxy.$(OBJEXT) proc_stat.$(OBJEXT) \
+ proc_sys_kernel_random_entropy_avail.$(OBJEXT) \
+ proc_vmstat.$(OBJEXT) sys_kernel_mm_ksm.$(OBJEXT) \
+ procfile.$(OBJEXT) rrd.$(OBJEXT) rrd2json.$(OBJEXT) \
+ storage_number.$(OBJEXT) unit_test.$(OBJEXT) url.$(OBJEXT) \
+ web_buffer.$(OBJEXT) web_client.$(OBJEXT) web_server.$(OBJEXT)
+netdata_OBJECTS = $(am_netdata_OBJECTS)
+am__DEPENDENCIES_1 =
+netdata_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(apps_plugin_SOURCES) $(netdata_SOURCES)
+DIST_SOURCES = $(apps_plugin_SOURCES) $(netdata_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+DATA = $(dist_cache_DATA) $(dist_log_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_CFLAGS = @MATH_CFLAGS@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NFACCT_CFLAGS = @NFACCT_CFLAGS@
+NFACCT_LIBS = @NFACCT_LIBS@
+OBJEXT = @OBJEXT@
+OPTIONAL_MATH_CLFAGS = @OPTIONAL_MATH_CLFAGS@
+OPTIONAL_MATH_LIBS = @OPTIONAL_MATH_LIBS@
+OPTIONAL_NFACCT_CLFAGS = @OPTIONAL_NFACCT_CLFAGS@
+OPTIONAL_NFACCT_LIBS = @OPTIONAL_NFACCT_LIBS@
+OPTIONAL_ZLIB_CLFAGS = @OPTIONAL_ZLIB_CLFAGS@
+OPTIONAL_ZLIB_LIBS = @OPTIONAL_ZLIB_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_RPM_RELEASE = @PACKAGE_RPM_RELEASE@
+PACKAGE_RPM_VERSION = @PACKAGE_RPM_VERSION@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+chartsdir = @chartsdir@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nodedir = @nodedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pluginsdir = @pluginsdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+webdir = @webdir@
+
+#
+# Copyright (C) 2015 Alon Bar-Lev <alon.barlev@gmail.com>
+#
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+AM_CPPFLAGS = \
+ -DCACHE_DIR="\"$(cachedir)\"" \
+ -DCONFIG_DIR="\"$(configdir)\"" \
+ -DLOG_DIR="\"$(logdir)\"" \
+ -DPLUGINS_DIR="\"$(pluginsdir)\"" \
+ -DRUN_DIR="\"$(localstatedir)/run/netdata\"" \
+ -DWEB_DIR="\"$(webdir)\"" \
+ $(NULL)
+
+AM_CFLAGS = \
+ $(OPTIONAL_MATH_CFLAGS) \
+ $(OPTIONAL_NFACCT_CLFAGS) \
+ $(OPTIONAL_ZLIB_CFLAGS) \
+ $(NULL)
+
+dist_cache_DATA = .keep
+dist_log_DATA = .keep
+netdata_SOURCES = \
+ appconfig.c appconfig.h \
+ avl.c avl.h \
+ common.c common.h \
+ daemon.c daemon.h \
+ dictionary.c dictionary.h \
+ global_statistics.c global_statistics.h \
+ log.c log.h \
+ main.c main.h \
+ plugin_checks.c plugin_checks.h \
+ plugin_idlejitter.c plugin_idlejitter.h \
+ plugin_nfacct.c plugin_nfacct.h \
+ plugin_proc.c plugin_proc.h \
+ plugin_tc.c plugin_tc.h \
+ plugins_d.c plugins_d.h \
+ popen.c popen.h \
+ proc_diskstats.c \
+ proc_interrupts.c \
+ proc_softirqs.c \
+ proc_loadavg.c \
+ proc_meminfo.c \
+ proc_net_dev.c \
+ proc_net_ip_vs_stats.c \
+ proc_net_netstat.c \
+ proc_net_rpc_nfsd.c \
+ proc_net_snmp.c \
+ proc_net_snmp6.c \
+ proc_net_stat_conntrack.c \
+ proc_net_stat_synproxy.c \
+ proc_stat.c \
+ proc_sys_kernel_random_entropy_avail.c \
+ proc_vmstat.c \
+ sys_kernel_mm_ksm.c \
+ procfile.c procfile.h \
+ rrd.c rrd.h \
+ rrd2json.c rrd2json.h \
+ storage_number.c storage_number.h \
+ unit_test.c unit_test.h \
+ url.c url.h \
+ web_buffer.c web_buffer.h \
+ web_client.c web_client.h \
+ web_server.c web_server.h \
+ $(NULL)
+
+netdata_LDADD = \
+ $(OPTIONAL_MATH_LIBS) \
+ $(OPTIONAL_NFACCT_LIBS) \
+ $(OPTIONAL_ZLIB_LIBS) \
+ $(NULL)
+
+apps_plugin_SOURCES = \
+ apps_plugin.c \
+ avl.c avl.h \
+ common.c common.h \
+ log.c log.h \
+ procfile.c procfile.h \
+ $(NULL)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginsPROGRAMS: $(plugins_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pluginsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pluginsdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pluginsdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pluginsdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-pluginsPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugins_PROGRAMS)'; test -n "$(pluginsdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pluginsdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pluginsdir)" && rm -f $$files
+
+clean-pluginsPROGRAMS:
+ -test -z "$(plugins_PROGRAMS)" || rm -f $(plugins_PROGRAMS)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+apps.plugin$(EXEEXT): $(apps_plugin_OBJECTS) $(apps_plugin_DEPENDENCIES) $(EXTRA_apps_plugin_DEPENDENCIES)
+ @rm -f apps.plugin$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(apps_plugin_OBJECTS) $(apps_plugin_LDADD) $(LIBS)
+
+netdata$(EXEEXT): $(netdata_OBJECTS) $(netdata_DEPENDENCIES) $(EXTRA_netdata_DEPENDENCIES)
+ @rm -f netdata$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(netdata_OBJECTS) $(netdata_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/appconfig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apps_plugin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dictionary.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global_statistics.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_checks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_idlejitter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_nfacct.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_proc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_tc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugins_d.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/popen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_diskstats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_interrupts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_loadavg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_meminfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_dev.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_ip_vs_stats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_netstat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_rpc_nfsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp6.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_conntrack.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_synproxy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_softirqs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_stat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_sys_kernel_random_entropy_avail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_vmstat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/procfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrd2json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage_number.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_kernel_mm_ksm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_server.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+install-dist_cacheDATA: $(dist_cache_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_cache_DATA)'; test -n "$(cachedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(cachedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(cachedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cachedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(cachedir)" || exit $$?; \
+ done
+
+uninstall-dist_cacheDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_cache_DATA)'; test -n "$(cachedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(cachedir)'; $(am__uninstall_files_from_dir)
+install-dist_logDATA: $(dist_log_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_log_DATA)'; test -n "$(logdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(logdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(logdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(logdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(logdir)" || exit $$?; \
+ done
+
+uninstall-dist_logDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_log_DATA)'; test -n "$(logdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(logdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pluginsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(cachedir)" "$(DESTDIR)$(logdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-pluginsPROGRAMS clean-sbinPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_cacheDATA install-dist_logDATA \
+ install-pluginsPROGRAMS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_cacheDATA uninstall-dist_logDATA \
+ uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
+
+.MAKE: install-am install-data-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-pluginsPROGRAMS clean-sbinPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-data-hook install-dist_cacheDATA install-dist_logDATA \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-pluginsPROGRAMS \
+ install-ps install-ps-am install-sbinPROGRAMS install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-dist_cacheDATA uninstall-dist_logDATA \
+ uninstall-pluginsPROGRAMS uninstall-sbinPROGRAMS
+
+
+install-data-hook:
+ if [ `id -u` == 0 ]; then \
+ chown root '$(DESTDIR)$(pluginsdir)/apps.plugin' && \
+ chmod 4755 '$(DESTDIR)$(pluginsdir)/apps.plugin'; \
+ else \
+ echo; \
+ echo "ATTENTION"; \
+ echo; \
+ echo "setuid bit of $(pluginsdir)/apps.plugin must be set, please execute as root:"; \
+ echo "chown root '$(pluginsdir)/apps.plugin' && chmod 4755 '$(pluginsdir)/apps.plugin'"; \
+ echo; \
+ fi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/appconfig.c b/src/appconfig.c
index 49eca90f0..73b946508 100755..100644
--- a/src/appconfig.c
+++ b/src/appconfig.c
@@ -188,7 +188,7 @@ int load_config(char *filename, int overwrite_used)
if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
FILE *fp = fopen(filename, "r");
if(!fp) {
- error("Cannot open file '%s'", CONFIG_DIR "/" CONFIG_FILENAME);
+ error("Cannot open file '%s'", filename);
return 0;
}
@@ -216,7 +216,7 @@ int load_config(char *filename, int overwrite_used)
if(!co) {
// line outside a section
- error("Ignoring line %d ('%s'), it is outsize all sections.", line, s);
+ error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
continue;
}
diff --git a/src/appconfig.h b/src/appconfig.h
index 41d1e19bb..41d1e19bb 100755..100644
--- a/src/appconfig.h
+++ b/src/appconfig.h
diff --git a/src/apps_plugin.c b/src/apps_plugin.c
index 153687196..e8a6f43ae 100755..100644
--- a/src/apps_plugin.c
+++ b/src/apps_plugin.c
@@ -13,6 +13,7 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
+#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/stat.h>
@@ -27,13 +28,20 @@
#include <dirent.h>
#include <arpa/inet.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "avl.h"
+
#include "common.h"
#include "log.h"
-#include "avl.h"
#include "procfile.h"
+#include "../config.h"
-#define MAX_COMPARE_NAME 15
+#define MAX_COMPARE_NAME 100
#define MAX_NAME 100
+#define MAX_CMDLINE 1024
unsigned long long Hertz = 1;
@@ -43,11 +51,15 @@ int debug = 0;
int update_every = 1;
unsigned long long file_counter = 0;
+int proc_pid_cmdline_is_needed = 0;
char *host_prefix = "";
+char *config_dir = CONFIG_DIR;
+#ifdef NETDATA_INTERNAL_CHECKS
// ----------------------------------------------------------------------------
// memory debugger
+// do not use in production systems - it mis-aligns allocated memory
struct allocations {
size_t allocations;
@@ -197,23 +209,26 @@ char *strdup_debug(const char *file, int line, const char *function, const char
#endif
#define strdup(ptr) strdup_debug(__FILE__, __LINE__, __FUNCTION__, (ptr))
+#endif /* NETDATA_INTERNAL_CHECKS */
+
// ----------------------------------------------------------------------------
-// helper functions
+// system functions
+// to retrieve settings of the system
-procfile *ff = NULL;
+long get_system_cpus(void) {
+ procfile *ff = NULL;
-long get_processors(void) {
int processors = 0;
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) return 1;
ff = procfile_readall(ff);
if(!ff) {
- // procfile_close(ff);
+ procfile_close(ff);
return 1;
}
@@ -226,32 +241,33 @@ long get_processors(void) {
processors--;
if(processors < 1) processors = 1;
- // procfile_close(ff);
+ procfile_close(ff);
return processors;
}
-long get_pid_max(void) {
+long get_system_pid_max(void) {
+ procfile *ff = NULL;
long mpid = 32768;
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
if(!ff) return mpid;
ff = procfile_readall(ff);
if(!ff) {
- // procfile_close(ff);
+ procfile_close(ff);
return mpid;
}
mpid = atol(procfile_lineword(ff, 0, 0));
if(!mpid) mpid = 32768;
- // procfile_close(ff);
+ procfile_close(ff);
return mpid;
}
-unsigned long long get_hertz(void)
+unsigned long long get_system_hertz(void)
{
unsigned long long myhz = 1;
@@ -263,10 +279,10 @@ unsigned long long get_hertz(void)
#ifdef HZ
myhz = HZ; /* <asm/param.h> */
-#else
+#else /* HZ */
/* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
-#endif
+#endif /* HZ */
error("Unknown HZ value. Assuming %llu.", myhz);
return myhz;
@@ -275,13 +291,21 @@ unsigned long long get_hertz(void)
// ----------------------------------------------------------------------------
// target
-// target is the point to aggregate a process tree values
+// 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;
@@ -341,143 +365,248 @@ struct target {
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 *target; // the one that will be reported to netdata
struct target *next;
-} *target_root = NULL, *default_target = NULL;
+};
-long targets = 0;
-// find or create a target
-// there are targets that are just agregated to other target (the second argument)
-struct target *get_target(const char *id, struct target *target)
+// ----------------------------------------------------------------------------
+// apps_groups.conf
+// aggregate all processes in groups, to have a limited number of dimensions
+
+struct target *apps_groups_root_target = NULL;
+struct target *apps_groups_default_target = NULL;
+long apps_groups_targets = 0;
+
+struct target *users_root_target = NULL;
+struct target *groups_root_target = NULL;
+
+struct target *get_users_target(uid_t uid)
{
- const char *nid = id;
- if(nid[0] == '-') nid++;
+ struct target *w;
+ for(w = users_root_target ; w ; w = w->next)
+ if(w->uid == uid) return w;
+
+ w = calloc(sizeof(struct target), 1);
+ if(unlikely(!w)) {
+ error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
+ return NULL;
+ }
+
+ snprintf(w->compare, MAX_COMPARE_NAME, "%d", uid);
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
+
+ snprintf(w->id, MAX_NAME, "%d", uid);
+ w->idhash = simple_hash(w->id);
+
+ struct passwd *pw = getpwuid(uid);
+ if(!pw)
+ snprintf(w->name, MAX_NAME, "%d", uid);
+ else
+ snprintf(w->name, MAX_NAME, "%s", pw->pw_name);
+
+ netdata_fix_id(w->name);
+
+ w->uid = uid;
+
+ w->next = users_root_target;
+ users_root_target = w;
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: added uid %d ('%s') target\n", w->uid, w->name);
+
+ return w;
+}
+
+struct target *get_groups_target(gid_t gid)
+{
struct target *w;
- for(w = target_root ; w ; w = w->next)
- if(strncmp(nid, w->id, MAX_NAME) == 0) return w;
+ for(w = groups_root_target ; w ; w = w->next)
+ if(w->gid == gid) return w;
w = calloc(sizeof(struct target), 1);
- if(!w) {
+ if(unlikely(!w)) {
error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
return NULL;
}
- strncpy(w->id, nid, MAX_NAME);
- strncpy(w->name, nid, MAX_NAME);
- strncpy(w->compare, nid, MAX_COMPARE_NAME);
- if(id[0] == '-') w->hidden = 1;
+ snprintf(w->compare, MAX_COMPARE_NAME, "%d", gid);
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
- w->target = target;
+ snprintf(w->id, MAX_NAME, "%d", gid);
+ w->idhash = simple_hash(w->id);
- w->next = target_root;
- target_root = w;
+ struct group *gr = getgrgid(gid);
+ if(!gr)
+ snprintf(w->name, MAX_NAME, "%d", gid);
+ else
+ snprintf(w->name, MAX_NAME, "%s", gr->gr_name);
- if(debug) fprintf(stderr, "apps.plugin: adding hook for process '%s', compare '%s' on target '%s'\n", w->id, w->compare, w->target?w->target->id:"");
+ netdata_fix_id(w->name);
+
+ w->gid = gid;
+
+ w->next = groups_root_target;
+ groups_root_target = w;
+
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: added gid %d ('%s') target\n", w->gid, w->name);
return w;
}
-// read the process groups file
-int read_process_groups(const char *name)
+// 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)
{
- char buffer[4096+1];
- char filename[FILENAME_MAX + 1];
+ int tdebug = 0, thidden = 0, ends_with = 0;
+ const char *nid = id;
- snprintf(filename, FILENAME_MAX, "%s/apps_%s.conf", CONFIG_DIR, name);
+ 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);
- if(debug) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
- FILE *fp = fopen(filename, "r");
- if(!fp) {
- error("Cannot open file '%s'", filename);
- return 1;
+ struct target *w;
+ for(w = apps_groups_root_target ; w ; w = w->next) {
+ if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
+ return w;
}
- long line = 0;
- while(fgets(buffer, 4096, fp) != NULL) {
- int whidden = 0, wdebug = 0;
- line++;
+ w = calloc(sizeof(struct target), 1);
+ if(unlikely(!w)) {
+ error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
+ return NULL;
+ }
- // if(debug) fprintf(stderr, "apps.plugin: \tread %s\n", buffer);
+ strncpy(w->id, nid, MAX_NAME);
+ w->idhash = simple_hash(w->id);
+
+ strncpy(w->name, nid, MAX_NAME);
- char *s = buffer, *t, *p;
- s = trim(s);
- if(!s || !*s || *s == '#') continue;
+ strncpy(w->compare, nid, MAX_COMPARE_NAME);
+ int len = strlen(w->compare);
+ if(w->compare[len - 1] == '*') {
+ w->compare[len - 1] = '\0';
+ w->starts_with = 1;
+ }
+ w->ends_with = ends_with;
- if(debug) fprintf(stderr, "apps.plugin: \tread %s\n", s);
+ if(w->starts_with && w->ends_with)
+ proc_pid_cmdline_is_needed = 1;
- // the target name
- t = strsep(&s, ":");
- if(t) t = trim(t);
- if(!t || !*t) continue;
+ w->comparehash = simple_hash(w->compare);
+ w->comparelen = strlen(w->compare);
- while(t[0]) {
- int stop = 1;
+ w->hidden = thidden;
+ w->debug = tdebug;
+ w->target = target;
- switch(t[0]) {
- case '-':
- stop = 0;
- whidden = 1;
- t++;
- break;
+ w->next = apps_groups_root_target;
+ apps_groups_root_target = w;
- case '+':
- stop = 0;
- wdebug = 1;
- t++;
- break;
- }
+ 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":"-"
+ );
- if(stop) break;
- }
+ return w;
+}
- if(debug) fprintf(stderr, "apps.plugin: \t\ttarget %s\n", t);
+// read the apps_groups.conf file
+int read_apps_groups_conf(const char *name)
+{
+ char filename[FILENAME_MAX + 1];
- struct target *w = NULL;
- long count = 0;
- int blen = 0;
- char buffer[4097] = "";
- buffer[4096] = '\0';
+ snprintf(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
+
+ if(unlikely(debug))
+ fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
- // the process names
- while((p = strsep(&s, " "))) {
- p = trim(p);
- if(!p || !*p) continue;
+ // ----------------------------------------
- strncpy(&buffer[blen], p, 4096 - blen);
- blen = strlen(buffer);
+ procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
+ if(!ff) return 1;
+
+ procfile_set_quotes(ff, "'\"");
+
+ ff = procfile_readall(ff);
+ if(!ff) {
+ procfile_close(ff);
+ return 1;
+ }
+
+ 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;
- while(buffer[blen - 1] == '\\') {
- buffer[blen - 1] = ' ';
+ for(word = 0; word < words ;word++) {
+ char *s = procfile_lineword(ff, line, word);
+ if(!s || !*s) continue;
+ if(*s == '#') break;
- if((p = strsep(&s, " ")))
- p = trim(p);
+ if(t == s) continue;
- if(!p || !*p) p = " ";
- strncpy(&buffer[blen], p, 4096 - blen);
- blen = strlen(buffer);
+ struct target *n = get_apps_groups_target(s, w);
+ if(!n) {
+ error("Cannot create target '%s' (line %d, word %d)", s, line, word);
+ continue;
}
- struct target *n = get_target(buffer, w);
- n->hidden = whidden;
- n->debug = wdebug;
if(!w) w = n;
+ }
- buffer[0] = '\0';
- blen = 0;
+ if(w) {
+ int tdebug = 0, thidden = 0;
- count++;
- }
+ while(t[0] == '-' || t[0] == '+') {
+ if(t[0] == '-') thidden = 1;
+ if(t[0] == '+') tdebug = 1;
+ t++;
+ }
- if(w) strncpy(w->name, t, MAX_NAME);
- if(!count) error("The line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
+ strncpy(w->name, t, MAX_NAME);
+ w->name[MAX_NAME] = '\0';
+ 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":"-"
+ );
+ }
}
- fclose(fp);
- default_target = get_target("+p!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
- strncpy(default_target->name, "other", MAX_NAME);
+ 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
+ strncpy(apps_groups_default_target->name, "other", MAX_NAME);
return 0;
}
@@ -490,6 +619,8 @@ int read_process_groups(const char *name)
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;
@@ -533,6 +664,9 @@ struct pid_stat {
// uint64_t guest_time;
// int64_t cguest_time;
+ uid_t uid;
+ gid_t gid;
+
unsigned long long statm_size;
unsigned long long statm_resident;
unsigned long long statm_share;
@@ -549,7 +683,29 @@ struct pid_stat {
unsigned long long io_storage_bytes_written;
unsigned long long io_cancelled_write_bytes;
-#ifdef INCLUDE_CHILDS
+ // we need the last values
+ // for all incremental counters
+ // so that when a process switches users/groups
+ // we will subtract these values from the old
+ // target
+ unsigned long long last_minflt;
+ unsigned long long last_cminflt;
+ unsigned long long last_majflt;
+ unsigned long long last_cmajflt;
+ unsigned long long last_utime;
+ unsigned long long last_stime;
+ unsigned long long last_cutime;
+ unsigned long long last_cstime;
+
+ unsigned long long last_io_logical_bytes_read;
+ unsigned long long last_io_logical_bytes_written;
+ unsigned long long last_io_read_calls;
+ unsigned long long last_io_write_calls;
+ unsigned long long last_io_storage_bytes_read;
+ unsigned long long last_io_storage_bytes_written;
+ unsigned long long last_io_cancelled_write_bytes;
+
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
unsigned long long old_utime;
unsigned long long old_stime;
unsigned long long old_minflt;
@@ -569,19 +725,24 @@ struct pid_stat {
unsigned long long diff_cstime;
unsigned long long diff_cminflt;
unsigned long long diff_cmajflt;
-#endif
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
- int *fds; // array of fds it uses
- int fds_size; // the size of the fds array
+ int *fds; // array of fds it uses
+ int fds_size; // the size of the fds array
- int childs; // number of processes directly referencing this
- int updated; // 1 when update
- int merged; // 1 when it has been merged to its parent
+ int children_count; // number of processes directly referencing this
+ int updated; // 1 when update
+ int merged; // 1 when it has been merged to its parent
int new_entry;
- struct target *target;
+
+ struct target *target; // app_groups.conf targets
+ struct target *user_target; // uid based targets
+ struct target *group_target; // gid based targets
+
struct pid_stat *parent;
struct pid_stat *prev;
struct pid_stat *next;
+
} *root_of_pids = NULL, **all_pids;
long all_pids_count = 0;
@@ -633,14 +794,68 @@ void del_pid_entry(pid_t pid)
// ----------------------------------------------------------------------------
// update pids from proc
+int read_proc_pid_cmdline(struct pid_stat *p) {
+ char filename[FILENAME_MAX + 1];
+ snprintf(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
+
+ int fd = open(filename, O_RDONLY, 0666);
+ if(unlikely(fd == -1)) return 1;
+
+ int i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
+ close(fd);
+
+ if(bytes <= 0) {
+ // copy the command to the command line
+ strncpy(p->cmdline, p->comm, MAX_CMDLINE);
+ p->cmdline[MAX_CMDLINE] = '\0';
+ return 0;
+ }
+
+ p->cmdline[bytes] = '\0';
+ for(i = 0; i < bytes ; i++)
+ if(!p->cmdline[i]) p->cmdline[i] = ' ';
+
+ if(unlikely(debug))
+ fprintf(stderr, "Read file '%s' contents: %s\n", filename, p->cmdline);
+
+ return 0;
+}
+
+int read_proc_pid_ownership(struct pid_stat *p) {
+ char filename[FILENAME_MAX + 1];
+
+ snprintf(filename, FILENAME_MAX, "%s/proc/%d", host_prefix, p->pid);
+
+ // ----------------------------------------
+ // read uid and gid
+
+ struct stat st;
+ if(stat(filename, &st) != 0)
+ return 1;
+
+ p->uid = st.st_uid;
+ p->gid = st.st_gid;
+
+ return 0;
+}
+
int read_proc_pid_stat(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
+ // ----------------------------------------
+
+ int set_quotes = (!ff)?1:0;
+
ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
if(!ff) return 1;
+ // if(set_quotes) procfile_set_quotes(ff, "()");
+ if(set_quotes) procfile_set_open_close(ff, "(", ")");
+
ff = procfile_readall(ff);
if(!ff) {
// procfile_close(ff);
@@ -649,27 +864,10 @@ int read_proc_pid_stat(struct pid_stat *p) {
file_counter++;
- p->comm[0] = '\0';
- p->comm[MAX_COMPARE_NAME] = '\0';
- size_t blen = 0;
-
- char *s = procfile_lineword(ff, 0, 1);
- if(*s == '(') s++;
- size_t len = strlen(s);
+ // parse the process name
unsigned int i = 0;
- while(len && s[len - 1] != ')') {
- if(blen < MAX_COMPARE_NAME) {
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
- blen = strlen(p->comm);
- }
-
- i++;
- s = procfile_lineword(ff, 0, 1+i);
- len = strlen(s);
- }
- if(len && s[len - 1] == ')') s[len - 1] = '\0';
- if(blen < MAX_COMPARE_NAME)
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
+ strncpy(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
+ p->comm[MAX_COMPARE_NAME] = '\0';
// p->pid = atol(procfile_lineword(ff, 0, 0+i));
// comm is at 1
@@ -716,13 +914,16 @@ int read_proc_pid_stat(struct pid_stat *p) {
// p->guest_time = strtoull(procfile_lineword(ff, 0, 42+i), NULL, 10);
// p->cguest_time = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' 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->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
// procfile_close(ff);
return 0;
}
int read_proc_pid_statm(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
@@ -751,6 +952,8 @@ int read_proc_pid_statm(struct pid_stat *p) {
}
int read_proc_pid_io(struct pid_stat *p) {
+ static procfile *ff = NULL;
+
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
@@ -780,56 +983,17 @@ int read_proc_pid_io(struct pid_stat *p) {
// ----------------------------------------------------------------------------
-
-#ifdef INCLUDE_CHILDS
-// print a tree view of all processes
-int walk_down(pid_t pid, int level) {
- struct pid_stat *p = NULL;
- char b[level+3];
- int i, ret = 0;
-
- for(i = 0; i < level; i++) b[i] = '\t';
- b[level] = '|';
- b[level+1] = '-';
- b[level+2] = '\0';
-
- for(p = root_of_pids; p ; p = p->next) {
- if(p->ppid == pid) {
- ret += walk_down(p->pid, level+1);
- }
- }
-
- p = all_pids[pid];
- if(p) {
- if(!p->updated) ret += 1;
- if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"
- , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->childs
- , p->utime, p->utime - p->old_utime
- , p->stime, p->stime - p->old_stime
- , p->cutime, p->cutime - p->old_cutime
- , p->cstime, p->cstime - p->old_cstime
- , p->minflt, p->minflt - p->old_minflt
- , p->majflt, p->majflt - p->old_majflt
- , p->cminflt, p->cminflt - p->old_cminflt
- , p->cmajflt, p->cmajflt - p->old_cmajflt
- );
- }
-
- return ret;
-}
-#endif
-
-
-// ----------------------------------------------------------------------------
// file descriptor
// this is used to keep a global list of all open files of the system
-// it is needed in order to figure out the unique files a process tree has open
+// it is needed in order to calculate the unique files processes have open
#define FILE_DESCRIPTORS_INCREASE_STEP 100
struct file_descriptor {
avl avl;
+#ifdef NETDATA_INTERNAL_CHECKS
uint32_t magic;
+#endif /* NETDATA_INTERNAL_CHECKS */
uint32_t hash;
const char *name;
int type;
@@ -841,25 +1005,33 @@ int all_files_len = 0;
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.");
+#endif /* NETDATA_INTERNAL_CHECKS */
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,
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
PTHREAD_MUTEX_INITIALIZER
#else
PTHREAD_RWLOCK_INITIALIZER
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
};
static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) {
@@ -868,7 +1040,9 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
tmp.name = name;
tmp.count = 0;
tmp.pos = 0;
+#ifdef NETDATA_INTERNAL_CHECKS
tmp.magic = 0x0BADCAFE;
+#endif /* NETDATA_INTERNAL_CHECKS */
avl_search(&all_files_index, (avl *)&tmp, file_descriptor_iterator, (avl **)&result);
return result;
@@ -890,10 +1064,13 @@ 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) {
+
+#ifdef NETDATA_INTERNAL_CHECKS
if(all_files[id].magic != 0x0BADCAFE) {
error("Ignoring request to remove empty file id %d.", id);
return;
}
+#endif /* NETDATA_INTERNAL_CHECKS */
if(debug) fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
@@ -903,7 +1080,9 @@ void file_descriptor_not_used(int id)
if(!all_files[id].count) {
if(debug) fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
file_descriptor_remove(&all_files[id]);
+#ifdef NETDATA_INTERNAL_CHECKS
all_files[id].magic = 0x00000000;
+#endif /* NETDATA_INTERNAL_CHECKS */
all_files_len--;
}
}
@@ -953,7 +1132,9 @@ int file_descriptor_find_or_add(const char *name)
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;
+#endif /* NETDATA_INTERNAL_CHECKS */
all_files[i].pos = i;
}
@@ -972,8 +1153,10 @@ int file_descriptor_find_or_add(const char *name)
if(!all_files[c].count) {
if(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);
+#endif /* NETDATA_INTERNAL_CHECKS */
if(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) free((void *)all_files[c].name);
@@ -1015,8 +1198,9 @@ int file_descriptor_find_or_add(const char *name)
all_files[c].type = type;
all_files[c].pos = c;
all_files[c].count = 1;
+#ifdef NETDATA_INTERNAL_CHECKS
all_files[c].magic = 0x0BADCAFE;
-
+#endif /* NETDATA_INTERNAL_CHECKS */
file_descriptor_add(&all_files[c]);
if(debug) fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
@@ -1024,6 +1208,81 @@ int file_descriptor_find_or_add(const char *name)
return c;
}
+int read_pid_file_descriptors(struct pid_stat *p) {
+ char dirname[FILENAME_MAX+1];
+
+ snprintf(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(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 = realloc(p->fds, (fdid + 100) * sizeof(int));
+ if(!p->fds) {
+ error("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;
+}
+
+// ----------------------------------------------------------------------------
// 1. read all files in /proc
// 2. for each numeric directory:
@@ -1041,11 +1300,8 @@ int file_descriptor_find_or_add(const char *name)
// to avoid filling up all disk space
// if debug is enabled, all errors are printed
-int update_from_proc(void)
+int collect_data_for_all_processes_from_proc(void)
{
- static long count_errors = 0;
-
- char filename[FILENAME_MAX+1];
char dirname[FILENAME_MAX + 1];
snprintf(dirname, FILENAME_MAX, "%s/proc", host_prefix);
@@ -1061,38 +1317,73 @@ int update_from_proc(void)
all_pids_count++;
p->parent = NULL;
p->updated = 0;
- p->childs = 0;
+ p->children_count = 0;
p->merged = 0;
p->new_entry = 0;
+
+ p->last_minflt = p->minflt;
+ p->last_cminflt = p->cminflt;
+ p->last_majflt = p->majflt;
+ p->last_cmajflt = p->cmajflt;
+ p->last_utime = p->utime;
+ p->last_stime = p->stime;
+ p->last_cutime = p->cutime;
+ p->last_cstime = p->cstime;
+
+ p->last_io_logical_bytes_read = p->io_logical_bytes_read;
+ p->last_io_logical_bytes_written = p->io_logical_bytes_written;
+ p->last_io_read_calls = p->io_read_calls;
+ p->last_io_write_calls = p->io_write_calls;
+ p->last_io_storage_bytes_read = p->io_storage_bytes_read;
+ p->last_io_storage_bytes_written = p->io_storage_bytes_written;
+ p->last_io_cancelled_write_bytes = p->io_cancelled_write_bytes;
}
while((file = readdir(dir))) {
char *endptr = file->d_name;
pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
- if(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0') continue;
+
+ // make sure we read a valid number
+ if(unlikely(pid <= 0 || pid > pid_max || endptr == file->d_name || *endptr != '\0'))
+ continue;
p = get_pid_entry(pid);
- if(!p) continue;
+ if(unlikely(!p)) continue;
+
// --------------------------------------------------------------------
// /proc/<pid>/stat
- if(read_proc_pid_stat(p)) {
- if(!count_errors++ || debug || (p->target && p->target->debug))
+ if(unlikely(read_proc_pid_stat(p))) {
error("Cannot process %s/proc/%d/stat", host_prefix, pid);
+ // there is no reason to proceed if we cannot get its status
continue;
}
- if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
+ // check its parent pid
+ if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
+ error("Pid %d states invalid parent pid %d. Using 0.", pid, p->ppid);
+
+ p->ppid = 0;
+ }
+
+ // --------------------------------------------------------------------
+ // /proc/<pid>/cmdline
+
+ if(proc_pid_cmdline_is_needed) {
+ if(unlikely(read_proc_pid_cmdline(p))) {
+ error("Cannot process %s/proc/%d/cmdline", host_prefix, pid);
+ }
+ }
// --------------------------------------------------------------------
// /proc/<pid>/statm
- if(read_proc_pid_statm(p)) {
- if(!count_errors++ || debug || (p->target && p->target->debug))
+ if(unlikely(read_proc_pid_statm(p))) {
error("Cannot process %s/proc/%d/statm", host_prefix, pid);
+ // there is no reason to proceed if we cannot get its memory status
continue;
}
@@ -1100,11 +1391,19 @@ int update_from_proc(void)
// --------------------------------------------------------------------
// /proc/<pid>/io
- if(read_proc_pid_io(p)) {
- if(!count_errors++ || debug || (p->target && p->target->debug))
+ if(unlikely(read_proc_pid_io(p))) {
error("Cannot process %s/proc/%d/io", host_prefix, pid);
- continue;
+ // on systems without /proc/X/io
+ // allow proceeding without I/O information
+ // continue;
+ }
+
+ // --------------------------------------------------------------------
+ // <pid> ownership
+
+ if(unlikely(read_proc_pid_ownership(p))) {
+ error("Cannot stat %s/proc/%d", host_prefix, pid);
}
// --------------------------------------------------------------------
@@ -1112,18 +1411,30 @@ int update_from_proc(void)
// check if it is target
// we do this only once, the first time this pid is loaded
- if(p->new_entry) {
+ if(unlikely(p->new_entry)) {
if(debug) fprintf(stderr, "apps.plugin: \tJust added %s\n", p->comm);
+ uint32_t hash = simple_hash(p->comm);
+ size_t pclen = strlen(p->comm);
struct target *w;
- for(w = target_root; w ; w = w->next) {
+ 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);
- if(strcmp(w->compare, p->comm) == 0) {
+ // 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);
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
}
}
}
@@ -1131,69 +1442,8 @@ int update_from_proc(void)
// --------------------------------------------------------------------
// /proc/<pid>/fd
- snprintf(filename, FILENAME_MAX, "%s/proc/%s/fd", host_prefix, file->d_name);
- DIR *fds = opendir(filename);
- 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(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 = realloc(p->fds, (fdid + 100) * sizeof(int));
- if(!p->fds) {
- error("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/%s/fd/%s", host_prefix, file->d_name, de->d_name);
- ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
- if(l == -1) {
- if(debug || (p->target && p->target->debug)) {
- if(!count_errors++ || 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;
- }
+ if(unlikely(read_pid_file_descriptors(p))) {
+ error("Cannot process entries in %s/proc/%d/fd", host_prefix, pid);
}
// --------------------------------------------------------------------
@@ -1202,10 +1452,6 @@ int update_from_proc(void)
// mark it as updated
p->updated = 1;
}
- if(count_errors > 1000) {
- error("%ld more errors encountered\n", count_errors - 1);
- count_errors = 0;
- }
closedir(dir);
@@ -1214,6 +1460,48 @@ int update_from_proc(void)
// ----------------------------------------------------------------------------
+
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+// print a tree view of all processes
+int debug_childrens_aggregations(pid_t pid, int level) {
+ struct pid_stat *p = NULL;
+ char b[level+3];
+ int i, ret = 0;
+
+ for(i = 0; i < level; i++) b[i] = '\t';
+ b[level] = '|';
+ b[level+1] = '-';
+ b[level+2] = '\0';
+
+ for(p = root_of_pids; p ; p = p->next) {
+ if(p->ppid == pid) {
+ ret += debug_childrens_aggregations(p->pid, level+1);
+ }
+ }
+
+ p = all_pids[pid];
+ if(p) {
+ if(!p->updated) ret += 1;
+ if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"
+ , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->children_count
+ , p->utime, p->utime - p->old_utime
+ , p->stime, p->stime - p->old_stime
+ , p->cutime, p->cutime - p->old_cutime
+ , p->cstime, p->cstime - p->old_cstime
+ , p->minflt, p->minflt - p->old_minflt
+ , p->majflt, p->majflt - p->old_majflt
+ , p->cminflt, p->cminflt - p->old_cminflt
+ , p->cmajflt, p->cmajflt - p->old_cmajflt
+ );
+ }
+
+ return ret;
+}
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+
+
+
+// ----------------------------------------------------------------------------
// update statistics on the targets
// 1. link all childs to their parents
@@ -1223,87 +1511,41 @@ int update_from_proc(void)
// 4. go from top to bottom, linking all childs without a target, to their parent target
// after this step, all processes have a target
// [5. for each killed pid (updated = 0), remove its usage from its target]
-// 6. zero all targets
-// 7. concentrate all values on the targets
+// 6. zero all apps_groups_targets
+// 7. concentrate all values on the apps_groups_targets
// 8. remove all killed processes
// 9. find the unique file count for each target
+// check: update_apps_groups_statistics()
-void update_statistics(void)
-{
- int c;
+void link_all_processes_to_their_parents(void) {
struct pid_stat *p = NULL;
- // link all parents and update childs count
+ // link all children to their parents
+ // and update children count on parents
for(p = root_of_pids; p ; p = p->next) {
- if(p->ppid > 0 && p->ppid <= pid_max && all_pids[p->ppid]) {
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \tparent of %d %s is %d %s\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
+ // for each process found running
- p->parent = all_pids[p->ppid];
- p->parent->childs++;
- }
- else if(p->ppid != 0) error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
- }
+ if(p->ppid > 0
+ && p->ppid <= pid_max
+ && all_pids[p->ppid]
+ ) {
+ // for valid processes
- // find all the procs with 0 childs and merge them to their parents
- // repeat, until nothing more can be done.
- int found = 1;
- while(found) {
- found = 0;
- for(p = root_of_pids; p ; p = p->next) {
- // if this process does not have any childs, and
- // is not already merged, and
- // its parent has childs waiting to be merged, and
- // the target of this process and its parent is the same, or the parent does not have a target, or this process does not have a parent
- // and its parent is not init
- // then... merge them!
- if(!p->childs && !p->merged && p->parent && p->parent->childs && (p->target == p->parent->target || !p->parent->target || !p->target) && p->ppid != 1) {
- p->parent->childs--;
- p->merged = 1;
-
- // the parent inherits the child's target, if it does not have a target itself
- if(p->target && !p->parent->target) {
- p->parent->target = p->target;
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\ttarget %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);
- }
+ if(debug || (p->target && p->target->debug))
+ fprintf(stderr, "apps.plugin: \tparent of %d (%s) is %d (%s)\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
- found++;
- }
+ p->parent = all_pids[p->ppid];
+ p->parent->children_count++;
}
- if(debug) fprintf(stderr, "apps.plugin: merged %d processes\n", found);
- }
-
- // give a default target on all top level processes
- // init goes always to default target
- if(all_pids[1]) all_pids[1]->target = default_target;
-
- for(p = root_of_pids; p ; p = p->next) {
- // if the process is not merged itself
- // then is is a top level process
- if(!p->merged && !p->target) p->target = default_target;
-
-#ifdef INCLUDE_CHILDS
- // by the way, update the diffs
- // will be used later for substracting killed process times
- p->diff_cutime = p->utime - p->cutime;
- p->diff_cstime = p->stime - p->cstime;
- p->diff_cminflt = p->minflt - p->cminflt;
- p->diff_cmajflt = p->majflt - p->cmajflt;
-#endif
+ else if(p->ppid != 0)
+ error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
}
+}
- // give a target to all merged child processes
- found = 1;
- while(found) {
- found = 0;
- for(p = root_of_pids; p ; p = p->next) {
- if(!p->target && p->merged && p->parent && p->parent->target) {
- p->target = p->parent->target;
- found++;
- }
- }
- }
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+void aggregate_children_to_parents(void) {
+ struct pid_stat *p = NULL;
-#ifdef INCLUDE_CHILDS
// for each killed process, remove its values from the parents
// sums (we had already added them in a previous loop)
for(p = root_of_pids; p ; p = p->next) {
@@ -1356,17 +1598,140 @@ void update_statistics(void)
if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
}
-#endif
+}
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+
+void cleanup_non_existing_pids(void) {
+ int c;
+ struct pid_stat *p = NULL;
+
+ for(p = root_of_pids; p ;) {
+ if(!p->updated) {
+// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%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->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+
+ 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 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;
+ while(found) {
+ 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.
+ found = 1;
+ while(found) {
+ found = 0;
+ for(p = root_of_pids; p ; p = p->next) {
+ // 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;
- // zero all the targets
- targets = 0;
+ // 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(debug)
+ fprintf(stderr, "apps.plugin: 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
+ for(p = root_of_pids; p ; p = p->next) {
+ // if the process is not merged itself
+ // then is is a top level process
+ if(!p->merged && !p->target)
+ p->target = apps_groups_default_target;
+
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+ // by the way, update the diffs
+ // will be used later for subtracting killed process times
+ p->diff_cutime = p->utime - p->cutime;
+ p->diff_cstime = p->stime - p->cstime;
+ p->diff_cminflt = p->minflt - p->cminflt;
+ p->diff_cmajflt = p->majflt - p->cmajflt;
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+ }
+
+ // give a target to all merged child processes
+ found = 1;
+ while(found) {
+ 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);
+ }
+ }
+ }
+}
+
+long zero_all_targets(struct target *root) {
struct target *w;
- for (w = target_root; w ; w = w->next) {
- targets++;
+ long count = 0;
- w->fds = calloc(sizeof(int), (size_t) all_files_size);
- if(!w->fds)
- error("Cannot allocate memory for fds in %s", w->name);
+ for (w = root; w ; w = w->next) {
+ count++;
+
+ if(w->fds) free(w->fds);
+ w->fds = NULL;
w->minflt = 0;
w->majflt = 0;
@@ -1397,131 +1762,175 @@ void update_statistics(void)
w->io_cancelled_write_bytes = 0;
}
-#ifdef INCLUDE_CHILDS
- if(debug) walk_down(0, 1);
-#endif
+ return count;
+}
- // concentrate everything on the targets
- for(p = root_of_pids; p ; p = p->next) {
- if(!p->target) {
- error("pid %d %s was left without a target!", p->pid, p->comm);
- continue;
- }
+void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
+ if(unlikely(!w->fds)) {
+ w->fds = calloc(sizeof(int), (size_t) all_files_size);
+ if(unlikely(!w->fds))
+ error("Cannot allocate memory for fds in %s", w->name);
+ }
- if(p->updated) {
- p->target->cutime += p->cutime; // - p->fix_cutime;
- p->target->cstime += p->cstime; // - p->fix_cstime;
- p->target->cminflt += p->cminflt; // - p->fix_cminflt;
- p->target->cmajflt += p->cmajflt; // - p->fix_cmajflt;
+ if(likely(p->updated)) {
+ w->cutime += p->cutime; // - p->fix_cutime;
+ w->cstime += p->cstime; // - p->fix_cstime;
+ w->cminflt += p->cminflt; // - p->fix_cminflt;
+ w->cmajflt += p->cmajflt; // - p->fix_cmajflt;
- p->target->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
- p->target->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
- p->target->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
- p->target->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
+ w->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
+ w->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
+ w->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
+ w->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
- //if(p->num_threads < 0)
- // error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
+ //if(p->num_threads < 0)
+ // error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
- //if(p->num_threads > 10000)
- // error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
+ //if(p->num_threads > 10000)
+ // error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
- p->target->num_threads += p->num_threads;
- p->target->rss += p->rss;
+ w->num_threads += p->num_threads;
+ w->rss += p->rss;
- p->target->statm_size += p->statm_size;
- p->target->statm_resident += p->statm_resident;
- p->target->statm_share += p->statm_share;
- p->target->statm_text += p->statm_text;
- p->target->statm_lib += p->statm_lib;
- p->target->statm_data += p->statm_data;
- p->target->statm_dirty += p->statm_dirty;
+ 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;
- p->target->io_logical_bytes_read += p->io_logical_bytes_read;
- p->target->io_logical_bytes_written += p->io_logical_bytes_written;
- p->target->io_read_calls += p->io_read_calls;
- p->target->io_write_calls += p->io_write_calls;
- p->target->io_storage_bytes_read += p->io_storage_bytes_read;
- p->target->io_storage_bytes_written += p->io_storage_bytes_written;
- p->target->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+ 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;
- p->target->processes++;
+ w->processes++;
+ if(likely(w->fds)) {
+ int c;
for(c = 0; c < p->fds_size ;c++) {
if(p->fds[c] == 0) continue;
- if(p->fds[c] < all_files_size) {
- if(p->target->fds) p->target->fds[p->fds[c]]++;
+
+ 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(debug || p->target->debug) fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
-
-/* if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);
- if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);
- if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
- if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
- if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
- if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
- if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);
- if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);
+ if(unlikely(debug || w->debug))
+ fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+
+/* if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);
+ if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);
+ if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
+ if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
+ if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
+ if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
+ if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);
+ if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);
*/
-#ifdef INCLUDE_CHILDS
- p->old_utime = p->utime;
- p->old_cutime = p->cutime;
- p->old_stime = p->stime;
- p->old_cstime = p->cstime;
- p->old_minflt = p->minflt;
- p->old_majflt = p->majflt;
- p->old_cminflt = p->cminflt;
- p->old_cmajflt = p->cmajflt;
-#endif
- }
- else {
- // since the process has exited, the user
- // will see a drop in our charts, because the incremental
- // values of this process will not be there
-
- // add them to the fix_* values and they will be added to
- // the reported values, so that the report goes steady
- p->target->fix_minflt += p->minflt;
- p->target->fix_majflt += p->majflt;
- p->target->fix_utime += p->utime;
- p->target->fix_stime += p->stime;
- p->target->fix_cminflt += p->cminflt;
- p->target->fix_cmajflt += p->cmajflt;
- p->target->fix_cutime += p->cutime;
- p->target->fix_cstime += p->cstime;
-
- p->target->fix_io_logical_bytes_read += p->io_logical_bytes_read;
- p->target->fix_io_logical_bytes_written += p->io_logical_bytes_written;
- p->target->fix_io_read_calls += p->io_read_calls;
- p->target->fix_io_write_calls += p->io_write_calls;
- p->target->fix_io_storage_bytes_read += p->io_storage_bytes_read;
- p->target->fix_io_storage_bytes_written += p->io_storage_bytes_written;
- p->target->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+ p->old_utime = p->utime;
+ p->old_cutime = p->cutime;
+ p->old_stime = p->stime;
+ p->old_cstime = p->cstime;
+ p->old_minflt = p->minflt;
+ p->old_majflt = p->majflt;
+ p->old_cminflt = p->cminflt;
+ p->old_cmajflt = p->cmajflt;
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+
+ if(o) {
+ // since the process switched target
+ // for all incremental values
+ // we have to subtract its OLD values from the new target
+ // and add its OLD values to the old target
+
+ // IMPORTANT
+ // We add/subtract the last/OLD values we added to the target
+
+ w->fix_cutime -= p->last_cutime;
+ w->fix_cstime -= p->last_cstime;
+ w->fix_cminflt -= p->last_cminflt;
+ w->fix_cmajflt -= p->last_cmajflt;
+
+ w->fix_utime -= p->last_utime;
+ w->fix_stime -= p->last_stime;
+ w->fix_minflt -= p->last_minflt;
+ w->fix_majflt -= p->last_majflt;
+
+
+ w->fix_io_logical_bytes_read -= p->last_io_logical_bytes_read;
+ w->fix_io_logical_bytes_written -= p->last_io_logical_bytes_written;
+ w->fix_io_read_calls -= p->last_io_read_calls;
+ w->fix_io_write_calls -= p->last_io_write_calls;
+ w->fix_io_storage_bytes_read -= p->last_io_storage_bytes_read;
+ w->fix_io_storage_bytes_written -= p->last_io_storage_bytes_written;
+ w->fix_io_cancelled_write_bytes -= p->last_io_cancelled_write_bytes;
+
+ // ---
+
+ o->fix_cutime += p->last_cutime;
+ o->fix_cstime += p->last_cstime;
+ o->fix_cminflt += p->last_cminflt;
+ o->fix_cmajflt += p->last_cmajflt;
+
+ o->fix_utime += p->last_utime;
+ o->fix_stime += p->last_stime;
+ o->fix_minflt += p->last_minflt;
+ o->fix_majflt += p->last_majflt;
+
+ o->fix_io_logical_bytes_read += p->last_io_logical_bytes_read;
+ o->fix_io_logical_bytes_written += p->last_io_logical_bytes_written;
+ o->fix_io_read_calls += p->last_io_read_calls;
+ o->fix_io_write_calls += p->last_io_write_calls;
+ o->fix_io_storage_bytes_read += p->last_io_storage_bytes_read;
+ o->fix_io_storage_bytes_written += p->last_io_storage_bytes_written;
+ o->fix_io_cancelled_write_bytes += p->last_io_cancelled_write_bytes;
}
}
+ else {
+ // if(o) fprintf(stderr, "apps.plugin: \t\tpid %d (%s) is not updated by OLD target %s (%s) is present.\n", p->pid, p->comm, o->id, o->name);
+
+ // since the process has exited, the user
+ // will see a drop in our charts, because the incremental
+ // values of this process will not be there
+
+ // add them to the fix_* values and they will be added to
+ // the reported values, so that the report goes steady
+ w->fix_minflt += p->minflt;
+ w->fix_majflt += p->majflt;
+ w->fix_utime += p->utime;
+ w->fix_stime += p->stime;
+ w->fix_cminflt += p->cminflt;
+ w->fix_cmajflt += p->cmajflt;
+ w->fix_cutime += p->cutime;
+ w->fix_cstime += p->cstime;
+
+ w->fix_io_logical_bytes_read += p->io_logical_bytes_read;
+ w->fix_io_logical_bytes_written += p->io_logical_bytes_written;
+ w->fix_io_read_calls += p->io_read_calls;
+ w->fix_io_write_calls += p->io_write_calls;
+ w->fix_io_storage_bytes_read += p->io_storage_bytes_read;
+ w->fix_io_storage_bytes_written += p->io_storage_bytes_written;
+ w->fix_io_cancelled_write_bytes += p->io_cancelled_write_bytes;
+ }
-// fprintf(stderr, "\n");
- // cleanup all un-updated processed (exited, killed, etc)
- for(p = root_of_pids; p ;) {
- if(!p->updated) {
-// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%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->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
+}
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
- file_descriptor_not_used(p->fds[c]);
- p->fds[c] = 0;
- }
+void count_targets_fds(struct target *root) {
+ int c;
+ struct target *w;
- pid_t r = p->pid;
- p = p->next;
- del_pid_entry(r);
- }
- else p = p->next;
- }
+ for (w = root; w ; w = w->next) {
+ if(!w->fds) continue;
- for (w = target_root; w ; w = w->next) {
w->openfiles = 0;
w->openpipes = 0;
w->opensockets = 0;
@@ -1533,7 +1942,8 @@ void update_statistics(void)
w->openother = 0;
for(c = 1; c < all_files_size ;c++) {
- if(w->fds && w->fds[c] > 0) switch(all_files[c].type) {
+ if(w->fds[c] > 0)
+ switch(all_files[c].type) {
case FILETYPE_FILE:
w->openfiles++;
break;
@@ -1576,15 +1986,90 @@ void update_statistics(void)
}
}
+void calculate_netdata_statistics(void)
+{
+ link_all_processes_to_their_parents();
+ apply_apps_groups_targets_inheritance();
+
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+ aggregate_children_to_parents();
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+
+ zero_all_targets(users_root_target);
+ zero_all_targets(groups_root_target);
+ apps_groups_targets = zero_all_targets(apps_groups_root_target);
+
+#ifdef AGGREGATE_CHILDREN_TO_PARENTS
+ if(debug)
+ debug_childrens_aggregations(0, 1);
+#endif /* AGGREGATE_CHILDREN_TO_PARENTS */
+
+ // 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) {
+
+ // --------------------------------------------------------------------
+ // 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 %d (%s) to %d.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, 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);
+
+
+ // --------------------------------------------------------------------
+ // 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 %d (%s) to %d.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, 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);
+
+ }
+
+ count_targets_fds(apps_groups_root_target);
+ count_targets_fds(users_root_target);
+ count_targets_fds(groups_root_target);
+
+ cleanup_non_existing_pids();
+}
+
// ----------------------------------------------------------------------------
// update chart dimensions
-void show_dimensions(void)
-{
+unsigned long long send_resource_usage_to_netdata() {
static struct timeval last = { 0, 0 };
static struct rusage me_last;
- struct target *w;
struct timeval now;
struct rusage me;
@@ -1615,138 +2100,145 @@ void show_dimensions(void)
bcopy(&me, &me_last, sizeof(struct rusage));
}
- fprintf(stdout, "BEGIN apps.cpu %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN netdata.apps_cpu %llu\n", usec);
+ fprintf(stdout, "SET user = %llu\n", cpuuser);
+ fprintf(stdout, "SET system = %llu\n", cpusyst);
+ fprintf(stdout, "END\n");
+
+ fprintf(stdout, "BEGIN netdata.apps_files %llu\n", usec);
+ fprintf(stdout, "SET files = %llu\n", file_counter);
+ fprintf(stdout, "SET pids = %ld\n", all_pids_count);
+ fprintf(stdout, "SET fds = %d\n", all_files_len);
+ fprintf(stdout, "SET targets = %ld\n", apps_groups_targets);
+ fprintf(stdout, "END\n");
+
+ return usec;
+}
+
+void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec)
+{
+ struct target *w;
+
+ fprintf(stdout, "BEGIN %s.cpu %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.cpu_user %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.cpu_user %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.cpu_system %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.cpu_system %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.threads %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.threads %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->num_threads);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.processes %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.processes %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %lu\n", w->name, w->processes);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.mem %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.mem %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %lld\n", w->name, (long long)w->statm_resident - (long long)w->statm_share);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.minor_faults %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.minor_faults %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.major_faults %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.major_faults %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.lreads %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.lreads %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read);
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read + w->fix_io_logical_bytes_read);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.lwrites %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.lwrites %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written);
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written + w->fix_io_logical_bytes_written);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.preads %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.preads %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read);
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read + w->fix_io_storage_bytes_read);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.pwrites %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.pwrites %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
- fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written);
+ fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written + w->fix_io_storage_bytes_written);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.files %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.files %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->openfiles);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.sockets %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.sockets %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->opensockets);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN apps.pipes %llu\n", usec);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "BEGIN %s.pipes %llu\n", type, usec);
+ for (w = root; w ; w = w->next) {
if(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "SET %s = %llu\n", w->name, w->openpipes);
}
fprintf(stdout, "END\n");
- fprintf(stdout, "BEGIN netdata.apps_cpu %llu\n", usec);
- fprintf(stdout, "SET user = %llu\n", cpuuser);
- fprintf(stdout, "SET system = %llu\n", cpusyst);
- fprintf(stdout, "END\n");
-
- fprintf(stdout, "BEGIN netdata.apps_files %llu\n", usec);
- fprintf(stdout, "SET files = %llu\n", file_counter);
- fprintf(stdout, "SET pids = %ld\n", all_pids_count);
- fprintf(stdout, "SET fds = %d\n", all_files_len);
- fprintf(stdout, "SET targets = %ld\n", targets);
- fprintf(stdout, "END\n");
-
fflush(stdout);
}
@@ -1754,12 +2246,12 @@ void show_dimensions(void)
// ----------------------------------------------------------------------------
// generate the charts
-void show_charts(void)
+void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
{
struct target *w;
int newly_added = 0;
- for(w = target_root ; w ; w = w->next)
+ for(w = root ; w ; w = w->next)
if(!w->exposed && w->processes) {
newly_added++;
w->exposed = 1;
@@ -1771,122 +2263,110 @@ void show_charts(void)
// we have something new to show
// update the charts
- fprintf(stdout, "CHART apps.cpu '' 'Apps CPU Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu stacked 20001 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "CHART %s.cpu '' '%s CPU Time (%ld%% = %ld 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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu %s\n", w->name, Hertz, w->hidden ? "hidden,noreset" : "noreset");
}
- fprintf(stdout, "CHART apps.mem '' 'Apps Dedicated Memory (w/o shared)' 'MB' mem apps.mem stacked 20003 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute %ld %ld noreset\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
}
- fprintf(stdout, "CHART apps.threads '' 'Apps Threads' 'threads' processes apps.threads stacked 20005 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.processes '' 'Apps Processes' 'processes' processes apps.processes stacked 20004 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.cpu_user '' 'Apps CPU User Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu_user stacked 20020 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "CHART %s.cpu_user '' '%s CPU User Time (%ld%% = %ld 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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu noreset\n", w->name, Hertz * processors);
}
- fprintf(stdout, "CHART apps.cpu_system '' 'Apps CPU System Time (%ld%% = %ld core%s)' 'cpu time %%' cpu apps.cpu_system stacked 20021 %d\n", (processors * 100), processors, (processors>1)?"s":"", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%ld%% = %ld 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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 100 %llu noreset\n", w->name, Hertz * processors);
}
- fprintf(stdout, "CHART apps.major_faults '' 'Apps Major Page Faults (swap read)' 'page faults/s' swap apps.major_faults stacked 20010 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.minor_faults '' 'Apps Minor Page Faults' 'page faults/s' mem apps.minor_faults stacked 20011 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.lreads '' 'Apps Disk Logical Reads' 'kilobytes/s' disk apps.lreads stacked 20042 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
}
- fprintf(stdout, "CHART apps.lwrites '' 'Apps I/O Logical Writes' 'kilobytes/s' disk apps.lwrites stacked 20042 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
}
- fprintf(stdout, "CHART apps.preads '' 'Apps Disk Reads' 'kilobytes/s' disk apps.preads stacked 20002 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
}
- fprintf(stdout, "CHART apps.pwrites '' 'Apps Disk Writes' 'kilobytes/s' disk apps.pwrites stacked 20002 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
}
- fprintf(stdout, "CHART apps.files '' 'Apps Open Files' 'open files' disk apps.files stacked 20050 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.sockets '' 'Apps Open Sockets' 'open sockets' net apps.sockets stacked 20051 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
}
- fprintf(stdout, "CHART apps.pipes '' 'Apps Pipes' 'open pipes' processes apps.pipes stacked 20053 %d\n", update_every);
- for (w = target_root; w ; w = w->next) {
+ fprintf(stdout, "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(w->target || (!w->processes && !w->exposed)) continue;
fprintf(stdout, "DIMENSION %s '' absolute 1 1 noreset\n", w->name);
}
-
- fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %d\n", update_every);
- fprintf(stdout, "DIMENSION user '' incremental 1 %d\n", 1000);
- fprintf(stdout, "DIMENSION system '' incremental 1 %d\n", 1000);
-
- fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %d\n", update_every);
- fprintf(stdout, "DIMENSION files '' incremental 1 1\n");
- fprintf(stdout, "DIMENSION pids '' absolute 1 1\n");
- fprintf(stdout, "DIMENSION fds '' absolute 1 1\n");
- fprintf(stdout, "DIMENSION targets '' absolute 1 1\n");
-
- fflush(stdout);
}
@@ -1925,12 +2405,18 @@ void parse_args(int argc, char **argv)
if(freq > 0) update_every = freq;
if(!name) name = "groups";
- if(read_process_groups(name)) {
+ if(read_apps_groups_conf(name)) {
error("Cannot read process groups %s", name);
exit(1);
}
}
+unsigned long long sutime() {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return now.tv_sec * 1000000ULL + now.tv_usec;
+}
+
int main(int argc, char **argv)
{
// debug_flags = D_PROCFILE;
@@ -1938,6 +2424,9 @@ int main(int argc, char **argv)
// set the name for logging
program_name = "apps.plugin";
+ // disable syslog for apps.plugin
+ error_log_syslog = 0;
+
host_prefix = getenv("NETDATA_HOST_PREFIX");
if(host_prefix == NULL) {
info("NETDATA_HOST_PREFIX is not passed from netdata");
@@ -1945,15 +2434,22 @@ int main(int argc, char **argv)
}
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);
+
info("starting...");
procfile_adaptive_initial_allocation = 1;
time_t started_t = time(NULL);
time_t current_t;
- Hertz = get_hertz();
- pid_max = get_pid_max();
- processors = get_processors();
+ Hertz = get_system_hertz();
+ pid_max = get_system_pid_max();
+ processors = get_system_cpus();
parse_args(argc, argv);
@@ -1964,39 +2460,63 @@ int main(int argc, char **argv)
exit(1);
}
- unsigned long long counter = 1;
- unsigned long long usec = 0, susec = 0;
- struct timeval last, now;
- gettimeofday(&last, NULL);
+ fprintf(stdout, "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %d\n", update_every);
+ fprintf(stdout, "DIMENSION user '' incremental 1 %d\n", 1000);
+ fprintf(stdout, "DIMENSION system '' incremental 1 %d\n", 1000);
+ fprintf(stdout, "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %d\n", update_every);
+ fprintf(stdout, "DIMENSION files '' incremental 1 1\n");
+ fprintf(stdout, "DIMENSION pids '' absolute 1 1\n");
+ fprintf(stdout, "DIMENSION fds '' absolute 1 1\n");
+ fprintf(stdout, "DIMENSION targets '' absolute 1 1\n");
+
+
+#ifndef PROFILING_MODE
+ unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
+ unsigned long long sunow;
+#endif /* PROFILING_MODE */
+
+ unsigned long long counter = 1;
for(;1; counter++) {
- if(!update_from_proc()) {
- error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
+#ifndef PROFILING_MODE
+ // delay until it is our time to run
+ while((sunow = sutime()) < sunext)
+ usleep((useconds_t)(sunext - sunow));
+
+ // find the next time we need to run
+ while(sutime() > 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);
}
- update_statistics();
- show_charts(); // this is smart enough to show only newly added apps, when needed
- show_dimensions();
+ calculate_netdata_statistics();
- if(debug) fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
- fflush(NULL);
+ unsigned long long dt = send_resource_usage_to_netdata();
- gettimeofday(&now, NULL);
- usec = usecdiff(&now, &last) - susec;
- if(debug) fprintf(stderr, "apps.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).\n", usec + susec, usec, susec);
+ // 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");
- // if the last loop took less than half the time
- // wait the rest of the time
- if(usec < (update_every * 1000000ULL / 2)) susec = (update_every * 1000000ULL) - usec;
- else susec = update_every * 1000000ULL / 2;
+ 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);
- usleep((__useconds_t) susec);
- bcopy(&now, &last, sizeof(struct timeval));
+ if(debug) fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
+ fflush(NULL);
- // restart once per day (14400 seconds)
current_t = time(NULL);
+
+#ifndef PROFILING_MODE
+ // restart check (14400 seconds)
if(current_t - started_t > 14400) exit(0);
+#else
+ if(current_t - started_t > 10) exit(0);
+#endif /* PROFILING_MODE */
}
}
diff --git a/src/avl.c b/src/avl.c
index 4eb0ce0e4..fd4fb1420 100755..100644
--- a/src/avl.c
+++ b/src/avl.c
@@ -17,6 +17,7 @@
#include <config.h>
#endif
#include "avl.h"
+#include "log.h"
/* Private methods */
int _avl_removeroot(avl_tree* t);
@@ -144,19 +145,23 @@ int _avl_insert(avl_tree* t, avl* a) {
}
}
int avl_insert(avl_tree* t, avl* a) {
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_lock(&t->mutex);
#else
pthread_rwlock_wrlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
int ret = _avl_insert(t, a);
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_unlock(&t->mutex);
#else
pthread_rwlock_unlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
return ret;
}
@@ -242,19 +247,23 @@ int _avl_remove(avl_tree* t, avl* a) {
}
int avl_remove(avl_tree* t, avl* a) {
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_lock(&t->mutex);
#else
pthread_rwlock_wrlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
int ret = _avl_remove(t, a);
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_unlock(&t->mutex);
#else
pthread_rwlock_unlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
return ret;
}
@@ -298,19 +307,23 @@ int _avl_removeroot(avl_tree* t) {
}
int avl_removeroot(avl_tree* t) {
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_lock(&t->mutex);
#else
pthread_rwlock_wrlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
int ret = _avl_removeroot(t);
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_unlock(&t->mutex);
#else
pthread_rwlock_unlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
return ret;
}
@@ -362,19 +375,23 @@ int _avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
}
int avl_range(avl_tree* t, avl* a, avl* b, int (*iter)(avl*), avl** ret) {
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_lock(&t->mutex);
#else
pthread_rwlock_wrlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
int ret2 = _avl_range(t, a, b, iter, ret);
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_unlock(&t->mutex);
#else
pthread_rwlock_unlock(&t->rwlock);
#endif
+#endif /* AVL_WITHOUT_PTHREADS */
return ret2;
}
@@ -390,9 +407,19 @@ int avl_search(avl_tree* t, avl* a, int (*iter)(avl* a), avl** ret) {
void avl_init(avl_tree* t, int (*compar)(void* a, void* b)) {
t->root = NULL;
t->compar = compar;
+
+#ifndef AVL_WITHOUT_PTHREADS
+ int lock;
+
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_init(&t->mutex, NULL);
+ lock = pthread_mutex_init(&t->mutex, NULL);
#else
- 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);
+
+#endif /* AVL_WITHOUT_PTHREADS */
+
}
diff --git a/src/avl.h b/src/avl.h
index cbcc41211..2d1fbc537 100755..100644
--- a/src/avl.h
+++ b/src/avl.h
@@ -15,7 +15,9 @@
#ifndef _AVL_H
#define _AVL_H 1
+#ifndef AVL_WITHOUT_PTHREADS
#include <pthread.h>
+#endif /* AVL_WITHOUT_PTHREADS */
// #define AVL_LOCK_WITH_MUTEX 1
@@ -33,11 +35,13 @@ typedef struct avl_tree {
avl* root;
int (*compar)(void* a, void* b);
+#ifndef AVL_WITHOUT_PTHREADS
#ifdef AVL_LOCK_WITH_MUTEX
pthread_mutex_t mutex;
-#else
+#else /* AVL_LOCK_WITH_MUTEX */
pthread_rwlock_t rwlock;
-#endif
+#endif /* AVL_LOCK_WITH_MUTEX */
+#endif /* AVL_WITHOUT_PTHREADS */
} avl_tree;
/* Public methods */
diff --git a/src/common.c b/src/common.c
index e3c3afe3f..cb74b6335 100755..100644
--- a/src/common.c
+++ b/src/common.c
@@ -15,10 +15,276 @@
#include "log.h"
#include "common.h"
#include "appconfig.h"
+#include "../config.h"
char *global_host_prefix = "";
int enable_ksm = 1;
+unsigned char netdata_keys_map[256] = {
+ [0] = '\0', //
+ [1] = '_', //
+ [2] = '_', //
+ [3] = '_', //
+ [4] = '_', //
+ [5] = '_', //
+ [6] = '_', //
+ [7] = '_', //
+ [8] = '_', //
+ [9] = '_', //
+ [10] = '_', //
+ [11] = '_', //
+ [12] = '_', //
+ [13] = '_', //
+ [14] = '_', //
+ [15] = '_', //
+ [16] = '_', //
+ [17] = '_', //
+ [18] = '_', //
+ [19] = '_', //
+ [20] = '_', //
+ [21] = '_', //
+ [22] = '_', //
+ [23] = '_', //
+ [24] = '_', //
+ [25] = '_', //
+ [26] = '_', //
+ [27] = '_', //
+ [28] = '_', //
+ [29] = '_', //
+ [30] = '_', //
+ [31] = '_', //
+ [32] = '_', //
+ [33] = '_', // !
+ [34] = '_', // "
+ [35] = '_', // #
+ [36] = '_', // $
+ [37] = '_', // %
+ [38] = '_', // &
+ [39] = '_', // '
+ [40] = '_', // (
+ [41] = '_', // )
+ [42] = '_', // *
+ [43] = '_', // +
+ [44] = '.', // ,
+ [45] = '-', // -
+ [46] = '.', // .
+ [47] = '/', // /
+ [48] = '0', // 0
+ [49] = '1', // 1
+ [50] = '2', // 2
+ [51] = '3', // 3
+ [52] = '4', // 4
+ [53] = '5', // 5
+ [54] = '6', // 6
+ [55] = '7', // 7
+ [56] = '8', // 8
+ [57] = '9', // 9
+ [58] = '_', // :
+ [59] = '_', // ;
+ [60] = '_', // <
+ [61] = '_', // =
+ [62] = '_', // >
+ [63] = '_', // ?
+ [64] = '_', // @
+ [65] = 'a', // A
+ [66] = 'b', // B
+ [67] = 'c', // C
+ [68] = 'd', // D
+ [69] = 'e', // E
+ [70] = 'f', // F
+ [71] = 'g', // G
+ [72] = 'h', // H
+ [73] = 'i', // I
+ [74] = 'j', // J
+ [75] = 'k', // K
+ [76] = 'l', // L
+ [77] = 'm', // M
+ [78] = 'n', // N
+ [79] = 'o', // O
+ [80] = 'p', // P
+ [81] = 'q', // Q
+ [82] = 'r', // R
+ [83] = 's', // S
+ [84] = 't', // T
+ [85] = 'u', // U
+ [86] = 'v', // V
+ [87] = 'w', // W
+ [88] = 'x', // X
+ [89] = 'y', // Y
+ [90] = 'z', // Z
+ [91] = '_', // [
+ [92] = '/', // backslash
+ [93] = '_', // ]
+ [94] = '_', // ^
+ [95] = '_', // _
+ [96] = '_', // `
+ [97] = 'a', // a
+ [98] = 'b', // b
+ [99] = 'c', // c
+ [100] = 'd', // d
+ [101] = 'e', // e
+ [102] = 'f', // f
+ [103] = 'g', // g
+ [104] = 'h', // h
+ [105] = 'i', // i
+ [106] = 'j', // j
+ [107] = 'k', // k
+ [108] = 'l', // l
+ [109] = 'm', // m
+ [110] = 'n', // n
+ [111] = 'o', // o
+ [112] = 'p', // p
+ [113] = 'q', // q
+ [114] = 'r', // r
+ [115] = 's', // s
+ [116] = 't', // t
+ [117] = 'u', // u
+ [118] = 'v', // v
+ [119] = 'w', // w
+ [120] = 'x', // x
+ [121] = 'y', // y
+ [122] = 'z', // z
+ [123] = '_', // {
+ [124] = '_', // |
+ [125] = '_', // }
+ [126] = '_', // ~
+ [127] = '_', //
+ [128] = '_', //
+ [129] = '_', //
+ [130] = '_', //
+ [131] = '_', //
+ [132] = '_', //
+ [133] = '_', //
+ [134] = '_', //
+ [135] = '_', //
+ [136] = '_', //
+ [137] = '_', //
+ [138] = '_', //
+ [139] = '_', //
+ [140] = '_', //
+ [141] = '_', //
+ [142] = '_', //
+ [143] = '_', //
+ [144] = '_', //
+ [145] = '_', //
+ [146] = '_', //
+ [147] = '_', //
+ [148] = '_', //
+ [149] = '_', //
+ [150] = '_', //
+ [151] = '_', //
+ [152] = '_', //
+ [153] = '_', //
+ [154] = '_', //
+ [155] = '_', //
+ [156] = '_', //
+ [157] = '_', //
+ [158] = '_', //
+ [159] = '_', //
+ [160] = '_', //
+ [161] = '_', //
+ [162] = '_', //
+ [163] = '_', //
+ [164] = '_', //
+ [165] = '_', //
+ [166] = '_', //
+ [167] = '_', //
+ [168] = '_', //
+ [169] = '_', //
+ [170] = '_', //
+ [171] = '_', //
+ [172] = '_', //
+ [173] = '_', //
+ [174] = '_', //
+ [175] = '_', //
+ [176] = '_', //
+ [177] = '_', //
+ [178] = '_', //
+ [179] = '_', //
+ [180] = '_', //
+ [181] = '_', //
+ [182] = '_', //
+ [183] = '_', //
+ [184] = '_', //
+ [185] = '_', //
+ [186] = '_', //
+ [187] = '_', //
+ [188] = '_', //
+ [189] = '_', //
+ [190] = '_', //
+ [191] = '_', //
+ [192] = '_', //
+ [193] = '_', //
+ [194] = '_', //
+ [195] = '_', //
+ [196] = '_', //
+ [197] = '_', //
+ [198] = '_', //
+ [199] = '_', //
+ [200] = '_', //
+ [201] = '_', //
+ [202] = '_', //
+ [203] = '_', //
+ [204] = '_', //
+ [205] = '_', //
+ [206] = '_', //
+ [207] = '_', //
+ [208] = '_', //
+ [209] = '_', //
+ [210] = '_', //
+ [211] = '_', //
+ [212] = '_', //
+ [213] = '_', //
+ [214] = '_', //
+ [215] = '_', //
+ [216] = '_', //
+ [217] = '_', //
+ [218] = '_', //
+ [219] = '_', //
+ [220] = '_', //
+ [221] = '_', //
+ [222] = '_', //
+ [223] = '_', //
+ [224] = '_', //
+ [225] = '_', //
+ [226] = '_', //
+ [227] = '_', //
+ [228] = '_', //
+ [229] = '_', //
+ [230] = '_', //
+ [231] = '_', //
+ [232] = '_', //
+ [233] = '_', //
+ [234] = '_', //
+ [235] = '_', //
+ [236] = '_', //
+ [237] = '_', //
+ [238] = '_', //
+ [239] = '_', //
+ [240] = '_', //
+ [241] = '_', //
+ [242] = '_', //
+ [243] = '_', //
+ [244] = '_', //
+ [245] = '_', //
+ [246] = '_', //
+ [247] = '_', //
+ [248] = '_', //
+ [249] = '_', //
+ [250] = '_', //
+ [251] = '_', //
+ [252] = '_', //
+ [253] = '_', //
+ [254] = '_', //
+ [255] = '_' //
+};
+
+// make sure the supplied string
+// is good for a netdata chart/dimension ID/NAME
+void netdata_fix_id(char *s) {
+ while((*s = netdata_keys_map[(unsigned char)*s])) s++;
+}
+
/*
// http://stackoverflow.com/questions/7666509/hash-function-for-string
uint32_t simple_hash(const char *name)
diff --git a/src/common.h b/src/common.h
index 9d8836f8b..e9987af72 100755..100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,3 +1,6 @@
+#include <sys/time.h>
+#include <sys/resource.h>
+
#ifndef NETDATA_COMMON_H
#define NETDATA_COMMON_H 1
@@ -12,6 +15,8 @@
#define abs(x) ((x < 0)? -x : x)
#define usecdiff(now, last) (((((now)->tv_sec * 1000000ULL) + (now)->tv_usec) - (((last)->tv_sec * 1000000ULL) + (last)->tv_usec)))
+extern void netdata_fix_id(char *s);
+
extern uint32_t simple_hash(const char *name);
extern void strreverse(char* begin, char* end);
extern char *mystrsep(char **ptr, char *s);
@@ -32,4 +37,11 @@ extern void get_HZ(void);
extern pid_t gettid(void);
+/* fix for alpine linux */
+#ifndef RUSAGE_THREAD
+#ifdef RUSAGE_CHILDREN
+#define RUSAGE_THREAD RUSAGE_CHILDREN
+#endif
+#endif
+
#endif /* NETDATA_COMMON_H */
diff --git a/src/daemon.c b/src/daemon.c
index 268814798..9dcf32f0b 100755..100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -13,7 +13,6 @@
#include <pthread.h>
#include <sys/wait.h>
#include <sys/stat.h>
-#include <execinfo.h>
#include "common.h"
#include "appconfig.h"
@@ -25,6 +24,9 @@
#include "main.h"
#include "daemon.h"
+char pidfile[FILENAME_MAX + 1] = "";
+int pidfd = -1;
+
void sig_handler(int signo)
{
switch(signo) {
@@ -72,23 +74,6 @@ void sig_handler(int signo)
}
}
-char rundir[FILENAME_MAX + 1] = "/var/run/netdata";
-char pidfile[FILENAME_MAX + 1] = "";
-void prepare_rundir() {
- if(getuid() != 0) {
- mkdir("/run/user", 0775);
- snprintf(rundir, FILENAME_MAX, "/run/user/%d", getuid());
- mkdir(rundir, 0775);
- snprintf(rundir, FILENAME_MAX, "/run/user/%d/netdata", getuid());
- }
-
- snprintf(pidfile, FILENAME_MAX, "%s/netdata.pid", rundir);
-
- if(mkdir(rundir, 0775) != 0) {
- if(errno != EEXIST) error("Cannot create directory '%s'.", rundir);
- }
-}
-
int become_user(const char *username)
{
struct passwd *pw = getpwnam(username);
@@ -97,35 +82,50 @@ int become_user(const char *username)
return -1;
}
- if(chown(rundir, pw->pw_uid, pw->pw_gid) != 0) {
- error("Cannot chown directory '%s' to user %s.", rundir, username);
- return -1;
+ uid_t uid = pw->pw_uid;
+ gid_t gid = pw->pw_gid;
+
+ if(pidfile[0] && getuid() != uid) {
+ // we are dropping privileges
+ if(chown(pidfile, uid, gid) != 0)
+ error("Cannot chown pidfile '%s' to user '%s'", pidfile, username);
+
+ else if(pidfd != -1) {
+ // not need to keep it open
+ close(pidfd);
+ pidfd = -1;
+ }
+ }
+ else if(pidfd != -1) {
+ // not need to keep it open
+ close(pidfd);
+ pidfd = -1;
}
- if(setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
- error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setresgid(gid, gid, gid) != 0) {
+ error("Cannot switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
- error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(setresuid(uid, uid, uid) != 0) {
+ error("Cannot switch to user %s (uid: %d).", username, uid);
return -1;
}
- if(setgid(pw->pw_gid) != 0) {
- error("Cannot switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setgid(gid) != 0) {
+ error("Cannot switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setegid(pw->pw_gid) != 0) {
- error("Cannot effectively switch to user's %s group (gid: %d).", username, pw->pw_gid);
+ if(setegid(gid) != 0) {
+ error("Cannot effectively switch to user's %s group (gid: %d).", username, gid);
return -1;
}
- if(setuid(pw->pw_uid) != 0) {
- error("Cannot switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(setuid(uid) != 0) {
+ error("Cannot switch to user %s (uid: %d).", username, uid);
return -1;
}
- if(seteuid(pw->pw_uid) != 0) {
- error("Cannot effectively switch to user %s (uid: %d).", username, pw->pw_uid);
+ if(seteuid(uid) != 0) {
+ error("Cannot effectively switch to user %s (uid: %d).", username, uid);
return -1;
}
@@ -294,16 +294,22 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
close(dev_null);
// generate our pid file
- {
- unlink(pidfile);
- int fd = open(pidfile, O_RDWR | O_CREAT, 0666);
- if(fd >= 0) {
+ if(pidfile[0]) {
+ pidfd = open(pidfile, O_RDWR | 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(fd, b, strlen(b));
- if(i <= 0) perror("Cannot write pid to file.");
- close(fd);
+ ssize_t i = write(pidfd, b, strlen(b));
+ if(i <= 0)
+ error("Cannot write pidfile '%s'.", pidfile);
+
+ // don't close it, we might need it at exit
+ // close(pidfd);
}
+ else error("Failed to open pidfile '%s'.", pidfile);
}
if(user && *user) {
@@ -312,6 +318,8 @@ int become_daemon(int dont_fork, int close_all_files, const char *user, const ch
}
else info("Successfully became user '%s'.", user);
}
+ else if(pidfd != -1)
+ close(pidfd);
return(0);
}
diff --git a/src/daemon.h b/src/daemon.h
index 77186daae..0642be3c0 100755..100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -3,12 +3,13 @@
extern void sig_handler(int signo);
-extern void prepare_rundir();
-
extern int become_user(const char *username);
extern int become_daemon(int dont_fork, int close_all_files, const char *user, const char *input, const char *output, const char *error, const char *access, int *access_fd, FILE **access_fp);
extern void netdata_cleanup_and_exit(int i);
+extern char pidfile[];
+extern int pidfd;
+
#endif /* NETDATA_DAEMON_H */
diff --git a/src/dictionary.c b/src/dictionary.c
index 31f4d52e1..31f4d52e1 100755..100644
--- a/src/dictionary.c
+++ b/src/dictionary.c
diff --git a/src/dictionary.h b/src/dictionary.h
index 9822b23c2..9822b23c2 100755..100644
--- a/src/dictionary.h
+++ b/src/dictionary.h
diff --git a/src/global_statistics.c b/src/global_statistics.c
index d4a04efd2..d4a04efd2 100755..100644
--- a/src/global_statistics.c
+++ b/src/global_statistics.c
diff --git a/src/global_statistics.h b/src/global_statistics.h
index ce3c3490e..ce3c3490e 100755..100644
--- a/src/global_statistics.h
+++ b/src/global_statistics.h
diff --git a/src/log.c b/src/log.c
index 7ab3f1a51..e5e0ad2c4 100755..100644
--- a/src/log.c
+++ b/src/log.c
@@ -27,6 +27,85 @@ int access_log_syslog = 1;
int error_log_syslog = 1;
int output_log_syslog = 1; // debug log
+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;
+}
+
void log_date(FILE *out)
{
char outstr[200];
@@ -64,6 +143,9 @@ void info_int( const char *file, const char *function, const unsigned long line,
{
va_list args;
+ // prevent logging too much
+ if(error_log_limit(0)) return;
+
log_date(stderr);
va_start( args, fmt );
@@ -85,6 +167,9 @@ void error_int( const char *prefix, const char *file, const char *function, cons
{
va_list args;
+ // prevent logging too much
+ if(error_log_limit(0)) return;
+
log_date(stderr);
va_start( args, fmt );
@@ -143,9 +228,7 @@ void log_access( const char *fmt, ... )
vfprintf( stdaccess, fmt, args );
va_end( args );
fprintf( stdaccess, "\n");
-#ifdef NETDATA_INTERNAL_CHECKS
fflush( stdaccess );
-#endif
}
if(access_log_syslog) {
diff --git a/src/log.h b/src/log.h
index 08f3c4fe3..e882af386 100755..100644
--- a/src/log.h
+++ b/src/log.h
@@ -42,6 +42,12 @@ extern int access_log_syslog;
extern int error_log_syslog;
extern int output_log_syslog;
+extern time_t error_log_throttle_period;
+extern unsigned long error_log_errors_per_period;
+extern int error_log_limit(int reset);
+
+#define error_log_limit_reset() do { error_log_limit(1); } while(0)
+
#define debug(type, args...) do { if(unlikely(!silent && (debug_flags & type))) debug_int(__FILE__, __FUNCTION__, __LINE__, ##args); } while(0)
#define info(args...) info_int(__FILE__, __FUNCTION__, __LINE__, ##args)
#define infoerr(args...) error_int("INFO", __FILE__, __FUNCTION__, __LINE__, ##args)
diff --git a/src/main.c b/src/main.c
index a29757358..ad24debfa 100755..100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,6 +14,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
+#include <sys/prctl.h>
#include "common.h"
#include "log.h"
@@ -35,6 +36,7 @@
#include "plugin_nfacct.h"
#include "main.h"
+#include "../config.h"
int netdata_exit = 0;
@@ -43,7 +45,23 @@ void netdata_cleanup_and_exit(int ret)
netdata_exit = 1;
rrdset_save_all();
// kill_childs();
- unlink("/var/run/netdata.pid");
+
+ // let it log a few more error messages
+ error_log_limit_reset();
+
+ if(pidfd != -1) {
+ if(ftruncate(pidfd, 0) != 0)
+ error("Cannot truncate pidfile '%s'.", pidfile);
+
+ close(pidfd);
+ pidfd = -1;
+ }
+
+ if(pidfile[0]) {
+ if(unlink(pidfile) != 0)
+ error("Cannot unlink pidfile '%s'.", pidfile);
+ }
+
info("NetData exiting. Bye bye...");
exit(ret);
}
@@ -189,6 +207,8 @@ int main(int argc, char **argv)
int i;
int config_loaded = 0;
int dont_fork = 0;
+ size_t wanted_stacksize = 0, stacksize = 0;
+ pthread_attr_t attr;
// global initialization
get_HZ();
@@ -215,7 +235,13 @@ int main(int argc, char **argv)
else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) { config_set("global", "history", argv[i+1]); i++; }
else if(strcmp(argv[i], "-t") == 0 && (i+1) < argc) { config_set("global", "update every", argv[i+1]); i++; }
else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { config_set("global", "host access prefix", argv[i+1]); i++; }
- else if(strcmp(argv[i], "-nodeamon") == 0 || strcmp(argv[i], "-nd") == 0) dont_fork = 1;
+ else if(strcmp(argv[i], "-stacksize") == 0 && (i+1) < argc) { config_set("global", "pthread stack size", argv[i+1]); i++; }
+ else if(strcmp(argv[i], "-nodaemon") == 0 || strcmp(argv[i], "-nd") == 0) dont_fork = 1;
+ else if(strcmp(argv[i], "-pidfile") == 0 && (i+1) < argc) {
+ i++;
+ strncpy(pidfile, argv[i], FILENAME_MAX);
+ pidfile[FILENAME_MAX] = '\0';
+ }
else if(strcmp(argv[i], "--unittest") == 0) {
rrd_update_every = 1;
if(run_all_mockup_tests()) exit(1);
@@ -225,7 +251,7 @@ int main(int argc, char **argv)
}
else {
fprintf(stderr, "Cannot understand option '%s'.\n", argv[i]);
- fprintf(stderr, "\nUSAGE: %s [-d] [-l LINES_TO_SAVE] [-u UPDATE_TIMER] [-p LISTEN_PORT] [-dl debug log file] [-df debug flags].\n\n", argv[0]);
+ fprintf(stderr, "\nUSAGE: %s [-d] [-l LINES_TO_SAVE] [-u UPDATE_TIMER] [-p LISTEN_PORT] [-df debug flags].\n\n", argv[0]);
fprintf(stderr, " -c CONFIG FILE the configuration file to load. Default: %s.\n", CONFIG_DIR "/" CONFIG_FILENAME);
fprintf(stderr, " -l LINES_TO_SAVE can be from 5 to %d lines in JSON data. Default: %d.\n", RRD_HISTORY_ENTRIES_MAX, RRD_DEFAULT_HISTORY_ENTRIES);
fprintf(stderr, " -t UPDATE_TIMER can be from 1 to %d seconds. Default: %d.\n", UPDATE_EVERY_MAX, UPDATE_EVERY);
@@ -234,6 +260,8 @@ int main(int argc, char **argv)
fprintf(stderr, " -ch path to access host /proc and /sys when running in a container. Default: empty.\n");
fprintf(stderr, " -nd or -nodeamon to disable forking in the background. Default: unset.\n");
fprintf(stderr, " -df FLAGS debug options. Default: 0x%08llx.\n", debug_flags);
+ fprintf(stderr, " -stacksize BYTES to overwrite the pthread stack size.\n");
+ fprintf(stderr, " -pidfile FILENAME to save a pid while running.\n");
exit(1);
}
}
@@ -276,6 +304,7 @@ int main(int argc, char **argv)
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);
}
// --------------------------------------------------------------------
@@ -319,6 +348,12 @@ int main(int argc, char **argv)
}
else error_log_syslog = 0;
+ error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
+ setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
+
+ error_log_errors_per_period = config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
+ setenv("NETDATA_ERRORS_PER_PERIOD" , config_get("global", "errors to trigger flood protection", ""), 1);
+
// --------------------------------------------------------------------
access_log_file = config_get("global", "access log", LOG_DIR "/access.log");
@@ -347,7 +382,7 @@ int main(int argc, char **argv)
rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
- fprintf(stderr, "Invalid save lines %d given. Defaulting to %d.\n", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
+ info("Invalid save lines %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
}
else {
@@ -358,7 +393,7 @@ int main(int argc, char **argv)
rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
if(rrd_update_every < 1 || rrd_update_every > 600) {
- fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", rrd_update_every, UPDATE_EVERY_MAX);
+ info("Invalid update timer %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
rrd_update_every = UPDATE_EVERY;
}
else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);
@@ -372,6 +407,20 @@ int main(int argc, char **argv)
// --------------------------------------------------------------------
+ i = pthread_attr_init(&attr);
+ if(i != 0)
+ fatal("pthread_attr_init() failed with code %d.", i);
+
+ i = pthread_attr_getstacksize(&attr, &stacksize);
+ if(i != 0)
+ fatal("pthread_attr_getstacksize() failed with code %d.", i);
+ else
+ debug(D_OPTIONS, "initial pthread stack size is %zu bytes", stacksize);
+
+ wanted_stacksize = config_get_number("global", "pthread stack size", stacksize);
+
+ // --------------------------------------------------------------------
+
for (i = 0; static_threads[i].name != NULL ; i++) {
struct netdata_static_thread *st = &static_threads[i];
@@ -381,9 +430,13 @@ int main(int argc, char **argv)
// --------------------------------------------------------------------
- prepare_rundir();
+ // get the user we should run
+ // IMPORTANT: this is required before web_files_uid()
user = config_get("global", "run as user" , (getuid() == 0)?NETDATA_USER:"");
- web_files_uid();
+
+ // IMPORTANT: these have to run once, while single threaded
+ web_files_uid(); // IMPORTANT: web_files_uid() before web_files_gid()
+ web_files_gid();
// --------------------------------------------------------------------
@@ -391,7 +444,7 @@ int main(int argc, char **argv)
listen_port = (int) config_get_number("global", "port", LISTEN_PORT);
if(listen_port < 1 || listen_port > 65535) {
- fprintf(stderr, "Invalid listen port %d given. Defaulting to %d.\n", listen_port, LISTEN_PORT);
+ info("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
listen_port = LISTEN_PORT;
}
else debug(D_OPTIONS, "Listen port set to %d.", listen_port);
@@ -401,12 +454,12 @@ int main(int argc, char **argv)
if(!strcmp(ipv, "any") || !strcmp(ipv, "both") || !strcmp(ipv, "all")) ip = 0;
else if(!strcmp(ipv, "ipv4") || !strcmp(ipv, "IPV4") || !strcmp(ipv, "IPv4") || !strcmp(ipv, "4")) ip = 4;
else if(!strcmp(ipv, "ipv6") || !strcmp(ipv, "IPV6") || !strcmp(ipv, "IPv6") || !strcmp(ipv, "6")) ip = 6;
- else fprintf(stderr, "Cannot understand ip version '%s'. Assumming 'any'.", ipv);
+ else info("Cannot understand ip version '%s'. Assuming 'any'.", ipv);
- if(ip == 0 || ip == 6) listen_fd = create_listen_socket6(listen_port, listen_backlog);
+ if(ip == 0 || ip == 6) listen_fd = create_listen_socket6(config_get("global", "bind socket to IP", "*"), listen_port, listen_backlog);
if(listen_fd < 0) {
- listen_fd = create_listen_socket4(listen_port, listen_backlog);
- if(listen_fd >= 0 && ip != 4) fprintf(stderr, "Managed to open an IPv4 socket on port %d.", listen_port);
+ listen_fd = create_listen_socket4(config_get("global", "bind socket to IP", "*"), listen_port, listen_backlog);
+ if(listen_fd >= 0 && ip != 4) info("Managed to open an IPv4 socket on port %d.", listen_port);
}
if(listen_fd < 0) fatal("Cannot listen socket.");
@@ -420,6 +473,14 @@ int main(int argc, char **argv)
exit(1);
}
+ 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(output_log_syslog || error_log_syslog || access_log_syslog)
openlog("netdata", LOG_PID, LOG_DAEMON);
@@ -445,15 +506,31 @@ int main(int argc, char **argv)
}
}
+ // ------------------------------------------------------------------------
+ // get default pthread stack size
+
+ if(stacksize < wanted_stacksize) {
+ i = pthread_attr_setstacksize(&attr, wanted_stacksize);
+ if(i != 0)
+ fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i);
+ else
+ info("Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
+ }
+
+ // ------------------------------------------------------------------------
+ // spawn the threads
+
for (i = 0; static_threads[i].name != NULL ; i++) {
struct netdata_static_thread *st = &static_threads[i];
if(st->enabled) {
st->thread = malloc(sizeof(pthread_t));
+ if(!st->thread)
+ fatal("Cannot allocate pthread_t memory");
info("Starting thread %s.", st->name);
- if(pthread_create(st->thread, NULL, st->start_routine, NULL))
+ if(pthread_create(st->thread, &attr, st->start_routine, NULL))
error("failed to create new thread for %s.", st->name);
else if(pthread_detach(*st->thread))
diff --git a/src/main.h b/src/main.h
index 6a90efd9d..6a90efd9d 100755..100644
--- a/src/main.h
+++ b/src/main.h
diff --git a/src/plugin_checks.c b/src/plugin_checks.c
index 379fb9a84..379fb9a84 100755..100644
--- a/src/plugin_checks.c
+++ b/src/plugin_checks.c
diff --git a/src/plugin_checks.h b/src/plugin_checks.h
index c27685b84..c27685b84 100755..100644
--- a/src/plugin_checks.h
+++ b/src/plugin_checks.h
diff --git a/src/plugin_idlejitter.c b/src/plugin_idlejitter.c
index 56c22a160..56c22a160 100755..100644
--- a/src/plugin_idlejitter.c
+++ b/src/plugin_idlejitter.c
diff --git a/src/plugin_idlejitter.h b/src/plugin_idlejitter.h
index dc82f052f..dc82f052f 100755..100644
--- a/src/plugin_idlejitter.h
+++ b/src/plugin_idlejitter.h
diff --git a/src/plugin_nfacct.c b/src/plugin_nfacct.c
index 0c5b39457..6cde66e0c 100644
--- a/src/plugin_nfacct.c
+++ b/src/plugin_nfacct.c
@@ -16,6 +16,7 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_acct/libnetfilter_acct.h>
+#include "main.h"
#include "global_statistics.h"
#include "common.h"
#include "appconfig.h"
@@ -167,9 +168,9 @@ void *nfacct_main(void *ptr) {
if(nfacct_list && nfacct_list->len) {
int i;
- st = rrdset_find_bytype("nfacct", "packets");
+ st = rrdset_find_bytype("netfilter", "nfacct_packets");
if(!st) {
- st = rrdset_create("nfacct", "packets", NULL, "netfilter", "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
+ 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);
@@ -187,9 +188,9 @@ void *nfacct_main(void *ptr) {
// ----------------------------------------------------------------
- st = rrdset_find_bytype("nfacct", "bytes");
+ st = rrdset_find_bytype("netfilter", "nfacct_bytes");
if(!st) {
- st = rrdset_create("nfacct", "bytes", NULL, "netfilter", "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
+ 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);
diff --git a/src/plugin_nfacct.h b/src/plugin_nfacct.h
index 88a3a9230..88a3a9230 100755..100644
--- a/src/plugin_nfacct.h
+++ b/src/plugin_nfacct.h
diff --git a/src/plugin_proc.c b/src/plugin_proc.c
index af679de1e..4cd20afc5 100755..100644
--- a/src/plugin_proc.c
+++ b/src/plugin_proc.c
@@ -43,9 +43,11 @@ void *proc_main(void *ptr)
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);
@@ -61,9 +63,11 @@ void *proc_main(void *ptr)
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;
@@ -160,6 +164,14 @@ void *proc_main(void *ptr)
}
if(unlikely(netdata_exit)) break;
+ if(!vdo_proc_net_snmp6) {
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
+ sunow = sutime();
+ 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 = sutime();
@@ -184,6 +196,14 @@ void *proc_main(void *ptr)
}
if(unlikely(netdata_exit)) break;
+ if(!vdo_proc_net_stat_synproxy) {
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
+ sunow = sutime();
+ 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 = sutime();
diff --git a/src/plugin_proc.h b/src/plugin_proc.h
index 28b8c59ef..a512e1cdf 100755..100644
--- a/src/plugin_proc.h
+++ b/src/plugin_proc.h
@@ -6,6 +6,7 @@ void *proc_main(void *ptr);
extern int do_proc_net_dev(int update_every, unsigned long long dt);
extern int do_proc_diskstats(int update_every, unsigned long long dt);
extern int do_proc_net_snmp(int update_every, unsigned long long dt);
+extern int do_proc_net_snmp6(int update_every, unsigned long long dt);
extern int do_proc_net_netstat(int update_every, unsigned long long dt);
extern int do_proc_net_stat_conntrack(int update_every, unsigned long long dt);
extern int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt);
@@ -18,5 +19,6 @@ extern int do_proc_interrupts(int update_every, unsigned long long dt);
extern int do_proc_softirqs(int update_every, unsigned long long dt);
extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
extern int do_proc_loadavg(int update_every, unsigned long long dt);
+extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
#endif /* NETDATA_PLUGIN_PROC_H */
diff --git a/src/plugin_tc.c b/src/plugin_tc.c
index f02b70788..2c7a55cee 100755..100644
--- a/src/plugin_tc.c
+++ b/src/plugin_tc.c
@@ -15,6 +15,7 @@
#include "popen.h"
#include "plugin_tc.h"
#include "main.h"
+#include "../config.h"
#define RRD_TYPE_TC "tc"
#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
@@ -346,11 +347,15 @@ static struct tc_device *tc_device_create(char *id)
d->classes_index.root = NULL;
d->classes_index.compar = tc_class_compare;
+
+ int lock;
#ifdef AVL_LOCK_WITH_MUTEX
- pthread_mutex_init(&d->classes_index.mutex, NULL);
+ lock = pthread_mutex_init(&d->classes_index.mutex, NULL);
#else
- pthread_rwlock_init(&d->classes_index.rwlock, NULL);
+ lock = pthread_rwlock_init(&d->classes_index.rwlock, NULL);
#endif
+ if(lock != 0)
+ fatal("Failed to initialize plugin_tc mutex/rwlock, return code %d.", lock);
tc_device_index_add(d);
@@ -713,7 +718,8 @@ void *tc_main(void *ptr)
// debug(D_TC_LOOP, "IGNORED line");
//}
}
- mypclose(fp, tc_child_pid);
+ // fgets() failed or loop broke
+ int code = mypclose(fp, tc_child_pid);
tc_child_pid = 0;
if(device) {
@@ -728,10 +734,19 @@ void *tc_main(void *ptr)
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;
}
-
diff --git a/src/plugin_tc.h b/src/plugin_tc.h
index c3abbddd0..c3abbddd0 100755..100644
--- a/src/plugin_tc.h
+++ b/src/plugin_tc.h
diff --git a/src/plugins_d.c b/src/plugins_d.c
index eb8f141b8..b8524d99c 100755..100644
--- a/src/plugins_d.c
+++ b/src/plugins_d.c
@@ -16,6 +16,7 @@
#include "rrd.h"
#include "popen.h"
#include "plugins_d.h"
+#include "../config.h"
struct plugind *pluginsd_root = NULL;
@@ -218,7 +219,7 @@ void *pluginsd_worker_thread(void *arg)
break;
}
- if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a END on chart %s", cd->fullfilename, st->id);
+ 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;
@@ -406,7 +407,7 @@ void *pluginsd_worker_thread(void *arg)
}
if(unlikely(!count && cd->enabled)) {
- error("PLUGINSD: '%s' (pid %d) does not generate usefull output. Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
+ error("PLUGINSD: '%s' (pid %d) does not generate useful output. Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
sleep((unsigned int) (cd->update_every * 10));
}
@@ -528,5 +529,3 @@ void *pluginsd_main(void *ptr)
pthread_exit(NULL);
return NULL;
}
-
-
diff --git a/src/plugins_d.h b/src/plugins_d.h
index 11e89e0ac..11e89e0ac 100755..100644
--- a/src/plugins_d.h
+++ b/src/plugins_d.h
diff --git a/src/popen.c b/src/popen.c
index 882a4cc5a..882a4cc5a 100755..100644
--- a/src/popen.c
+++ b/src/popen.c
diff --git a/src/popen.h b/src/popen.h
index 10680f0c8..10680f0c8 100755..100644
--- a/src/popen.h
+++ b/src/popen.h
diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c
index f404118fa..c2b84aae1 100755..100644
--- a/src/proc_diskstats.c
+++ b/src/proc_diskstats.c
@@ -4,6 +4,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "common.h"
#include "log.h"
@@ -14,6 +17,73 @@
#define RRD_TYPE_DISK "disk"
+struct disk {
+ unsigned long major;
+ unsigned long minor;
+ int partition_id; // -1 = this is not a partition
+ struct disk *next;
+} *disk_root = NULL;
+
+struct disk *get_disk(unsigned long major, unsigned long minor) {
+ static char path_find_block_device_partition[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;
+
+ if(unlikely(!path_find_block_device_partition[0])) {
+ char filename[FILENAME_MAX + 1];
+ snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/partition");
+ snprintf(path_find_block_device_partition, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device partition", filename));
+ }
+
+ // not found
+ // create a new disk structure
+ d = (struct disk *)malloc(sizeof(struct disk));
+ if(!d) fatal("Cannot allocate memory for struct disk in proc_diskstats.");
+
+ d->major = major;
+ d->minor = minor;
+ d->partition_id = -1;
+ 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 if it is a partition
+ // by reading /sys/dev/block/MAJOR:MINOR/partition
+ char buffer[FILENAME_MAX + 1];
+ snprintf(buffer, FILENAME_MAX, path_find_block_device_partition, major, minor);
+
+ int fd = open(buffer, O_RDONLY, 0666);
+ if(likely(fd != -1)) {
+ // we opened it
+ int bytes = read(fd, buffer, FILENAME_MAX);
+ close(fd);
+
+ if(bytes > 0)
+ d->partition_id = strtoul(buffer, NULL, 10);
+ }
+ // if the /partition file does not exist, it is a disk, not a partition
+
+ return d;
+}
+
int do_proc_diskstats(int update_every, unsigned long long dt) {
static procfile *ff = NULL;
static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
@@ -40,7 +110,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
if(!path_to_get_hw_sector_size[0]) {
char filename[FILENAME_MAX + 1];
snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
- snprintf(path_to_get_hw_sector_size, FILENAME_MAX, "%s%s", global_host_prefix, config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", filename));
+ snprintf(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", filename));
}
ff = procfile_readall(ff);
@@ -107,13 +177,19 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
// I/O completion time and the backlog that may be accumulating.
backlog_ms = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
-
int def_enabled = 0;
// remove slashes from disk names
char *s;
for(s = disk; *s ;s++) if(*s == '/') *s = '_';
+ struct disk *d = get_disk(major, minor);
+ if(d->partition_id == -1)
+ def_enabled = enable_new_disks;
+ else
+ def_enabled = 0;
+
+/*
switch(major) {
case 9: // MDs
case 43: // network block
@@ -123,6 +199,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
case 199: // veritas
case 201: // veritas
case 251: // dm
+ case 253: // virtio
def_enabled = enable_new_disks;
break;
@@ -195,8 +272,10 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
case 135: // scsi
case 153: // raid
case 202: // xen
+ case 254: // virtio3
case 256: // flash
case 257: // flash
+ case 259: // nvme0n1 issue #119
if(minor % 16) def_enabled = 0; // partitions
else def_enabled = enable_new_disks;
break;
@@ -230,6 +309,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
def_enabled = 0;
break;
}
+*/
int ddo_io = do_io, ddo_ops = do_ops, ddo_mops = do_mops, ddo_iotime = do_iotime, ddo_qops = do_qops, ddo_util = do_util, ddo_backlog = do_backlog;
diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c
index 25482dfa7..6704ef1a5 100755..100644
--- a/src/proc_interrupts.c
+++ b/src/proc_interrupts.c
@@ -25,10 +25,28 @@ struct interrupt {
unsigned long long total;
};
+static struct interrupt *alloc_interrupts(int lines) {
+ static struct interrupt *irrs = NULL;
+ static int alloced = 0;
+
+ if(lines < alloced) return irrs;
+ else {
+ irrs = (struct interrupt *)realloc(irrs, lines * sizeof(struct interrupt));
+ if(!irrs)
+ fatal("Cannot allocate memory for %d interrupts", lines);
+
+ alloced = lines;
+ }
+
+ 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);
@@ -46,6 +64,11 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
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;
@@ -63,7 +86,7 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
}
// allocate the size we need;
- struct interrupt irrs[lines];
+ irrs = alloc_interrupts(lines);
irrs[0].used = 0;
// loop through all lines
diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c
index cd7edc832..cd7edc832 100755..100644
--- a/src/proc_loadavg.c
+++ b/src/proc_loadavg.c
diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c
index dbd43369f..dbd43369f 100755..100644
--- a/src/proc_meminfo.c
+++ b/src/proc_meminfo.c
diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c
index 5070ab817..5070ab817 100755..100644
--- a/src/proc_net_dev.c
+++ b/src/proc_net_dev.c
diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c
index 8c2ece7d3..8c2ece7d3 100755..100644
--- a/src/proc_net_ip_vs_stats.c
+++ b/src/proc_net_ip_vs_stats.c
diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c
index 3f178a4a3..859cf9053 100755..100644
--- a/src/proc_net_netstat.c
+++ b/src/proc_net_netstat.c
@@ -16,12 +16,12 @@ 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("plugin:proc:/proc/net/netstat", "bandwidth", 1);
- if(do_inerrors == -1) do_inerrors = config_get_boolean("plugin:proc:/proc/net/netstat", "input errors", 1);
- if(do_mcast == -1) do_mcast = config_get_boolean("plugin:proc:/proc/net/netstat", "multicast bandwidth", 1);
- if(do_bcast == -1) do_bcast = config_get_boolean("plugin:proc:/proc/net/netstat", "broadcast bandwidth", 1);
- if(do_mcast_p == -1) do_mcast_p = config_get_boolean("plugin:proc:/proc/net/netstat", "multicast packets", 1);
- if(do_bcast_p == -1) do_bcast_p = config_get_boolean("plugin:proc:/proc/net/netstat", "broadcast packets", 1);
+ 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) {};
@@ -74,7 +74,8 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
- if(do_bandwidth) {
+ 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);
@@ -91,25 +92,27 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
- if(do_inerrors) {
+ 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, "trunkated", 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, "trunkated", InTruncatedPkts);
+ rrddim_set(st, "truncated", InTruncatedPkts);
rrdset_done(st);
}
// --------------------------------------------------------------------
- if(do_mcast) {
+ 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);
@@ -127,7 +130,8 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
- if(do_bcast) {
+ 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);
@@ -145,7 +149,8 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
- if(do_mcast_p) {
+ 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);
@@ -163,7 +168,8 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
- if(do_bcast_p) {
+ 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);
diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c
index efefbadce..742b4cfc7 100755..100644
--- a/src/proc_net_snmp.c
+++ b/src/proc_net_snmp.c
@@ -22,7 +22,7 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
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 fragrments sent", 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);
diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c
new file mode 100644
index 000000000..e7fadf573
--- /dev/null
+++ b/src/proc_net_snmp6.c
@@ -0,0 +1,1067 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "log.h"
+#include "appconfig.h"
+#include "procfile.h"
+#include "rrd.h"
+#include "plugin_proc.h"
+
+#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];
+ snprintf(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 %d. Expected 2 params, read %d.", 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;
+}
+
diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c
index 912c3eef0..f7e5c45b2 100755..100644
--- a/src/proc_net_stat_conntrack.c
+++ b/src/proc_net_stat_conntrack.c
@@ -12,7 +12,8 @@
#include "rrd.h"
#include "plugin_proc.h"
-#define RRD_TYPE_NET_STAT_CONNTRACK "netfilter"
+#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) {
@@ -97,9 +98,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_sockets) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".sockets");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
+ 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);
}
@@ -112,9 +113,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_new) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".new");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
+ 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);
@@ -131,9 +132,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_changes) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".changes");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
+ 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);
@@ -151,9 +152,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_expect) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".expect");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
+ 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);
@@ -171,9 +172,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_search) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".search");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
+ 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);
@@ -191,9 +192,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
// --------------------------------------------------------------------
if(do_errors) {
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".errors");
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
if(!st) {
- st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
+ 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);
diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c
new file mode 100644
index 000000000..62296d78a
--- /dev/null
+++ b/src/proc_net_stat_synproxy.c
@@ -0,0 +1,138 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "appconfig.h"
+#include "procfile.h"
+#include "rrd.h"
+#include "plugin_proc.h"
+#include "log.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)
+
+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;
+
+ 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(!ff) {
+ char filename[FILENAME_MAX + 1];
+ snprintf(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
+
+ // make sure we have 3 lines
+ unsigned long lines = procfile_lines(ff), l;
+ if(lines < 2) {
+ error("/proc/net/stat/synproxy has %d 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;
+
+ // 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);
+ }
+
+ unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
+
+ RRDSET *st;
+
+ // --------------------------------------------------------------------
+
+ 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);
+
+ rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
+ }
+ else rrdset_next(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;
+
+ 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_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;
+
+ 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_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;
+
+ 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_set(st, "valid", cookie_valid);
+ rrddim_set(st, "invalid", cookie_invalid);
+ rrddim_set(st, "retransmits", cookie_retrans);
+ rrdset_done(st);
+ }
+
+ return 0;
+}
diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c
index 9373baaec..c3a75f600 100755..100644
--- a/src/proc_softirqs.c
+++ b/src/proc_softirqs.c
@@ -25,10 +25,28 @@ struct interrupt {
unsigned long long total;
};
+static struct interrupt *alloc_interrupts(int lines) {
+ static struct interrupt *irrs = NULL;
+ static int alloced = 0;
+
+ if(lines < alloced) return irrs;
+ else {
+ irrs = (struct interrupt *)realloc(irrs, lines * sizeof(struct interrupt));
+ if(!irrs)
+ fatal("Cannot allocate memory for %d interrupts", lines);
+
+ alloced = lines;
+ }
+
+ 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;
+ 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);
@@ -46,6 +64,11 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
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;
@@ -63,7 +86,7 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
}
// allocate the size we need;
- struct interrupt irrs[lines];
+ irrs = alloc_interrupts(lines);
irrs[0].used = 0;
// loop through all lines
diff --git a/src/proc_stat.c b/src/proc_stat.c
index 3d090ed71..47f994b52 100755..100644
--- a/src/proc_stat.c
+++ b/src/proc_stat.c
@@ -47,8 +47,8 @@ int do_proc_stat(int update_every, unsigned long long dt) {
for(l = 0; l < lines ;l++) {
if(strncmp(procfile_lineword(ff, l, 0), "cpu", 3) == 0) {
words = procfile_linewords(ff, l);
- if(words < 10) {
- error("Cannot read /proc/stat cpu line. Expected 10 params, read %d.", words);
+ if(words < 9) {
+ error("Cannot read /proc/stat cpu line. Expected 9 params, read %d.", words);
continue;
}
@@ -64,7 +64,7 @@ int do_proc_stat(int update_every, unsigned long long dt) {
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);
+ if(words >= 10) guest = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
if(words >= 11) guest_nice = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
char *title = "Core utilization";
diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c
index be9070aca..be9070aca 100755..100644
--- a/src/proc_sys_kernel_random_entropy_avail.c
+++ b/src/proc_sys_kernel_random_entropy_avail.c
diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c
index 46ddbae7f..c8222390c 100755..100644
--- a/src/proc_vmstat.c
+++ b/src/proc_vmstat.c
@@ -13,9 +13,6 @@
#include "rrd.h"
#include "plugin_proc.h"
-#define MAX_PROC_VMSTAT_LINE 4096
-#define MAX_PROC_VMSTAT_NAME 1024
-
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;
diff --git a/src/procfile.c b/src/procfile.c
index 7a4857959..1fc33ef5f 100755..100644
--- a/src/procfile.c
+++ b/src/procfile.c
@@ -20,6 +20,7 @@
#include "common.h"
#include "log.h"
#include "procfile.h"
+#include "../config.h"
#define PF_PREFIX "PROCFILE"
@@ -142,6 +143,9 @@ void pflines_free(pflines *fl) {
#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);
@@ -156,17 +160,82 @@ void procfile_close(procfile *ff) {
procfile *procfile_parser(procfile *ff) {
debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
- char *s = ff->data, *e = ff->data, *t = ff->data;
+ char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
uint32_t l = 0, w = 0;
- e += ff->len;
+ 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[(int)(*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(likely(s == t)) {
+ if(unlikely(quote || opened)) {
+ // we are inside a quote
+ s++;
+ continue;
+ }
+
+ if(unlikely(s == t)) {
// skip all leading white spaces
t = ++s;
continue;
@@ -209,9 +278,10 @@ procfile *procfile_parser(procfile *ff) {
}
}
- if(likely(s != t)) {
+ if(likely(s > t && t < e)) {
// the last word
- if(likely(ff->len < ff->size)) *s = '\0';
+ if(likely(ff->len < ff->size))
+ *s = '\0';
else {
// we are going to loose the last byte
ff->data[ff->size - 1] = '\0';
@@ -309,10 +379,53 @@ static void procfile_set_separators(procfile *ff, const char *separators) {
while(likely(ffd != ffe)) *ffs++ = *ffd++;
// set the separators
- if(unlikely(!separators)) separators = " \t=|";
+ if(unlikely(!separators))
+ separators = " \t=|";
+
ffs = ff->separators;
const char *s = separators;
- while(likely(*s)) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
+ 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;
+}
+
+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;
}
procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
diff --git a/src/procfile.h b/src/procfile.h
index ce2f9bc92..122e153f1 100755..100644
--- a/src/procfile.h
+++ b/src/procfile.h
@@ -86,6 +86,9 @@ extern procfile *procfile_reopen(procfile *ff, const char *filename, const char
// example walk-through a procfile parsed file
extern void procfile_print(procfile *ff);
+extern void procfile_set_quotes(procfile *ff, const char *quotes);
+extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
+
// ----------------------------------------------------------------------------
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far
diff --git a/src/rrd.c b/src/rrd.c
index 2dce02e66..86ff39687 100755..100644
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -682,6 +682,9 @@ void rrdset_save_all(void)
{
debug(D_RRD_CALLS, "rrdset_save_all()");
+ // let it log a few error messages
+ error_log_limit_reset();
+
RRDSET *st;
RRDDIM *rd;
diff --git a/src/rrd.h b/src/rrd.h
index 4211b7d56..4211b7d56 100755..100644
--- a/src/rrd.h
+++ b/src/rrd.h
diff --git a/src/rrd2json.c b/src/rrd2json.c
index ad453cb68..88a750443 100755..100644
--- a/src/rrd2json.c
+++ b/src/rrd2json.c
@@ -936,7 +936,7 @@ static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startlin
// 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, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ 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)) {
diff --git a/src/rrd2json.h b/src/rrd2json.h
index d1f850d4a..d1f850d4a 100755..100644
--- a/src/rrd2json.h
+++ b/src/rrd2json.h
diff --git a/src/storage_number.c b/src/storage_number.c
index 225cf0348..225cf0348 100755..100644
--- a/src/storage_number.c
+++ b/src/storage_number.c
diff --git a/src/storage_number.h b/src/storage_number.h
index f35e99ddd..f35e99ddd 100755..100644
--- a/src/storage_number.h
+++ b/src/storage_number.h
diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c
index 822e0d41a..822e0d41a 100755..100644
--- a/src/sys_kernel_mm_ksm.c
+++ b/src/sys_kernel_mm_ksm.c
diff --git a/src/unit_test.c b/src/unit_test.c
index 47aa5396c..47aa5396c 100755..100644
--- a/src/unit_test.c
+++ b/src/unit_test.c
diff --git a/src/unit_test.h b/src/unit_test.h
index 916ad71f2..916ad71f2 100755..100644
--- a/src/unit_test.h
+++ b/src/unit_test.h
diff --git a/src/url.c b/src/url.c
index c4933b205..edf52be7c 100755..100644
--- a/src/url.c
+++ b/src/url.c
@@ -31,6 +31,9 @@ char *url_encode(char *str) {
*buf = malloc(strlen(str) * 3 + 1),
*pbuf = buf;
+ if(!buf)
+ fatal("Cannot allocate memory.");
+
while (*pstr) {
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
*pbuf++ = *pstr;
@@ -56,7 +59,8 @@ char *url_decode(char *str) {
*buf = malloc(strlen(str) + 1),
*pbuf = buf;
- if(!buf) fatal("Cannot allocate memory.");
+ if(!buf)
+ fatal("Cannot allocate memory.");
while (*pstr) {
if (*pstr == '%') {
diff --git a/src/url.h b/src/url.h
index f79a20ea0..f79a20ea0 100755..100644
--- a/src/url.h
+++ b/src/url.h
diff --git a/src/web_buffer.c b/src/web_buffer.c
index 482eb3900..482eb3900 100755..100644
--- a/src/web_buffer.c
+++ b/src/web_buffer.c
diff --git a/src/web_buffer.h b/src/web_buffer.h
index 58dd9c094..58dd9c094 100755..100644
--- a/src/web_buffer.h
+++ b/src/web_buffer.h
diff --git a/src/web_client.c b/src/web_client.c
index 127333554..6500a59b2 100755..100644
--- a/src/web_client.c
+++ b/src/web_client.c
@@ -14,6 +14,7 @@
#include <netinet/tcp.h>
#include <malloc.h>
#include <pwd.h>
+#include <grp.h>
#include <ctype.h>
#include "common.h"
@@ -27,9 +28,11 @@
#include "rrd2json.h"
#include "web_client.h"
+#include "../config.h"
#define INITIAL_WEB_DATA_LENGTH 16384
#define WEB_REQUEST_LENGTH 16384
+#define TOO_BIG_REQUEST 16384
int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS;
int web_enable_gzip = 1;
@@ -230,10 +233,13 @@ uid_t web_files_uid(void)
static uid_t owner_uid = 0;
if(unlikely(!web_owner)) {
- web_owner = config_get("global", "web files owner", NETDATA_USER);
+ 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);
@@ -249,6 +255,34 @@ uid_t web_files_uid(void)
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.\n", web_group);
+ owner_gid = gr->gr_gid;
+ }
+ }
+ }
+
+ return(owner_gid);
+}
+
int mysendfile(struct web_client *w, char *filename)
{
static char *web_dir = NULL;
@@ -268,7 +302,7 @@ int mysendfile(struct web_client *w, char *filename)
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'", *s);
+ buffer_sprintf(w->response.data, "File '%s' cannot be served. Filename contains invalid character '%c'", filename, *s);
return 400;
}
}
@@ -288,14 +322,21 @@ int mysendfile(struct web_client *w, char *filename)
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.", filename);
+ buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", webfilename);
return 404;
}
- // check if the file is owned by us
+ // check if the file is owned by expected user
if(stat.st_uid != web_files_uid()) {
- error("%llu: File '%s' is owned by user %d (I run as user %d). Access Denied.", w->id, webfilename, stat.st_uid, getuid());
- buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", filename);
+ error("%llu: File '%s' is owned by user %d (expected user %d). 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 %d (expected group %d). 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;
}
@@ -306,7 +347,7 @@ int mysendfile(struct web_client *w, char *filename)
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.", filename);
+ buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
return 403;
}
@@ -318,12 +359,12 @@ int mysendfile(struct web_client *w, char *filename)
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.", 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'.", filename);
+ buffer_sprintf(w->response.data, "Cannot open file '%s'.", webfilename);
return 404;
}
}
@@ -747,36 +788,53 @@ int web_client_api_request_v1(struct web_client *w, char *url)
{
// get the command
char *tok = mystrsep(&url, "/?&");
- debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
-
- if(strcmp(tok, "data") == 0)
- return web_client_api_request_v1_data(w, url);
- else if(strcmp(tok, "chart") == 0)
- return web_client_api_request_v1_chart(w, url);
- else if(strcmp(tok, "charts") == 0)
- return web_client_api_request_v1_charts(w, url);
-
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
- return 404;
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
+
+ if(strcmp(tok, "data") == 0)
+ return web_client_api_request_v1_data(w, url);
+ else if(strcmp(tok, "chart") == 0)
+ return web_client_api_request_v1_chart(w, url);
+ else if(strcmp(tok, "charts") == 0)
+ return web_client_api_request_v1_charts(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, "/?&");
- 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);
-
- buffer_flush(w->response.data);
- buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
- return 404;
+ 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_data_request(struct web_client *w, char *url, int datasource_type)
{
+ RRDSET *st = NULL;
+
char *args = strchr(url, '?');
if(args) {
*args='\0';
@@ -785,11 +843,14 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
// get the name of the data to show
char *tok = mystrsep(&url, "/");
- 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(tok && *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
@@ -816,34 +877,36 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
if(url) {
// parse the group count required
tok = mystrsep(&url, "/");
- if(tok) group_count = atoi(tok);
+ 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(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(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) after = strtoul(tok, NULL, 10);
+ if(tok && *tok) after = strtoul(tok, NULL, 10);
if(after < 0) after = 0;
}
if(url) {
// parse before time
tok = mystrsep(&url, "/");
- if(tok) before = strtoul(tok, NULL, 10);
+ if(tok && *tok) before = strtoul(tok, NULL, 10);
if(before < 0) before = 0;
}
if(url) {
// parse nonzero
tok = mystrsep(&url, "/");
- if(tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
+ if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
}
w->response.data->contenttype = CT_APPLICATION_JSON;
@@ -862,9 +925,9 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
while(args) {
tok = mystrsep(&args, "&");
- if(tok) {
+ if(tok && *tok) {
char *name = mystrsep(&tok, "=");
- if(name && strcmp(name, "tqx") == 0) {
+ if(name && *name && strcmp(name, "tqx") == 0) {
char *key = mystrsep(&tok, ":");
char *value = mystrsep(&tok, ";");
if(key && value && *key && *value) {
@@ -1056,118 +1119,142 @@ void web_client_process(struct web_client *w) {
w->last_url[URL_MAX] = '\0';
tok = mystrsep(&url, "/?");
+ if(tok && *tok) {
+ debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
- debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
-
- if(strcmp(tok, "api") == 0) {
- // the client is requesting api access
- datasource_type = DATASOURCE_JSON;
- code = web_client_api_request(w, url);
- }
-#ifdef NETDATA_INTERNAL_CHECKS
- else if(strcmp(tok, "exit") == 0) {
- netdata_exit = 1;
- code = 200;
- w->response.data->contenttype = CT_TEXT_PLAIN;
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "will do");
- }
-#endif
- else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
- // the client is requesting rrd data
- datasource_type = DATASOURCE_JSON;
- code = web_client_data_request(w, url, datasource_type);
- }
- else if(strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
- // the client is requesting google datasource
- code = web_client_data_request(w, url, datasource_type);
- }
- else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
- // the client is requesting an rrd graph
-
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- 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);
+ if(strcmp(tok, "api") == 0) {
+ // the client is requesting api access
+ datasource_type = DATASOURCE_JSON;
+ code = web_client_api_request(w, url);
}
- else {
+#ifdef NETDATA_INTERNAL_CHECKS
+ else if(strcmp(tok, "exit") == 0) {
+ netdata_exit = 1;
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;
+ w->response.data->contenttype = CT_TEXT_PLAIN;
buffer_flush(w->response.data);
- rrd_stats_graph_json(st, url, w->response.data);
+ buffer_strcat(w->response.data, "will do");
+ }
+#endif
+ else if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
+ // the client is requesting rrd data
+ datasource_type = DATASOURCE_JSON;
+ code = web_client_data_request(w, url, datasource_type);
+ }
+ else if(strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
+ // the client is requesting google datasource
+ code = web_client_data_request(w, url, datasource_type);
+ }
+ else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
+ // the client is requesting an rrd graph
+
+ // 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");
+ }
}
- }
#ifdef NETDATA_INTERNAL_CHECKS
- else if(strcmp(tok, "debug") == 0) {
- buffer_flush(w->response.data);
+ else if(strcmp(tok, "debug") == 0) {
+ buffer_flush(w->response.data);
- // get the name of the data to show
- tok = mystrsep(&url, "/?&");
- 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);
+ // 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?0:1;
+ 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 {
+ else if(strcmp(tok, "mirror") == 0) {
code = 200;
- debug_flags |= D_RRD_STATS;
- st->debug = st->debug?0:1;
- 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 if(strcmp(tok, "mirror") == 0) {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
- // replace the zero bytes with spaces
- buffer_char_replace(w->response.data, '\0', ' ');
+ // 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
- }
+ // just leave the buffer as is
+ // it will be copied back to the client
+ }
#endif
- else if(strcmp(tok, "list") == 0) {
- code = 200;
+ else if(strcmp(tok, "list") == 0) {
+ code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
- buffer_flush(w->response.data);
- RRDSET *st = rrdset_root;
+ buffer_flush(w->response.data);
+ RRDSET *st = rrdset_root;
- for ( ; st ; st = st->next )
- buffer_sprintf(w->response.data, "%s\n", st->name);
- }
- else if(strcmp(tok, "all.json") == 0) {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
+ for ( ; st ; st = st->next )
+ buffer_sprintf(w->response.data, "%s\n", st->name);
+ }
+ else if(strcmp(tok, "all.json") == 0) {
+ 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);
- }
- else if(strcmp(tok, "netdata.conf") == 0) {
- code = 200;
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
+ w->response.data->contenttype = CT_APPLICATION_JSON;
+ buffer_flush(w->response.data);
+ rrd_stats_all_json(w->response.data);
+ }
+ else if(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);
+ w->response.data->contenttype = CT_TEXT_PLAIN;
+ buffer_flush(w->response.data);
+ generate_config(w->response.data, 0);
+ }
+ else {
+ char filename[FILENAME_MAX+1];
+ url = filename;
+ strncpy(filename, w->last_url, FILENAME_MAX);
+ filename[FILENAME_MAX] = '\0';
+ tok = mystrsep(&url, "?");
+ buffer_flush(w->response.data);
+ code = mysendfile(w, (tok && *tok)?tok:"/");
+ }
}
else {
char filename[FILENAME_MAX+1];
@@ -1190,16 +1277,19 @@ void web_client_process(struct web_client *w) {
}
// free url_decode() buffer
- if(pointer_to_free) free(pointer_to_free);
+ if(pointer_to_free) {
+ free(pointer_to_free);
+ pointer_to_free = NULL;
+ }
}
- else if(w->response.data->len > 8192) {
+ else 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.", w->id);
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zd bytes).", w->id, w->response.data->len);
code = 400;
buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Received request is too big.\r\n");
+ buffer_sprintf(w->response.data, "Received request is too big (%zd bytes).\r\n", w->response.data->len);
}
else {
// wait for more data
diff --git a/src/web_client.h b/src/web_client.h
index 14cd91bc6..3823dbc91 100755..100644
--- a/src/web_client.h
+++ b/src/web_client.h
@@ -81,6 +81,7 @@ struct web_client {
extern struct web_client *web_clients;
extern uid_t web_files_uid(void);
+extern uid_t web_files_gid(void);
extern struct web_client *web_client_create(int listener);
extern struct web_client *web_client_free(struct web_client *w);
diff --git a/src/web_server.c b/src/web_server.c
index cae94acad..10bf39a78 100755..100644
--- a/src/web_server.c
+++ b/src/web_server.c
@@ -24,12 +24,14 @@
#include "global_statistics.h"
#include "rrd.h"
#include "rrd2json.h"
+#include "../config.h"
int listen_backlog = LISTEN_BACKLOG;
int listen_fd = -1;
int listen_port = LISTEN_PORT;
+#ifdef NETDATA_INTERNAL_CHECKS
static void log_allocations(void)
{
static int mem = 0;
@@ -46,82 +48,123 @@ static void log_allocations(void)
mem = mi.uordblks;
}
}
+#endif
-int create_listen_socket4(int port, int listen_backlog)
+static int is_ip_anything(const char *ip)
{
- int sock;
- int sockopt = 1;
- struct sockaddr_in name;
+ if(!ip || !*ip
+ || !strcmp(ip, "any")
+ || !strcmp(ip, "all")
+ || !strcmp(ip, "*")
+ || !strcmp(ip, "::")
+ || !strcmp(ip, "0.0.0.0")
+ ) return 1;
+
+ return 0;
+}
- debug(D_LISTENER, "IPv4 creating new listening socket on port %d", port);
+int create_listen_socket4(const char *ip, int port, int listen_backlog)
+{
+ int sock;
+ int sockopt = 1;
+ struct sockaddr_in name;
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if(sock < 0) {
- error("IPv4 socket() failed.");
- return -1;
- }
+ debug(D_LISTENER, "IPv4 creating new listening socket on port %d", port);
- /* avoid "address already in use" */
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt));
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if(sock < 0) {
+ error("IPv4 socket() failed.");
+ return -1;
+ }
- memset(&name, 0, sizeof(struct sockaddr_in));
- name.sin_family = AF_INET;
- name.sin_port = htons (port);
- name.sin_addr.s_addr = htonl (INADDR_ANY);
+ /* avoid "address already in use" */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt));
- if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
- close(sock);
- error("IPv4 bind() failed.");
- return -1;
- }
+ memset(&name, 0, sizeof(struct sockaddr_in));
+ name.sin_family = AF_INET;
+ name.sin_port = htons (port);
- if(listen(sock, listen_backlog) < 0) {
+ if(is_ip_anything(ip)) {
+ name.sin_addr.s_addr = htonl(INADDR_ANY);
+ info("Listening on any IPs (IPv4).");
+ }
+ else {
+ int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
+ if(ret != 1) {
+ error("Failed to convert IP '%s' to a valid IPv4 address.", ip);
close(sock);
- fatal("IPv4 listen() failed.");
return -1;
}
+ info("Listening on IP '%s' (IPv4).", ip);
+ }
+
+ if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+ close(sock);
+ error("IPv4 bind() failed.");
+ return -1;
+ }
+
+ if(listen(sock, listen_backlog) < 0) {
+ close(sock);
+ fatal("IPv4 listen() failed.");
+ return -1;
+ }
- debug(D_LISTENER, "IPv4 listening port %d created", port);
- return sock;
+ debug(D_LISTENER, "IPv4 listening port %d created", port);
+ return sock;
}
-int create_listen_socket6(int port, int listen_backlog)
+int create_listen_socket6(const char *ip, int port, int listen_backlog)
{
- int sock = -1;
- int sockopt = 1;
- struct sockaddr_in6 name;
+ int sock = -1;
+ int sockopt = 1;
+ struct sockaddr_in6 name;
- debug(D_LISTENER, "IPv6 creating new listening socket on port %d", port);
+ debug(D_LISTENER, "IPv6 creating new listening socket on port %d", port);
- sock = socket(AF_INET6, SOCK_STREAM, 0);
- if (sock < 0) {
- error("IPv6 socket() failed.");
- return -1;
- }
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+ if (sock < 0) {
+ error("IPv6 socket() failed. Disabling IPv6.");
+ return -1;
+ }
- /* avoid "address already in use" */
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt));
+ /* avoid "address already in use" */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt));
- memset(&name, 0, sizeof(struct sockaddr_in6));
- name.sin6_family = AF_INET6;
- name.sin6_port = htons ((uint16_t) port);
- name.sin6_addr = in6addr_any;
- name.sin6_scope_id = 0;
+ memset(&name, 0, sizeof(struct sockaddr_in6));
+ name.sin6_family = AF_INET6;
+ name.sin6_port = htons ((uint16_t) port);
- if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+ if(is_ip_anything(ip)) {
+ name.sin6_addr = in6addr_any;
+ info("Listening on all IPs (IPv6 and IPv4)");
+ }
+ else {
+ int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
+ if(ret != 1) {
+ error("Failed to convert IP '%s' to a valid IPv6 address. Disabling IPv6.", ip);
close(sock);
- error("IPv6 bind() failed.");
return -1;
}
+ info("Listening on IP '%s' (IPv6)", ip);
+ }
- if (listen(sock, listen_backlog) < 0) {
- close(sock);
- fatal("IPv6 listen() failed.");
- return -1;
- }
+ name.sin6_scope_id = 0;
+
+ if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
+ close(sock);
+ error("IPv6 bind() failed. Disabling IPv6.");
+ return -1;
+ }
- debug(D_LISTENER, "IPv6 listening port %d created", port);
- return sock;
+ if (listen(sock, listen_backlog) < 0) {
+ close(sock);
+ error("IPv6 listen() failed. Disabling IPv6.");
+ return -1;
+ }
+
+ debug(D_LISTENER, "IPv6 listening port %d created", port);
+ return sock;
}
@@ -210,7 +253,9 @@ void *socket_listen_main(void *ptr)
debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
// pthread_join(w->thread, NULL);
w = web_client_free(w);
+#ifdef NETDATA_INTERNAL_CHECKS
log_allocations();
+#endif
}
}
}
diff --git a/src/web_server.h b/src/web_server.h
index 0d1e2da92..39f3bad91 100755..100644
--- a/src/web_server.h
+++ b/src/web_server.h
@@ -13,8 +13,8 @@ extern int listen_backlog;
extern int listen_fd;
extern int listen_port;
-extern int create_listen_socket4(int port, int listen_backlog);
-extern int create_listen_socket6(int port, int listen_backlog);
+extern int create_listen_socket4(const char *ip, int port, int listen_backlog);
+extern int create_listen_socket6(const char *ip, int port, int listen_backlog);
extern void *socket_listen_main(void *ptr);
#endif /* NETDATA_WEB_SERVER_H */