diff options
author | Lennart Weller <lhw@ring0.de> | 2016-04-21 12:27:39 +0000 |
---|---|---|
committer | Lennart Weller <lhw@ring0.de> | 2016-04-21 12:27:39 +0000 |
commit | edff5c9db775e6e4318f3ad007df78ecae456190 (patch) | |
tree | 3677e5fcbccc776c77dd0451e5be4711068bff46 /src | |
parent | Add postrm and TODO, update service (diff) | |
parent | Imported Upstream version 1.1.0 (diff) | |
download | netdata-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.am | 3 | ||||
-rw-r--r-- | src/Makefile.in | 873 | ||||
-rw-r--r--[-rwxr-xr-x] | src/appconfig.c | 4 | ||||
-rw-r--r--[-rwxr-xr-x] | src/appconfig.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/apps_plugin.c | 1640 | ||||
-rw-r--r--[-rwxr-xr-x] | src/avl.c | 31 | ||||
-rw-r--r--[-rwxr-xr-x] | src/avl.h | 8 | ||||
-rw-r--r--[-rwxr-xr-x] | src/common.c | 266 | ||||
-rw-r--r--[-rwxr-xr-x] | src/common.h | 12 | ||||
-rw-r--r--[-rwxr-xr-x] | src/daemon.c | 88 | ||||
-rw-r--r--[-rwxr-xr-x] | src/daemon.h | 5 | ||||
-rw-r--r--[-rwxr-xr-x] | src/dictionary.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/dictionary.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/global_statistics.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/global_statistics.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/log.c | 87 | ||||
-rw-r--r--[-rwxr-xr-x] | src/log.h | 6 | ||||
-rw-r--r--[-rwxr-xr-x] | src/main.c | 103 | ||||
-rw-r--r--[-rwxr-xr-x] | src/main.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_checks.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_checks.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_idlejitter.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_idlejitter.h | 0 | ||||
-rw-r--r-- | src/plugin_nfacct.c | 9 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_nfacct.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_proc.c | 20 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_proc.h | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_tc.c | 23 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugin_tc.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugins_d.c | 7 | ||||
-rw-r--r--[-rwxr-xr-x] | src/plugins_d.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/popen.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/popen.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_diskstats.c | 84 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_interrupts.c | 25 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_loadavg.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_meminfo.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_net_dev.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_net_ip_vs_stats.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_net_netstat.c | 34 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_net_snmp.c | 2 | ||||
-rw-r--r-- | src/proc_net_snmp6.c | 1067 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_net_stat_conntrack.c | 27 | ||||
-rw-r--r-- | src/proc_net_stat_synproxy.c | 138 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_softirqs.c | 25 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_stat.c | 6 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_sys_kernel_random_entropy_avail.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/proc_vmstat.c | 3 | ||||
-rw-r--r--[-rwxr-xr-x] | src/procfile.c | 127 | ||||
-rw-r--r--[-rwxr-xr-x] | src/procfile.h | 3 | ||||
-rw-r--r--[-rwxr-xr-x] | src/rrd.c | 3 | ||||
-rw-r--r--[-rwxr-xr-x] | src/rrd.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/rrd2json.c | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | src/rrd2json.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/storage_number.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/storage_number.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/sys_kernel_mm_ksm.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/unit_test.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/unit_test.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/url.c | 6 | ||||
-rw-r--r--[-rwxr-xr-x] | src/url.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_buffer.c | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_buffer.h | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_client.c | 370 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_client.h | 1 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_server.c | 147 | ||||
-rw-r--r--[-rwxr-xr-x] | src/web_server.h | 4 |
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 */ |