summaryrefslogtreecommitdiff
path: root/torrus/bin
diff options
context:
space:
mode:
Diffstat (limited to 'torrus/bin')
-rw-r--r--torrus/bin/Makefile.am177
-rw-r--r--torrus/bin/Makefile.in538
-rw-r--r--torrus/bin/acledit.in432
-rw-r--r--torrus/bin/action_notify.in96
-rw-r--r--torrus/bin/action_printemail.in83
-rw-r--r--torrus/bin/action_snmptrap.in183
-rw-r--r--torrus/bin/action_snmpv1trap.in134
-rw-r--r--torrus/bin/bdbinfo.in38
-rw-r--r--torrus/bin/buildsearchdb.in200
-rw-r--r--torrus/bin/cleanup.in32
-rw-r--r--torrus/bin/clearcache.in40
-rw-r--r--torrus/bin/collector.in205
-rw-r--r--torrus/bin/compilexml.in207
-rw-r--r--torrus/bin/configinfo.in166
-rw-r--r--torrus/bin/configsnapshot.in332
-rw-r--r--torrus/bin/devdiscover.in619
-rw-r--r--torrus/bin/flushmonitors.in143
-rw-r--r--torrus/bin/genddx.in255
-rw-r--r--torrus/bin/genlist.in197
-rw-r--r--torrus/bin/genreport.in181
-rw-r--r--torrus/bin/install_plugin.in51
-rw-r--r--torrus/bin/monitor.in176
-rw-r--r--torrus/bin/nodeid.in252
-rw-r--r--torrus/bin/rrddir2xml.in311
-rw-r--r--torrus/bin/schedulerinfo.in454
-rw-r--r--torrus/bin/snmpfailures.in98
-rw-r--r--torrus/bin/srvderive.in371
-rw-r--r--torrus/bin/torrus.fcgi.in50
-rw-r--r--torrus/bin/torrus.in76
-rw-r--r--torrus/bin/ttproclist.in135
30 files changed, 6232 insertions, 0 deletions
diff --git a/torrus/bin/Makefile.am b/torrus/bin/Makefile.am
new file mode 100644
index 000000000..b6abf740d
--- /dev/null
+++ b/torrus/bin/Makefile.am
@@ -0,0 +1,177 @@
+
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: Makefile.am,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+#
+
+SUBST = @abs_top_builddir@/setup_tools/substvars.sh
+
+pkgbindir = @pkgbindir@
+pkgbin_SCRIPTS = \
+ acledit \
+ action_notify \
+ action_printemail \
+ action_snmptrap \
+ action_snmpv1trap \
+ bdbinfo \
+ buildsearchdb \
+ cleanup \
+ clearcache \
+ collector \
+ compilexml \
+ configinfo \
+ configsnapshot \
+ devdiscover \
+ flushmonitors \
+ genddx \
+ genlist \
+ genreport \
+ install_plugin \
+ monitor \
+ nodeid \
+ rrddir2xml \
+ schedulerinfo \
+ snmpfailures \
+ srvderive \
+ torrus.fcgi \
+ ttproclist
+
+wrapperdir = @wrapperdir@
+wrapper_SCRIPTS = \
+ torrus
+
+CLEANFILES = $(pkgbin_SCRIPTS) $(wrapper_SCRIPTS)
+
+EXTRA_DIST = \
+ acledit.in \
+ action_notify.in \
+ action_printemail.in \
+ action_snmptrap.in \
+ action_snmpv1trap.in \
+ bdbinfo.in \
+ buildsearchdb.in \
+ clearcache.in \
+ cleanup.in \
+ collector.in \
+ compilexml.in \
+ configinfo.in \
+ configsnapshot.in \
+ devdiscover.in \
+ flushmonitors.in \
+ genddx.in \
+ genlist.in \
+ genreport.in \
+ install_plugin.in \
+ monitor.in \
+ nodeid.in \
+ rrddir2xml.in \
+ schedulerinfo.in \
+ snmpfailures.in \
+ srvderive.in \
+ torrus.fcgi.in \
+ torrus.in \
+ ttproclist.in
+
+
+# Result of:
+# ls -1 | egrep '^[a-z][^.]+$' | \
+# awk '{printf "%s: %s.in\n\t$(SUBST) %s.in > %s\n\n", $1, $1, $1, $1}'
+
+acledit: acledit.in
+ $(SUBST) acledit.in > acledit
+
+action_printemail: action_printemail.in
+ $(SUBST) action_printemail.in > action_printemail
+
+action_notify: action_notify.in
+ $(SUBST) action_notify.in > action_notify
+
+action_snmptrap: action_snmptrap.in
+ $(SUBST) action_snmptrap.in > action_snmptrap
+
+action_snmpv1trap: action_snmpv1trap.in
+ $(SUBST) action_snmpv1trap.in > action_snmpv1trap
+
+buildsearchdb: buildsearchdb.in
+ $(SUBST) buildsearchdb.in > buildsearchdb
+
+bdbinfo: bdbinfo.in
+ $(SUBST) bdbinfo.in > bdbinfo
+
+cleanup: cleanup.in
+ $(SUBST) cleanup.in > cleanup
+
+clearcache: clearcache.in
+ $(SUBST) clearcache.in > clearcache
+
+collector: collector.in
+ $(SUBST) collector.in > collector
+
+compilexml: compilexml.in
+ $(SUBST) compilexml.in > compilexml
+
+configinfo: configinfo.in
+ $(SUBST) configinfo.in > configinfo
+
+configsnapshot: configsnapshot.in
+ $(SUBST) configsnapshot.in > configsnapshot
+
+devdiscover: devdiscover.in
+ $(SUBST) devdiscover.in > devdiscover
+
+flushmonitors: flushmonitors.in
+ $(SUBST) flushmonitors.in > flushmonitors
+
+genddx: genddx.in
+ $(SUBST) genddx.in > genddx
+
+genlist: genlist.in
+ $(SUBST) genlist.in > genlist
+
+genreport: genreport.in
+ $(SUBST) genreport.in > genreport
+
+install_plugin: install_plugin.in
+ $(SUBST) install_plugin.in > install_plugin
+
+monitor: monitor.in
+ $(SUBST) monitor.in > monitor
+
+nodeid: nodeid.in
+ $(SUBST) nodeid.in > nodeid
+
+rrddir2xml: rrddir2xml.in
+ $(SUBST) rrddir2xml.in > rrddir2xml
+
+schedulerinfo: schedulerinfo.in
+ $(SUBST) schedulerinfo.in > schedulerinfo
+
+snmpfailures: snmpfailures.in
+ $(SUBST) snmpfailures.in > snmpfailures
+
+srvderive: srvderive.in
+ $(SUBST) srvderive.in > srvderive
+
+torrus: torrus.in
+ $(SUBST) torrus.in > torrus
+
+torrus.fcgi: torrus.fcgi.in
+ $(SUBST) torrus.fcgi.in > torrus.fcgi
+
+ttproclist: ttproclist.in
+ $(SUBST) ttproclist.in > ttproclist
diff --git a/torrus/bin/Makefile.in b/torrus/bin/Makefile.in
new file mode 100644
index 000000000..fb4aa2bfb
--- /dev/null
+++ b/torrus/bin/Makefile.in
@@ -0,0 +1,538 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 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@
+
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: Makefile.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+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@
+subdir = bin
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(pkgbindir)" "$(DESTDIR)$(wrapperdir)"
+pkgbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+wrapperSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(pkgbin_SCRIPTS) $(wrapper_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+FIND = @FIND@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KILL = @KILL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERLINC = @PERLINC@
+POD2MAN = @POD2MAN@
+POD2MAN_PRESENT_FALSE = @POD2MAN_PRESENT_FALSE@
+POD2MAN_PRESENT_TRUE = @POD2MAN_PRESENT_TRUE@
+POD2TEXT = @POD2TEXT@
+POD2TEXT_PRESENT_FALSE = @POD2TEXT_PRESENT_FALSE@
+POD2TEXT_PRESENT_TRUE = @POD2TEXT_PRESENT_TRUE@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SLEEP = @SLEEP@
+STRIP = @STRIP@
+SU = @SU@
+VERSION = @VERSION@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+cachedir = @cachedir@
+cfgdefdir = @cfgdefdir@
+datadir = @datadir@
+dbhome = @dbhome@
+defrrddir = @defrrddir@
+distxmldir = @distxmldir@
+enable_pkgonly = @enable_pkgonly@
+enable_varperm = @enable_varperm@
+exec_prefix = @exec_prefix@
+exmpdir = @exmpdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+mandir = @mandir@
+mansec_misc = @mansec_misc@
+mansec_usercmd = @mansec_usercmd@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+perlithreads = @perlithreads@
+perllibdir = @perllibdir@
+perllibdirs = @perllibdirs@
+piddir = @piddir@
+pkgbindir = @pkgbindir@
+pkgdocdir = @pkgdocdir@
+pkghome = @pkghome@
+plugdevdisccfgdir = @plugdevdisccfgdir@
+pluginsdir = @pluginsdir@
+plugtorruscfgdir = @plugtorruscfgdir@
+plugwrapperdir = @plugwrapperdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+reportsdir = @reportsdir@
+sbindir = @sbindir@
+scriptsdir = @scriptsdir@
+seslockdir = @seslockdir@
+sesstordir = @sesstordir@
+sharedstatedir = @sharedstatedir@
+siteconfdir = @siteconfdir@
+sitedir = @sitedir@
+sitexmldir = @sitexmldir@
+supdir = @supdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+tmpldir = @tmpldir@
+tmpluserdir = @tmpluserdir@
+torrus_user = @torrus_user@
+var_group = @var_group@
+var_mode = @var_mode@
+var_user = @var_user@
+varprefix = @varprefix@
+webplaindir = @webplaindir@
+webscriptsdir = @webscriptsdir@
+wrapperdir = @wrapperdir@
+SUBST = @abs_top_builddir@/setup_tools/substvars.sh
+pkgbin_SCRIPTS = \
+ acledit \
+ action_notify \
+ action_printemail \
+ action_snmptrap \
+ action_snmpv1trap \
+ bdbinfo \
+ buildsearchdb \
+ cleanup \
+ clearcache \
+ collector \
+ compilexml \
+ configinfo \
+ configsnapshot \
+ devdiscover \
+ flushmonitors \
+ genddx \
+ genlist \
+ genreport \
+ install_plugin \
+ monitor \
+ nodeid \
+ rrddir2xml \
+ schedulerinfo \
+ snmpfailures \
+ srvderive \
+ torrus.fcgi \
+ ttproclist
+
+wrapper_SCRIPTS = \
+ torrus
+
+CLEANFILES = $(pkgbin_SCRIPTS) $(wrapper_SCRIPTS)
+EXTRA_DIST = \
+ acledit.in \
+ action_notify.in \
+ action_printemail.in \
+ action_snmptrap.in \
+ action_snmpv1trap.in \
+ bdbinfo.in \
+ buildsearchdb.in \
+ clearcache.in \
+ cleanup.in \
+ collector.in \
+ compilexml.in \
+ configinfo.in \
+ configsnapshot.in \
+ devdiscover.in \
+ flushmonitors.in \
+ genddx.in \
+ genlist.in \
+ genreport.in \
+ install_plugin.in \
+ monitor.in \
+ nodeid.in \
+ rrddir2xml.in \
+ schedulerinfo.in \
+ snmpfailures.in \
+ srvderive.in \
+ torrus.fcgi.in \
+ torrus.in \
+ ttproclist.in
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bin/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu bin/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: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pkgbinSCRIPTS: $(pkgbin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgbindir)" || $(mkdir_p) "$(DESTDIR)$(pkgbindir)"
+ @list='$(pkgbin_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(pkgbinSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgbindir)/$$f'"; \
+ $(pkgbinSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgbindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pkgbinSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgbin_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(pkgbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pkgbindir)/$$f"; \
+ done
+install-wrapperSCRIPTS: $(wrapper_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(wrapperdir)" || $(mkdir_p) "$(DESTDIR)$(wrapperdir)"
+ @list='$(wrapper_SCRIPTS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f $$d$$p; then \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " $(wrapperSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(wrapperdir)/$$f'"; \
+ $(wrapperSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(wrapperdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-wrapperSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(wrapper_SCRIPTS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+ echo " rm -f '$(DESTDIR)$(wrapperdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(wrapperdir)/$$f"; \
+ done
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$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 $(SCRIPTS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgbindir)" "$(DESTDIR)$(wrapperdir)"; 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:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgbinSCRIPTS install-wrapperSCRIPTS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-pkgbinSCRIPTS \
+ uninstall-wrapperSCRIPTS
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+ distclean-generic distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-pkgbinSCRIPTS install-strip install-wrapperSCRIPTS \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am uninstall uninstall-am uninstall-info-am \
+ uninstall-pkgbinSCRIPTS uninstall-wrapperSCRIPTS
+
+
+# Result of:
+# ls -1 | egrep '^[a-z][^.]+$' | \
+# awk '{printf "%s: %s.in\n\t$(SUBST) %s.in > %s\n\n", $1, $1, $1, $1}'
+
+acledit: acledit.in
+ $(SUBST) acledit.in > acledit
+
+action_printemail: action_printemail.in
+ $(SUBST) action_printemail.in > action_printemail
+
+action_notify: action_notify.in
+ $(SUBST) action_notify.in > action_notify
+
+action_snmptrap: action_snmptrap.in
+ $(SUBST) action_snmptrap.in > action_snmptrap
+
+action_snmpv1trap: action_snmpv1trap.in
+ $(SUBST) action_snmpv1trap.in > action_snmpv1trap
+
+buildsearchdb: buildsearchdb.in
+ $(SUBST) buildsearchdb.in > buildsearchdb
+
+bdbinfo: bdbinfo.in
+ $(SUBST) bdbinfo.in > bdbinfo
+
+cleanup: cleanup.in
+ $(SUBST) cleanup.in > cleanup
+
+clearcache: clearcache.in
+ $(SUBST) clearcache.in > clearcache
+
+collector: collector.in
+ $(SUBST) collector.in > collector
+
+compilexml: compilexml.in
+ $(SUBST) compilexml.in > compilexml
+
+configinfo: configinfo.in
+ $(SUBST) configinfo.in > configinfo
+
+configsnapshot: configsnapshot.in
+ $(SUBST) configsnapshot.in > configsnapshot
+
+devdiscover: devdiscover.in
+ $(SUBST) devdiscover.in > devdiscover
+
+flushmonitors: flushmonitors.in
+ $(SUBST) flushmonitors.in > flushmonitors
+
+genddx: genddx.in
+ $(SUBST) genddx.in > genddx
+
+genlist: genlist.in
+ $(SUBST) genlist.in > genlist
+
+genreport: genreport.in
+ $(SUBST) genreport.in > genreport
+
+install_plugin: install_plugin.in
+ $(SUBST) install_plugin.in > install_plugin
+
+monitor: monitor.in
+ $(SUBST) monitor.in > monitor
+
+nodeid: nodeid.in
+ $(SUBST) nodeid.in > nodeid
+
+rrddir2xml: rrddir2xml.in
+ $(SUBST) rrddir2xml.in > rrddir2xml
+
+schedulerinfo: schedulerinfo.in
+ $(SUBST) schedulerinfo.in > schedulerinfo
+
+snmpfailures: snmpfailures.in
+ $(SUBST) snmpfailures.in > snmpfailures
+
+srvderive: srvderive.in
+ $(SUBST) srvderive.in > srvderive
+
+torrus: torrus.in
+ $(SUBST) torrus.in > torrus
+
+torrus.fcgi: torrus.fcgi.in
+ $(SUBST) torrus.fcgi.in > torrus.fcgi
+
+ttproclist: ttproclist.in
+ $(SUBST) ttproclist.in > ttproclist
+# 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/torrus/bin/acledit.in b/torrus/bin/acledit.in
new file mode 100644
index 000000000..725d3b5eb
--- /dev/null
+++ b/torrus/bin/acledit.in
@@ -0,0 +1,432 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: acledit.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::ACL::Edit;
+use Torrus::SiteConfig;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+our %knownPrivileges =
+ ( 'DisplayTree' => 'tree',
+ 'DisplayAdmInfo' => 'tree',
+ 'DisplayReports' => 'tree',
+ 'GlobalSearch' => 'global' );
+
+our @addgroups;
+our @delgroups;
+our @modgroups;
+
+our @permitprivs;
+our @denyprivs;
+our @forobjects;
+
+our $adduser;
+our $addhost;
+our $deluser;
+our $moduser;
+our @addtogroups;
+our @delfromgroups;
+our $password;
+our $host_password;
+our $commonname;
+our $exportfile;
+our $exporttemplate = "aclexport.xml";
+our $importfile;
+our $clearconf;
+
+our @showgroups;
+our @showusers;
+our $listall;
+
+our $force;
+our $debug;
+our $verbose;
+our $help_needed;
+
+my $ok = GetOptions ('addgroup=s' => \@addgroups,
+ 'delgroup=s' => \@delgroups,
+ 'modgroup=s' => \@modgroups,
+ 'permit=s' => \@permitprivs,
+ 'deny=s' => \@denyprivs,
+ 'for=s' => \@forobjects,
+ 'adduser=s' => \$adduser,
+ 'addhost=s' => \$addhost,
+ 'deluser=s' => \$deluser,
+ 'moduser=s' => \$moduser,
+ 'addtogroup=s' => \@addtogroups,
+ 'delfromgroup=s' => \@delfromgroups,
+ 'password=s' => \$password,
+ 'hostpassword=s' => \$host_password,
+ 'cn=s' => \$commonname,
+ 'export=s' => \$exportfile,
+ 'template=s' => \$exporttemplate,
+ 'import=s' => \$importfile,
+ 'clear' => \$clearconf,
+ 'showgroup=s' => \@showgroups,
+ 'showuser=s' => \@showusers,
+ 'list' => \$listall,
+ 'force' => \$force,
+ 'debug' => \$debug,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or $help_needed or scalar(@ARGV) > 0 or
+ ( @addgroups ? 1:0 ) + ( @delgroups ? 1:0 ) + ( @modgroups ? 1:0 ) > 1 or
+ ( ( @permitprivs or @denyprivs ) and not @forobjects ) or
+ ( $adduser ? 1:0 ) + ( $deluser ? 1:0 ) + ( $moduser ? 1:0 ) > 1 or
+ ( ( @addtogroups or @delfromgroups or
+ length($password) > 0 or
+ length($host_password) > 0 or
+ length($commonname) > 0 ) and
+ ( length($adduser) + length($addhost) + length($moduser) == 0 ) ) )
+{
+ print STDERR "Usage: $0 [options...]\n",
+ "Group Options:\n",
+ " --addgroup=GROUP add group\n",
+ " --delgroup=GROUP delete group\n",
+ " --modgroup=GROUP modify group\n",
+ " --permit=PRIVILEGE add privilege to group(s)\n",
+ " --deny=PRIVILEGE revoke privilege from group(s)\n",
+ " --for=TREE subject of privilege or '*'\n",
+ " --force change privilege for non-existent object\n",
+ " --showgroup=GROUP display group details\n",
+ "User Options:\n",
+ " --adduser=UID add new user\n",
+ " --deluser=UID delete user\n",
+ " --moduser=UID modify user\n",
+ " --addtogroup=GROUP add user to group(s)\n",
+ " --delfromgroup=GROUP delete user from group(s)\n",
+ " --password=PASSWORD set the user password\n",
+ " --hostpassword=PASSWORD set the host password (UID must be a host)\n",
+ " --cn=\"John Smith\" set the user common name\n",
+ " --showuser=USER display user details\n",
+ "General Options:\n",
+ " --export=FILE export ACL config to a file\n",
+ " --template=NAME [aclexport.xml] export template \n",
+ " --import=FILE import ACL config from a file\n",
+ " --clear delete ALL user and privileges configuration\n",
+ " --list list all users and groups they belong to\n",
+ " --debug set the log level to debug\n",
+ " --verbose set the log level to verbose\n",
+ " --help this help message\n\n",
+ "Privileges:\n",
+ " DisplayTree see the datasources for a tree\n",
+ " DisplayAdmInfo see the administrative info for a tree\n",
+ " DisplayReports see the administrative info for a tree\n",
+ " GlobalSearch search globally for '*'\n";
+ exit 1;
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+# We set the signal handlers, but we actually don't react on
+# signals, because the acledit is a fast utility
+&Torrus::DB::setSafeSignalHandlers();
+
+Verbose(sprintf("Torrus version %s", '@VERSION@'));
+
+my $aclEdit = new Torrus::ACL::Edit;
+
+if( $ok and $exportfile )
+{
+ $ok = $aclEdit->exportACL( $exportfile, $exporttemplate ) ? $ok:0;
+}
+
+if( $ok and $clearconf )
+{
+ $ok = $aclEdit->clearConfig() ? $ok:0;
+}
+
+if( @delgroups )
+{
+ $ok = $aclEdit->deleteGroups( @delgroups ) ? $ok:0;
+}
+
+if( @addgroups )
+{
+ $ok = $aclEdit->addGroups( @addgroups ) ? $ok:0;
+}
+
+if( @addgroups or @modgroups )
+{
+ my $groups = [ @addgroups, @modgroups ];
+ if( @permitprivs )
+ {
+ $ok = setupPrivileges( $aclEdit, \@permitprivs,
+ $groups, \@forobjects, 1 ) ? $ok:0;
+ }
+ if( @denyprivs )
+ {
+ $ok = setupPrivileges( $aclEdit, \@denyprivs,
+ $groups, \@forobjects, 0 ) ? $ok:0;
+ }
+}
+
+
+my $attrValues = {};
+my $uid;
+
+if( $commonname )
+{
+ $attrValues->{'cn'} = $commonname;
+}
+
+if( $adduser )
+{
+ $uid = $adduser;
+ $ok = $aclEdit->addUser( $uid, $attrValues ) ? $ok:0;
+}
+elsif( $addhost )
+{
+ $uid = $addhost;
+ $uid =~ s/\W/_/g;
+ $ok = $aclEdit->addUser( $uid, $attrValues ) ? $ok:0;
+}
+
+elsif( $moduser )
+{
+ $uid = $moduser;
+ if( scalar( keys %{$attrValues} ) )
+ {
+ $ok = $aclEdit->setUserAttributes( $uid, $attrValues ) ? $ok:0;
+ }
+}
+elsif( $deluser )
+{
+ $ok = $aclEdit->deleteUser( $deluser ) ? $ok:0;
+}
+
+if( $uid )
+{
+ if( $password )
+ {
+ $ok = $aclEdit->setPassword( $uid, $password ) ? $ok:0;
+ }
+ elsif( $host_password )
+ {
+ $ok = $aclEdit->setPassword( $uid,
+ $uid . '//' . $host_password ) ? $ok:0;
+ }
+}
+
+if( $uid and scalar( @addtogroups ) )
+{
+ $ok = $aclEdit->addUserToGroups( $uid, @addtogroups ) ? $ok:0;
+}
+
+if( $uid and scalar( @delfromgroups ) )
+{
+ $ok = $aclEdit->delUserFromGroups( $uid, @delfromgroups ) ? $ok:0;
+}
+
+if( $ok and $importfile )
+{
+ $ok = $aclEdit->importACL( $importfile ) ? $ok:0;
+}
+
+if( $listall )
+{
+ @showusers = $aclEdit->listUsers();
+ @showgroups = $aclEdit->listGroups();
+}
+
+my %showGroupsHash;
+
+if( @showgroups )
+{
+ foreach my $group ( @showgroups )
+ {
+ if( $aclEdit->groupExists( $group ) )
+ {
+ $showGroupsHash{$group} = 1;
+ }
+ else
+ {
+ Error('No such group: ' . $group); $ok = 0;
+ }
+ }
+}
+
+if( @showusers )
+{
+ foreach my $uid ( sort @showusers )
+ {
+ if( $aclEdit->userExists( $uid ) )
+ {
+ printf("User: %s (%s)\n",
+ $uid, $aclEdit->userAttribute( $uid, 'cn' ) );
+ foreach my $group ( sort $aclEdit->memberOf( $uid ) )
+ {
+ printf("Member of: %s\n", $group);
+ $showGroupsHash{$group} = 1;
+ }
+
+ if( $verbose or $debug )
+ {
+ printf("Modified: %s\n",
+ $aclEdit->userAttribute( $uid, 'modified' ) );
+ }
+ printf ("\n");
+ }
+ else
+ {
+ Error('No such user: ' . $uid); $ok = 0;
+ }
+ }
+}
+
+if( %showGroupsHash )
+{
+ foreach my $group ( sort keys %showGroupsHash )
+ {
+ printf("Group: %s\n", $group);
+
+ my $privs = $aclEdit->listPrivileges( $group );
+ foreach my $object ( sort keys %{$privs} )
+ {
+ foreach my $priv ( sort keys %{$privs->{$object}} )
+ {
+ printf("Has privilege \"%s\" for %s \"%s\"\n", $priv,
+ $knownPrivileges{$priv}, $object);
+ }
+ }
+
+ foreach my $uid ( sort @{$aclEdit->listGroupMembers( $group )} )
+ {
+ printf("Member: %s\n", $uid);
+ }
+
+ if( $verbose or $debug )
+ {
+ printf("Modified: %s\n",
+ $aclEdit->groupAttribute( $group, 'modified' ) );
+ }
+
+ printf ("\n");
+ }
+}
+
+if( not $ok )
+{
+ Warn('acledit exited with errors');
+}
+exit( $ok ? 0:1 );
+
+sub setupPrivileges
+{
+ my $aclEdtit = shift;
+ my $privs = shift;
+ my $groups = shift;
+ my $objects = shift;
+ my $permit = shift;
+
+ my $ok = 1;
+ foreach my $priv ( @{$privs} )
+ {
+ if( defined( $knownPrivileges{$priv} ) )
+ {
+ if( $knownPrivileges{$priv} eq 'tree' )
+ {
+ foreach my $obj ( @{$objects} )
+ {
+ if( $obj eq '*' or
+ Torrus::SiteConfig::treeExists( $obj ) or $force )
+ {
+ foreach my $group ( @{$groups} )
+ {
+ if( $permit )
+ {
+ $ok = $aclEdit->
+ setPrivilege( $group, $obj,
+ $priv ) ? $ok:0;
+ }
+ else
+ {
+ $ok = $aclEdit->
+ clearPrivilege( $group, $obj,
+ $priv ) ? $ok:0;
+ }
+ }
+ }
+ else
+ {
+ Error('No such tree: ' . $obj); $ok = 0;
+ }
+ }
+ }
+ elsif( $knownPrivileges{$priv} eq 'global' )
+ {
+ foreach my $obj ( @{$objects} )
+ {
+ if( $obj ne '*' )
+ {
+ Error("Privilege GlobalSearch should be for '*'");
+ $ok = 0;
+ }
+ }
+
+ if( $ok )
+ {
+ foreach my $group ( @{$groups} )
+ {
+ if( $permit )
+ {
+ $ok = $aclEdit->
+ setPrivilege( $group, '*', $priv ) ? $ok:0;
+ }
+ else
+ {
+ $ok = $aclEdit->
+ clearPrivilege( $group, '*', $priv ) ? $ok:0;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Error('Unknown privilege name: ' . $priv); $ok = 0;
+ }
+ }
+ return $ok;
+}
+
+
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/action_notify.in b/torrus/bin/action_notify.in
new file mode 100644
index 000000000..a01b5486a
--- /dev/null
+++ b/torrus/bin/action_notify.in
@@ -0,0 +1,96 @@
+#!@PERL@
+# Copyright (C) 2006 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: action_notify.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# We need this for $Torrus::Global::templateDirs
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Date::Format;
+
+use Torrus::Log;
+
+require '@notify_siteconfig_pl@';
+
+if( not $ENV{'TORRUS_TREE'} )
+{
+ print STDERR ("Torrus environment variables missing. This program ",
+ "must be run from Torrus Monitor\n");
+ exit 1;
+}
+
+our $now = time();
+our $nowHour = time2str('%H', $now);
+our $nowWeekday = time2str('%w', $now);
+
+my $severity = $ENV{'TORRUS_SEVERITY'};
+my $ok = 1;
+
+foreach my $policy ( keys %Torrus::Notify::policies )
+{
+ if( &{$Torrus::Notify::policies{$policy}{'match'}} )
+ {
+ Debug('Notification policy matched: ' . $policy);
+
+ my @targets = ();
+ my $levels = $Torrus::Notify::policies{$policy}{'severity'};
+
+ foreach my $level ( sort {$a <=>$b} keys %{$levels} )
+ {
+ if( $severity >= $level )
+ {
+ push( @targets, @{$levels->{$level}} );
+ }
+ }
+
+ if( isDebug() )
+ {
+ Debug('Selected notification targets: ' . join(' ', @targets));
+ }
+
+ foreach my $target ( @targets )
+ {
+ my($protocol, $arg) = split(':', $target);
+ if( defined( $Torrus::Notify::programs{$protocol} ) )
+ {
+ $ENV{'ARG1'} = $arg;
+ my $status = system( $Torrus::Notify::programs{$protocol} );
+ delete $ENV{'ARG1'};
+
+ if( $status != 0 )
+ {
+ Error('The command "' .
+ $Torrus::Notify::programs{$protocol} .
+ '" returned error code ' . $status);
+ $ok = 0;
+ }
+ }
+ }
+ }
+}
+
+exit( $ok ? 0:1 );
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/action_printemail.in b/torrus/bin/action_printemail.in
new file mode 100644
index 000000000..416147b85
--- /dev/null
+++ b/torrus/bin/action_printemail.in
@@ -0,0 +1,83 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: action_printemail.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# We need this for $Torrus::Global::templateDirs
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Template;
+use Getopt::Long;
+
+require '@email_siteconfig_pl@';
+
+if( not $ENV{'TORRUS_TREE'} )
+{
+ print STDERR ("Torrus environment variables missing. This program ",
+ "must be run from Torrus Monitor\n");
+ exit 1;
+}
+
+
+my $ok = GetOptions( 'url=s' => \$Torrus::Email::url,
+ 'template=s' => \$Torrus::Email::template );
+
+if( not $ok )
+{
+ print STDERR ("Error parsing options\n");
+ exit 1;
+}
+
+my $tt = new Template(INCLUDE_PATH => $Torrus::Global::templateDirs);
+
+my $vars =
+{
+ 'tree' => $ENV{'TORRUS_TREE'},
+ 'token' => $ENV{'TORRUS_TOKEN'},
+ 'path' => $ENV{'TORRUS_NODEPATH'},
+ 'nickname' => $ENV{'TORRUS_NICKNAME'},
+ 'url' => $Torrus::Email::url . '/' .
+ $ENV{'TORRUS_TREE'} . '?token='.$ENV{'TORRUS_TOKEN'},
+ 'ncomment' => $ENV{'TORRUS_NCOMMENT'},
+ 'npcomment' => $ENV{'TORRUS_NPCOMMENT'},
+ 'event' => $ENV{'TORRUS_EVENT'},
+ 'monitor' => $ENV{'TORRUS_MONITOR'},
+ 'mcomment' => $ENV{'TORRUS_MCOMMENT'},
+ 'severity' => $ENV{'TORRUS_SEVERITY'},
+ 'timestamp' => scalar(localtime($ENV{'TORRUS_TSTAMP'})),
+ 'value' => $ENV{'TORRUS_VALUE'},
+ 'dispvalue' => $ENV{'TORRUS_DISPLAY_VALUE'},
+ 'env' => sub { return $ENV{$_[0]} }
+};
+
+my $result = $tt->process($Torrus::Email::template, $vars);
+
+if( not $result )
+{
+ print STDERR "Error while processing template: ".$tt->error()."\n";
+}
+
+exit( $result ? 0:1 );
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/action_snmptrap.in b/torrus/bin/action_snmptrap.in
new file mode 100644
index 000000000..c2e9c20bb
--- /dev/null
+++ b/torrus/bin/action_snmptrap.in
@@ -0,0 +1,183 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: action_snmptrap.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# SNMP v2c trap
+# See Torrus-MIB.txt for reference
+
+use strict;
+use Net::SNMP qw(:ALL);
+use Getopt::Long;
+
+require '@snmptrap_siteconfig_pl@';
+
+if( not $ENV{'TORRUS_TOKEN'} )
+{
+ print STDERR ("Torrus environment variables missing. This program ",
+ "must be run from Torrus Monitor\n");
+ exit 1;
+}
+
+my @hosts;
+my $severity;
+
+my $ok = GetOptions( 'host=s' => \@hosts,
+ 'community=s' => \$Torrus::Snmptrap::community,
+ 'port=i' => \$Torrus::Snmptrap::port,
+ 'severity=i' => \$severity );
+
+if( not $ok )
+{
+ print STDERR ("Error parsing options\n");
+ exit 1;
+}
+
+if( scalar(@hosts) > 0 )
+{
+ @Torrus::Snmptrap::hosts = @hosts;
+}
+
+my $oid_prefix = '.1.3.6.1.4.1.14697.1.1.1';
+
+my %event_type = ( 'set' => 1,
+ 'repeat' => 2,
+ 'clear' => 3,
+ 'forget' => 4
+ );
+
+my @varbindlist = ( $oid_prefix . '.1',
+ INTEGER32, 1,
+
+ $oid_prefix . '.2',
+ OCTET_STRING, $ENV{'TORRUS_TOKEN'},
+
+ $oid_prefix . '.3',
+ OCTET_STRING, $ENV{'TORRUS_MONITOR'},
+
+ $oid_prefix . '.4',
+ INTEGER, $event_type{$ENV{'TORRUS_EVENT'}},
+
+ $oid_prefix . '.5',
+ OCTET_STRING, $ENV{'TORRUS_NODEPATH'},
+
+ $oid_prefix . '.6',
+ OCTET_STRING, snmp_dateandtime( $ENV{'TORRUS_TSTAMP'} ),
+
+ $oid_prefix . '.7',
+ OCTET_STRING, $ENV{'TORRUS_TREE'},
+
+ $oid_prefix . '.9',
+ OCTET_STRING, $ENV{'TORRUS_MCOMMENT'}
+ );
+
+if( defined( $severity ) )
+{
+ push( @varbindlist,
+ $oid_prefix . '.8',
+ INTEGER32, $severity );
+}
+
+
+foreach my $host ( @Torrus::Snmptrap::hosts )
+{
+ my( $session, $error ) =
+ Net::SNMP->session( -hostname => $host,
+ -community => $Torrus::Snmptrap::community,
+ -port => $Torrus::Snmptrap::port,
+ -version => 2
+ );
+
+ if( not defined($session) )
+ {
+ printf STDERR ("Error opening SNMP trap session: %s.\n", $error);
+ exit 1;
+ }
+
+
+ my $result =
+ $session->snmpv2_trap( -varbindlist => \@varbindlist );
+
+ if( not $result )
+ {
+ printf STDERR ("Error sending SNMP trap: %s.\n", $session->error());
+ }
+
+ $session->close();
+}
+
+# Converts UNIX time to DateAndTime from SNMPv2-TC
+# Currently timezone is not handled.
+
+# DateAndTime ::= TEXTUAL-CONVENTION
+# DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+# STATUS current
+# DESCRIPTION
+# "A date-time specification.
+#
+# field octets contents range
+# ----- ------ -------- -----
+# 1 1-2 year* 0..65536
+# 2 3 month 1..12
+# 3 4 day 1..31
+# 4 5 hour 0..23
+# 5 6 minutes 0..59
+# 6 7 seconds 0..60
+# (use 60 for leap-second)
+# 7 8 deci-seconds 0..9
+# 8 9 direction from UTC '+' / '-'
+# 9 10 hours from UTC* 0..13
+# 10 11 minutes from UTC 0..59
+#
+# * Notes:
+# - the value of year is in network-byte order
+# - daylight saving time in New Zealand is +13
+#
+# For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+# displayed as:
+#
+# 1992-5-26,13:30:15.0,-4:0
+#
+# Note that if only local time is known, then timezone
+# information (fields 8-10) is not present."
+# SYNTAX OCTET STRING (SIZE (8 | 11))
+
+sub snmp_dateandtime
+{
+ my $thetime = shift;
+
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
+ localtime( $thetime );
+
+ my $result = pack('nC6',
+ $year + 1900,
+ $mon + 1,
+ $mday,
+ $hour,
+ $min,
+ $sec,
+ 0);
+ return $result;
+}
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/action_snmpv1trap.in b/torrus/bin/action_snmpv1trap.in
new file mode 100644
index 000000000..02ec14a31
--- /dev/null
+++ b/torrus/bin/action_snmpv1trap.in
@@ -0,0 +1,134 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: action_snmpv1trap.in,v 1.1 2010-12-27 00:04:02 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Obsoleted and not used SNMP v1 trap script.
+# Version 2c is preferred one.
+
+
+use strict;
+use Net::SNMP qw(:ALL);
+use Getopt::Long;
+
+require '@snmptrap_siteconfig_pl@';
+
+# SNMP Enterprise. Needed for SNMP v1 trap.
+# See http://www.iana.org/assignments/enterprise-numbers for reference
+$Torrus::Snmptrap::enterprise = '1.3.6.1.4.1.14697.1.1.1';
+
+
+if( not $ENV{'TORRUS_TOKEN'} )
+{
+ print STDERR ("Torrus environment variables missing. This program ",
+ "must be run from Torrus Monitor\n");
+ exit 1;
+}
+
+my @hosts;
+my $severity;
+
+my $ok = GetOptions( 'host=s' => \@hosts,
+ 'community=s' => \$Torrus::Snmptrap::community,
+ 'port=i' => \$Torrus::Snmptrap::port,
+ 'enterprise' => \$Torrus::Snmptrap::enterprise,
+ 'severity=i' => \$severity );
+
+if( not $ok )
+{
+ print STDERR ("Error parsing options\n");
+ exit 1;
+}
+
+if( scalar(@hosts) > 0 )
+{
+ @Torrus::Snmptrap::hosts = @hosts;
+}
+
+my %specifictrap = ( 'set' => 1,
+ 'repeat' => 2,
+ 'clear' => 3,
+ 'forget' => 4
+ );
+
+my @varbindlist = ( $Torrus::Snmptrap::enterprise . '.2',
+ OCTET_STRING, $ENV{'TORRUS_TOKEN'},
+
+ $Torrus::Snmptrap::enterprise . '.5',
+ OCTET_STRING, $ENV{'TORRUS_NODEPATH'},
+
+ $Torrus::Snmptrap::enterprise . '.3',
+ OCTET_STRING, $ENV{'TORRUS_MONITOR'},
+
+ $Torrus::Snmptrap::enterprise . '.4',
+ OCTET_STRING, $ENV{'TORRUS_EVENT'},
+
+ $Torrus::Snmptrap::enterprise . '.6',
+ OCTET_STRING, scalar(localtime($ENV{'TORRUS_TSTAMP'})),
+
+ $Torrus::Snmptrap::enterprise . '.7',
+ OCTET_STRING, $ENV{'TORRUS_TREE'},
+
+ $Torrus::Snmptrap::enterprise . '.9',
+ OCTET_STRING, $ENV{'TORRUS_MCOMMENT'}
+ );
+
+if( defined( $severity ) )
+{
+ push( @varbindlist,
+ $Torrus::Snmptrap::enterprise . '.8',
+ INTEGER32, $severity );
+}
+
+foreach my $host ( @Torrus::Snmptrap::hosts )
+{
+ my( $session, $error ) =
+ Net::SNMP->session( -hostname => $host,
+ -community => $Torrus::Snmptrap::community,
+ -port => $Torrus::Snmptrap::port
+ );
+
+ if( not defined($session) )
+ {
+ printf STDERR ("Error opening SNMP trap session: %s.\n", $error);
+ exit 1;
+ }
+
+
+ my $result =
+ $session->trap( -enterprise => $Torrus::Snmptrap::enterprise,
+ -generictrap => ENTERPRISE_SPECIFIC,
+ -specifictrap => $specifictrap{$ENV{'TORRUS_EVENT'}},
+ -timestamp => $ENV{'TORRUS_UPTIME'} * 100,
+ -varbindlist => \@varbindlist
+ );
+
+ if( not $result )
+ {
+ printf STDERR ("Error sending SNMP trap: %s.\n", $session->error());
+ }
+
+ $session->close();
+}
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/bdbinfo.in b/torrus/bin/bdbinfo.in
new file mode 100644
index 000000000..c5628acbf
--- /dev/null
+++ b/torrus/bin/bdbinfo.in
@@ -0,0 +1,38 @@
+#!@PERL@ -w
+# Copyright (C) 2002-2008 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: bdbinfo.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use BerkeleyDB;
+
+
+printf("MAJOR: %d\n", DB_VERSION_MAJOR);
+printf("MINOR: %d\n", DB_VERSION_MINOR);
+printf("PATCH: %d\n", DB_VERSION_PATCH);
+printf("STRING: %s\n", DB_VERSION_STRING);
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/buildsearchdb.in b/torrus/bin/buildsearchdb.in
new file mode 100644
index 000000000..19c1ea8ff
--- /dev/null
+++ b/torrus/bin/buildsearchdb.in
@@ -0,0 +1,200 @@
+#!@PERL@ -w
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: buildsearchdb.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::ConfigTree;
+use Torrus::Search;
+use Torrus::SiteConfig;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+my @trees;
+my $build_global;
+my $all_trees;
+
+my $verbose;
+my $help_needed;
+
+my $ok = GetOptions ('tree=s' => \@trees,
+ 'all' => \$all_trees,
+ 'global' => \$build_global,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not (scalar(@trees) or $all_trees or $build_global) or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME rebuild search DB for a tree\n",
+ " --all rebuild search DB for all trees\n",
+ " --global rebuild global search DB\n",
+ " --verbose print extra information\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( $build_global )
+{
+ $all_trees = 1;
+}
+
+if( $all_trees )
+{
+ @trees = Torrus::SiteConfig::listTreeNames();
+}
+
+if( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+Verbose(sprintf('Torrus version %s', '@VERSION@'));
+
+my $search = new Torrus::Search( -WriteAccess => 1 );
+
+if( $build_global )
+{
+ $search->openGlobal();
+}
+
+foreach my $tree ( @trees )
+{
+ if( not Torrus::SiteConfig::treeExists( $tree ) )
+ {
+ Error("Tree named \"" . $tree . "\" does not exist");
+ exit(1);
+ }
+
+ &Torrus::DB::checkInterrupted();
+
+ my $config_tree = new Torrus::ConfigTree( -TreeName => $tree );
+ if( not defined($config_tree) )
+ {
+ print("Configuration is not ready\n");
+ exit(1);
+ }
+
+ Verbose("Processing the tree: $tree");
+
+ $search->openTree( $tree );
+
+ walkSubtree( $config_tree, $search, $config_tree->token('/') );
+
+ $search->closeTree( $tree );
+ $config_tree = undef;
+}
+
+exit(0);
+
+
+sub walkSubtree
+{
+ my $config_tree = shift;
+ my $search = shift;
+ my $ptoken = shift;
+
+ my $tree = $config_tree->treeName();
+
+ foreach my $token ( $config_tree->getChildren( $ptoken ) )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ if( $config_tree->isSubtree( $token ) )
+ {
+ walkSubtree( $config_tree, $search, $token );
+ }
+
+ my $isSearchable =
+ $config_tree->getNodeParam( $token, 'searchable', 1 );
+ if( defined( $isSearchable ) and $isSearchable eq 'yes' )
+ {
+ my $path = $config_tree->path( $token );
+
+ my $nodeName = $config_tree->nodeName( $path );
+ splitAndStore( $tree, $nodeName, $path );
+
+ my $params = $config_tree->getParams( $token, 1 );
+ while( my( $param, $value ) = each %{$params} )
+ {
+ if( $config_tree->getParamProperty( $param, 'search' ) )
+ {
+ splitAndStore( $tree, $value, $path, $param );
+ }
+ }
+ }
+ }
+}
+
+
+sub splitAndStore
+{
+ my $tree = shift;
+ my $value = shift;
+ my $path = shift;
+ my $param = shift;
+
+ if( length( $value ) > 0 )
+ {
+ # split the value into words
+ my @words = split( /\W+/ms, $value );
+ if( scalar( @words ) > 0 )
+ {
+ foreach my $word ( @words )
+ {
+ if( length( $word ) > 1 )
+ {
+ $search->storeKeyword( $tree, $word, $path, $param );
+
+ # Split the word by underscores and minus
+ my @subwords = split( /_+/, $word );
+ if( scalar( @subwords ) > 1 )
+ {
+ foreach my $subword ( @subwords )
+ {
+ if( length( $subword ) > 1 )
+ {
+ $search->storeKeyword( $tree,
+ $subword,
+ $path,
+ $param );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/cleanup.in b/torrus/bin/cleanup.in
new file mode 100644
index 000000000..bc4f69fba
--- /dev/null
+++ b/torrus/bin/cleanup.in
@@ -0,0 +1,32 @@
+#!@SHELL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: cleanup.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+#
+
+# How soon the sessions expire
+EXPIRE=60
+
+@FIND@ @sesstordir@ -type f -mtime +$EXPIRE -exec @RM@ '{}' ';'
+@FIND@ @seslockdir@ -type f -mtime +$EXPIRE -exec @RM@ '{}' ';'
+
+# Local Variables:
+# mode: shell-script
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/clearcache.in b/torrus/bin/clearcache.in
new file mode 100644
index 000000000..a3c0365d9
--- /dev/null
+++ b/torrus/bin/clearcache.in
@@ -0,0 +1,40 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: clearcache.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use Torrus::Log;
+
+use Torrus::Renderer;
+
+&Torrus::DB::setSafeSignalHandlers();
+
+my $renderer = new Torrus::Renderer;
+$renderer->clearcache();
+undef $renderer;
+
+Info('Renderer cache cleared');
+exit 0;
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/collector.in b/torrus/bin/collector.in
new file mode 100644
index 000000000..e682fadc8
--- /dev/null
+++ b/torrus/bin/collector.in
@@ -0,0 +1,205 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: collector.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Proc::Daemon;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::ConfigTree;
+use Torrus::Collector;
+use Torrus::SiteConfig;
+
+$| = 1;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+my $tree;
+my $instance;
+my $nodaemon;
+my $runonce;
+my $runalways;
+my $debug;
+my $verbose;
+my $help_needed;
+
+# Derive the process name from the command line
+my $process_name = $0;
+$process_name =~ s/^.*\/([^\/]+)$/$1/;
+$process_name .= ' ' . join(' ', @ARGV);
+
+my $ok = GetOptions ('tree=s' => \$tree,
+ 'instance=i' => \$instance,
+ 'nodaemon' => \$nodaemon,
+ 'runonce' => \$runonce,
+ 'runalways' => \$runalways,
+ 'debug' => \$debug,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not $tree or $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --instance=N instance number for multiple collectors per tree\n",
+ " --nodaemon do not fork daemon and log to STDERR\n",
+ " --runonce run one time and exit. Implies --nodaemon\n",
+ " --runalways continue running if no collectors defined\n",
+ " --debug set the log level to debug\n",
+ " --verbose set the log level to info\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( not Torrus::SiteConfig::mayRunCollector( $tree ) )
+{
+ Error('Tree ' . $tree . ' is not configured to run collector');
+ exit 1;
+}
+
+my $nInstances = Torrus::SiteConfig::collectorInstances( $tree );
+
+if( $nInstances > 1 and not defined( $instance ) )
+{
+ Error('--instance option is missing');
+ exit 1;
+}
+
+if( not defined( $instance ) )
+{
+ $instance = 0;
+}
+
+if( $instance >= $nInstances )
+{
+ Error('Invalid instance number. Allowed from 0 to ' . ($nInstances-1));
+ exit 1;
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+my $logfile =
+ $Torrus::Global::logDir . '/collector.' . $tree . '_' . $instance . '.log';
+my $pidfile;
+
+my $rotateLogs = sub
+{
+ Info('Caught SIGHUP. Reopening log file');
+ close( STDERR );
+ open( STDERR, ">>$logfile" );
+ $| = 1;
+};
+
+if( not $nodaemon and not $runonce )
+{
+ my $pidfilename =
+ $Torrus::Global::pidDir . '/collector.' .
+ $tree . '_' . $instance . '.pid';
+
+ if( -r $pidfilename )
+ {
+ Error("Another collector daemon is running, pid=",
+ `cat $pidfilename`);
+ exit 1;
+ }
+
+ &Proc::Daemon::Init();
+ umask 0017; # Proc::Daemon::Init sets the mask to all-writable
+
+ $SIG{'HUP'} = $rotateLogs;
+
+ # At this point, we cannot tell anyone if "open" fails
+ open(STDERR, ">>$logfile");
+
+ $pidfile = $pidfilename;
+
+ if( open( PID, ">$pidfile" ) )
+ {
+ printf PID ( "%d", $$ );
+ close PID;
+ }
+ else
+ {
+ Error("Cannot open $pidfile for writing: $!");
+ }
+}
+
+
+Torrus::Collector::initThreads();
+
+&Torrus::DB::setSafeSignalHandlers();
+
+
+Info(sprintf("Torrus version %s", '@VERSION@'));
+Info(sprintf("%s started for tree %s, instance #%d", $0, $tree, $instance));
+Debug(sprintf("Process ID %d", $$));
+
+my %options =
+ (
+ '-ProcessName' => $process_name,
+ '-Tree' => $tree,
+ '-Instance' => $instance
+ );
+
+if( $runonce )
+{
+ $options{'-RunOnce'} = 1;
+}
+if( $runalways )
+{
+ $options{'-RunAlways'} = 1;
+}
+
+
+my $scheduler = new Torrus::CollectorScheduler( %options );
+$scheduler->run();
+
+if( not $options{'-RunOnce'} )
+{
+ Error("Collector process exited: nothing to collect");
+ unlink $pidfile;
+}
+
+exit;
+
+
+END
+{
+ if( defined($pidfile) and -r $pidfile )
+ {
+ unlink $pidfile;
+ }
+}
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/compilexml.in b/torrus/bin/compilexml.in
new file mode 100644
index 000000000..56bbada0a
--- /dev/null
+++ b/torrus/bin/compilexml.in
@@ -0,0 +1,207 @@
+#!@PERL@ -w
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: compilexml.in,v 1.1 2010-12-27 00:04:00 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use Getopt::Long;
+use strict;
+
+use Torrus::ConfigTree::XMLCompiler;
+use Torrus::SiteConfig;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+our @trees;
+our $all_trees;
+our $no_ds;
+our $no_validation;
+our $force;
+
+our $debug;
+our $verbose;
+our $help_needed;
+
+my $ok = GetOptions ('tree=s' => \@trees,
+ 'all' => \$all_trees,
+ 'nods' => \$no_ds,
+ 'noval' => \$no_validation,
+ 'force' => \$force,
+ 'debug' => \$debug,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not (scalar(@trees) or $all_trees) or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name(s) to compile\n",
+ " --all compile all trees\n",
+ " --nods compile non-datasource configuration only\n",
+ " --noval disable parameter validation\n",
+ " --force force the compiler even if anoother " .
+ "compiler process is probably running\n",
+ " --debug set the log level to debug\n",
+ " --verbose set the log level to info\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( $all_trees )
+{
+ @trees = Torrus::SiteConfig::listTreeNames();
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+
+&Torrus::DB::setSafeSignalHandlers();
+
+Verbose(sprintf('Torrus version %s', '@VERSION@'));
+
+our $global_ok = 1;
+
+foreach my $tree ( @trees )
+{
+ if( not Torrus::SiteConfig::treeExists( $tree ) )
+ {
+ Error("Tree named \"" . $tree . "\" does not exist");
+ exit(1);
+ }
+
+ &Torrus::DB::checkInterrupted();
+
+ Verbose("Compiling tree: $tree");
+
+ my $ok = 1;
+ my $compiler =
+ new Torrus::ConfigTree::XMLCompiler( -TreeName => $tree,
+ -NoDSRebuild => $no_ds,
+ -ForceWriter => $force );
+ if( not defined( $compiler ) )
+ {
+ Error('Cannot initialize compiler for tree ' . $tree . '. Exiting');
+ Error('If you are sure there are no other compiler processes ' .
+ 'running, use the --force option');
+ $global_ok = 0;
+ last;
+ }
+
+ my @xmlFiles = @Torrus::Global::xmlAlwaysIncludeFirst;
+ push( @xmlFiles, Torrus::SiteConfig::listXmlFiles( $tree ) );
+ push( @xmlFiles, @Torrus::Global::xmlAlwaysIncludeLast );
+
+ foreach my $xmlfile ( @xmlFiles )
+ {
+ if( not $compiler->compile( $xmlfile ) )
+ {
+ Error($xmlfile . ' compiled with errors'); $ok = 0;
+ }
+ }
+
+ if( not $ok )
+ {
+ Error("Errors found during XML compilation in the tree named \"" .
+ $tree . "\"");
+ $global_ok = 0;
+ last;
+ }
+
+ Verbose('Data post-processing...');
+ if( not $compiler->postProcess() )
+ {
+ Error('Errors found during post-processing');
+ $ok = 0;
+ }
+
+ if( $no_validation )
+ {
+ Verbose('Skipping data validation...');
+ }
+ else
+ {
+ Verbose('Data validation...');
+ if( not $compiler->validate() )
+ {
+ Error('Errors found during validation process');
+ $ok = 0;
+ }
+ }
+
+ &Torrus::DB::checkInterrupted();
+
+ # Preserve the dynamic tokenset members
+ if( not $compiler->{'first_time_created'} )
+ {
+ my $oldConfig = new Torrus::ConfigTree( -TreeName => $tree );
+ if( defined( $oldConfig ) )
+ {
+ foreach my $ts ( $oldConfig->getTsets() )
+ {
+ if( $compiler->tsetExists( $ts ) )
+ {
+ foreach my $member ( $oldConfig->tsetMembers( $ts ) )
+ {
+ my $origin = $oldConfig->tsetMembers( $ts, $member );
+ if( defined( $origin ) and $origin ne 'static' )
+ {
+ my $path = $oldConfig->path($member);
+ if( $compiler->nodeExists( $path ) )
+ {
+ my $token = $compiler->token( $path );
+ $compiler->tsetAddMember
+ ( $ts, $token, $origin );
+ Verbose('Preserved dynamic tokenset member: ' .
+ $path . ' in ' . $ts);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ undef $oldConfig;
+ }
+
+ &Torrus::DB::checkInterrupted();
+
+ $compiler->finalize( $ok );
+ undef $compiler;
+ &Torrus::DB::cleanupEnvironment();
+
+ $global_ok = $ok ? $global_ok:0;
+}
+
+exit($global_ok ? 0:1);
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/configinfo.in b/torrus/bin/configinfo.in
new file mode 100644
index 000000000..1b985f88c
--- /dev/null
+++ b/torrus/bin/configinfo.in
@@ -0,0 +1,166 @@
+#!@PERL@ -w
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: configinfo.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use BerkeleyDB;
+
+use Torrus::ConfigTree;
+use Torrus::TimeStamp;
+use Torrus::SiteConfig;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+&Torrus::DB::setSafeSignalHandlers();
+
+Torrus::TimeStamp::init();
+
+my @tree_names = Torrus::SiteConfig::listTreeNames();
+
+
+printf("Torrus version %s\n", '@VERSION@');
+printf("%s\n", DB_VERSION_STRING);
+printf("BerkeleyDB.pm version %s\n", $BerkeleyDB::VERSION);
+printf("\n");
+
+printf("Datasource trees: %d\n", scalar( @tree_names ) );
+printf("Tree names: %s\n", join(', ', @tree_names) );
+printf("\n");
+
+foreach my $tree ( @tree_names )
+{
+ &Torrus::DB::checkInterrupted();
+
+ printf("Tree: %s\n", $tree );
+
+ my $config_tree = new Torrus::ConfigTree( -TreeName => $tree );
+ if( not defined($config_tree) )
+ {
+ print("Configuration is not ready\n");
+ }
+ else
+ {
+ my $stats = {};
+ foreach my $name ( 'leaves', 'collectorLeaves', 'monitorLeaves',
+ 'holtwintersLeaves', 'subtrees',
+ 'maxSubtreePath', 'maxSubtreeSize', 'views',
+ 'monitors', 'actions', 'compiled' )
+ {
+ $stats->{$name} = 0;
+ }
+
+ collectStats( $config_tree, $stats );
+ collectOtherStats( $config_tree, $stats );
+
+ printf("Leaves: %d\n", $stats->{'leaves'} );
+ printf("Collector leaves: %d\n", $stats->{'collectorLeaves'} );
+ printf("Monitor leaves: %d\n", $stats->{'monitorLeaves'} );
+ printf("Holt-Winters leaves: %d\n", $stats->{'holtwintersLeaves'} );
+ printf("Subtrees: %d\n", $stats->{'subtrees'} );
+ printf("Largest subtree: %s\n", $stats->{'maxSubtreePath'} );
+ printf("Largest subtree size: %d\n", $stats->{'maxSubtreeSize'} );
+ printf("Views: %d\n", $stats->{'views'} );
+ printf("Monitors: %d\n", $stats->{'monitors'} );
+ printf("Actions: %d\n", $stats->{'actions'} );
+ printf("Last compiled: %s\n",
+ scalar(localtime($stats->{'compiled'})));
+ printf("\n");
+ }
+}
+
+
+sub collectStats
+{
+ my $config_tree = shift;
+ my $stats = shift;
+ my $token = shift;
+
+ &Torrus::DB::checkInterrupted();
+
+ if( not defined( $token ) )
+ {
+ $token = $config_tree->token('/');
+ }
+
+ my @children = $config_tree->getChildren( $token );
+
+ my $nChildren = scalar( @children );
+ if( not defined( $stats->{'maxSubtreeSize'} ) or
+ $stats->{'maxSubtreeSize'} < $nChildren )
+ {
+ $stats->{'maxSubtreeSize'} = $nChildren;
+ $stats->{'maxSubtreePath'} = $config_tree->path( $token );
+ }
+
+ foreach my $ctoken ( @children )
+ {
+ if( $config_tree->isSubtree( $ctoken ) )
+ {
+ $stats->{'subtrees'}++;
+ collectStats( $config_tree, $stats, $ctoken );
+ }
+ elsif( $config_tree->isLeaf( $ctoken ) )
+ {
+ $stats->{'leaves'}++;
+ if( $config_tree->getNodeParam( $ctoken, 'ds-type' )
+ eq 'collector' )
+ {
+ $stats->{'collectorLeaves'}++;
+ }
+ if( defined( $config_tree->getNodeParam( $ctoken, 'monitor' ) ) )
+ {
+ $stats->{'monitorLeaves'}++;
+ }
+ my $val = $config_tree->getNodeParam( $ctoken, 'rrd-hwpredict' );
+ if( defined( $val ) and $val eq 'enabled' )
+ {
+ $stats->{'holtwintersLeaves'}++;
+ }
+ }
+ }
+}
+
+
+sub collectOtherStats
+{
+ my $config_tree = shift;
+ my $stats = shift;
+
+ my $n = scalar( $config_tree->getViewNames() );
+ $stats->{'views'} = $n if defined( $n );
+
+ $n = scalar( $config_tree->getMonitorNames() );
+ $stats->{'monitors'} = $n if defined( $n );
+
+ $n = scalar( $config_tree->getActionNames() );
+ $stats->{'actions'} = $n if defined( $n );
+
+ $n = $config_tree->getTimestamp();
+ $stats->{'compiled'} = $n if defined( $n );
+}
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/configsnapshot.in b/torrus/bin/configsnapshot.in
new file mode 100644
index 000000000..dc79e5bdb
--- /dev/null
+++ b/torrus/bin/configsnapshot.in
@@ -0,0 +1,332 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: configsnapshot.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::ConfigTree;
+use Torrus::SiteConfig;
+use Torrus::ConfigBuilder;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+my $tree;
+my $help_needed;
+my $verbose = 0;
+
+my $outfile = 'snapshot.xml';
+
+my $filter_param;
+my $filter_value;
+my $filter_op = '=';
+
+my $creator = "Torrus version @VERSION@\n" .
+ "This file was generated by command:\n" .
+ $0 . " \\\n";
+foreach my $arg ( @ARGV )
+{
+ if( $arg =~ /^--/ )
+ {
+ $creator .= ' ' . $arg . ' ';
+ }
+ else
+ {
+ $creator .= "\'" . $arg . "\'\\\n";
+ }
+}
+$creator .= "\nOn " . scalar(localtime(time));
+
+my $ok = GetOptions('tree=s' => \$tree,
+ 'out=s' => \$outfile,
+ 'param=s' => \$filter_param,
+ 'value=s' => \$filter_value,
+ 'op=s' => \$filter_op,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not $tree or $help_needed or
+ ( defined($filter_param) + defined($filter_value) == 1 ) or
+ ( $filter_op ne '=' and $filter_op ne 'eq' and $filter_op ne 're' ) or
+ scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --out=filename output file [".$outfile."]\n",
+ " --param=PARAM --value=VALUE \n",
+ " filter the output by leaves with specified value\n",
+ " --op=OP filter operation [=|eq|re], default: [=]\n",
+ " --verbose print extra information\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+if( not Torrus::SiteConfig::treeExists( $tree ) )
+{
+ Error('Tree ' . $tree . ' does not exist');
+ exit 1;
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+my $config_tree = new Torrus::ConfigTree( -TreeName => $tree, -Wait => 1 );
+if( not defined( $config_tree ) )
+{
+ exit 1;
+}
+
+
+my $filter_match = sub {return $_[0] == $filter_value};
+
+if(defined($filter_param))
+{
+ if( $filter_op eq 'eq' )
+ {
+ $filter_match = sub {return $_[0] eq $filter_value};
+ }
+ elsif( $filter_op eq 're' )
+ {
+ $filter_match = sub {return $_[0] =~ $filter_value};
+ }
+}
+
+
+
+my $cb = new Torrus::ConfigBuilder;
+
+$cb->addCreatorInfo( $creator );
+
+# We don't collect views, since they are in defaults.xml which is always
+# included
+
+collect_monitors( $config_tree, $cb );
+collect_tokensets( $config_tree, $cb );
+collect_definitions( $config_tree, $cb );
+collect_datasources( $config_tree, $cb );
+
+my $ok = $cb->toFile( $outfile );
+if( $ok )
+{
+ Verbose('Wrote ' . $outfile);
+}
+else
+{
+ Error('Cannot write ' . $outfile . ': ' . $!);
+}
+
+exit($ok ? 0:1);
+
+sub collect_monitors
+{
+ my $config_tree = shift;
+ my $cb = shift;
+
+ my $monitorsNode = $cb->startMonitors();
+
+ foreach my $action ( $config_tree->getActionNames() )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ my $params = $config_tree->getParams( $action );
+ $cb->addMonitorAction( $monitorsNode, $action, $params );
+ }
+
+ foreach my $monitor ( $config_tree->getMonitorNames() )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ my $params = $config_tree->getParams( $monitor );
+ $cb->addMonitor( $monitorsNode, $monitor, $params );
+ }
+}
+
+sub collect_tokensets
+{
+ my $config_tree = shift;
+ my $cb = shift;
+
+ my $tsetsNode = $cb->startTokensets();
+
+ foreach my $tset ( $config_tree->getTsets() )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ my $params = $config_tree->getParams( $tset );
+ my $name = $tset;
+ $name =~ s/^S//;
+ $cb->addTokenset( $tsetsNode, $name, $params );
+ }
+}
+
+
+sub collect_definitions
+{
+ my $config_tree = shift;
+ my $cb = shift;
+
+ my $definitionsNode = $cb->startDefinitions();
+
+ foreach my $defName ( sort $config_tree->getDefinitionNames() )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ my $value = $config_tree->getDefinition( $defName );
+ $cb->addDefinition( $definitionsNode, $defName, $value );
+ }
+
+ my $propsNode = $cb->startParamProps();
+ my $props = $config_tree->getParamProperties();
+
+ &Torrus::DB::checkInterrupted();
+
+ foreach my $prop ( sort keys %{$props} )
+ {
+ foreach my $param ( sort keys %{$props->{$prop}} )
+ {
+ $cb->addParamProp( $propsNode, $param, $prop,
+ $props->{$prop}{$param} );
+ }
+ }
+}
+
+
+my %filterTokens;
+
+
+sub collect_datasources
+{
+ my $config_tree = shift;
+ my $cb = shift;
+
+ my $topNode = $cb->getTopSubtree();
+ my $topToken = $config_tree->token('/');
+
+ my $params = prepare_params( $config_tree, $topToken );
+ $cb->addParams( $topNode, $params );
+
+ if( defined($filter_param) )
+ {
+ $filterTokens{$topToken} = apply_filter( $config_tree, $topToken );
+ }
+
+ collect_subtrees( $config_tree, $cb, $topToken, $topNode );
+}
+
+
+
+sub apply_filter
+{
+ my $config_tree = shift;
+ my $token = shift;
+
+ $filterTokens{$token} = 0;
+
+ foreach my $ctoken ( $config_tree->getChildren( $token ) )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ if( $config_tree->isSubtree( $ctoken ) )
+ {
+ $filterTokens{$token} += apply_filter( $config_tree, $ctoken );
+ }
+ elsif( $config_tree->isLeaf( $ctoken ) )
+ {
+ my $val = $config_tree->getNodeParam( $ctoken, $filter_param );
+ if( defined($val) and &{$filter_match}($val) )
+ {
+ $filterTokens{$ctoken} = 1;
+ $filterTokens{$token}++;
+ }
+ }
+ }
+
+ return $filterTokens{$token};
+}
+
+
+
+sub collect_subtrees
+{
+ my $config_tree = shift;
+ my $cb = shift;
+ my $token = shift;
+ my $parentNode = shift;
+
+ foreach my $ctoken ( $config_tree->getChildren( $token ) )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ if( not defined($filter_param) or $filterTokens{$ctoken} )
+ {
+ my $childName =
+ $config_tree->nodeName( $config_tree->path($ctoken) );
+ my $params = prepare_params( $config_tree, $ctoken );
+
+ if( $config_tree->isSubtree( $ctoken ) )
+ {
+ my $subtreeNode =
+ $cb->addSubtree( $parentNode, $childName, $params );
+ collect_subtrees( $config_tree, $cb, $ctoken, $subtreeNode );
+ }
+ elsif( $config_tree->isLeaf( $ctoken ) )
+ {
+ $cb->addLeaf( $parentNode, $childName, $params );
+ }
+
+ foreach my $aliasToken ( $config_tree->getAliases( $ctoken ) )
+ {
+ $cb->addAlias( $parentNode,
+ $config_tree->path( $aliasToken ) );
+ }
+ }
+ }
+}
+
+
+sub prepare_params
+{
+ my $config_tree = shift;
+ my $token = shift;
+
+ my $params = $config_tree->getParams( $token, 1 );
+
+ # Remove linebreaks
+ while( my( $param, $value ) = each %{$params} )
+ {
+ $value =~ s/\s+/ /gm;
+ $params->{$param} = $value;
+ }
+
+ return $params;
+}
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/devdiscover.in b/torrus/bin/devdiscover.in
new file mode 100644
index 000000000..f11372308
--- /dev/null
+++ b/torrus/bin/devdiscover.in
@@ -0,0 +1,619 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: devdiscover.in,v 1.1 2010-12-27 00:04:02 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Collect the router information and create the XML file
+
+BEGIN { require '@devdiscover_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+use XML::LibXML;
+
+use Torrus::Log;
+use Torrus::DevDiscover;
+use Torrus::ConfigBuilder;
+
+$| = 1;
+
+my @infiles;
+my $makedirs;
+my $limitre;
+my $forcebundle;
+my $fallback;
+my $workerThreads = 0;
+
+# Hidden parameter for debugging
+my $snmpdebug = 0;
+my $debug = 0;
+my $verbose = 0;
+
+my %formatsSupported = ( '1.0' => 1 );
+
+
+my $creator = "Torrus version @VERSION@\n" .
+ "This file was generated by command:\n" .
+ $0 . " \\\n";
+foreach my $arg ( @ARGV )
+{
+ if( $arg =~ /^--/ )
+ {
+ $creator .= ' ' . $arg . ' ';
+ }
+ else
+ {
+ $creator .= "\'" . $arg . "\'\\\n";
+ }
+}
+$creator .= "\n On " . scalar(localtime(time));
+
+my $ok = GetOptions(
+ 'in=s' => \@infiles,
+ 'mkdir' => \$makedirs,
+ 'limit=s' => \$limitre,
+ 'forcebundle' => \$forcebundle,
+ 'fallback=i' => \$fallback,
+ 'threads=i' => \$workerThreads,
+ 'snmpdebug' => \$snmpdebug,
+ 'verbose' => \$verbose,
+ 'debug' => \$debug
+ );
+if( $ok and scalar( @ARGV ) > 0 )
+{
+ push( @infiles, @ARGV );
+}
+
+if( not $ok or scalar(@infiles) == 0 or
+ ($workerThreads > 1 and not $Torrus::Global::threadsEnabled ) )
+{
+ print STDERR "Usage: $0 --in=filename.ddx options... [ddx files]\n",
+ "Options:\n",
+ " --in=filename.ddx discovery instructions XML file(s)\n",
+ " --mkdir create data-dir directories\n",
+ " --limit=regexp limit the discovery by output files\n",
+ " --forcebundle always write the bundle file\n",
+ " --fallback=integer maximum age of XML file to fall back to\n",
+ " --threads=integer number of parallel discovery threads\n",
+ " --verbose print extra information\n",
+ " --debug print debugging information\n",
+ " --snmpdebug print SNMP protocol details\n",
+ "\n";
+ if( not $Torrus::Global::threadsEnabled )
+ {
+ print STDERR "Multithreading is NOT SUPPORTED by current " .
+ "perl interpreter\n";
+ }
+
+ exit 1;
+}
+
+if( $snmpdebug )
+{
+ $Net::SNMP::Transport::UDP::DEBUG = 1;
+ $Net::SNMP::Message::DEBUG = 1;
+ $Net::SNMP::MessageProcessing::DEBUG = 1;
+ $Net::SNMP::Dispatcher::DEBUG = 1;
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+my $everythingsOk = 1;
+my $perOutfileHostParams = {};
+my %outputBundles;
+
+foreach my $infile ( @infiles )
+{
+ if( not -r $infile )
+ {
+ my $altfile = $Torrus::Global::discoveryDir . $infile;
+ if( not -r $altfile )
+ {
+ Error('Cannot find file ' . $infile .
+ ' neither in current directory nor in ' .
+ $Torrus::Global::discoveryDir);
+ exit 1;
+ }
+ else
+ {
+ $infile = $altfile;
+ }
+ }
+
+ Verbose('Processing ' . $infile);
+
+ my $parser = new XML::LibXML;
+ my $doc;
+ eval { $doc = $parser->parse_file( $infile ); };
+ if( $@ )
+ {
+ Error("Failed to parse $infile: $@");
+ exit 1;
+ }
+
+ my $root = $doc->documentElement();
+ if( $root->nodeName() ne 'snmp-discovery' )
+ {
+ Error('XML root element is not "snmp-discovery" in ' . $infile);
+ exit 1;
+ }
+
+ my $format_version =
+ (($root->getElementsByTagName('file-info'))[0]->
+ getElementsByTagName('format-version'))[0]->textContent();
+
+ $format_version =~ s/\s//g;
+
+ if( not $format_version or not $formatsSupported{$format_version} )
+ {
+ Error('Invalid format or format version not supported: ' . $infile);
+ exit 1;
+ }
+
+ my $globalParams = parseParams( $root );
+
+
+ # Parse the body of the XML
+
+ foreach my $hostNode ( $root->getChildrenByTagName('host') )
+ {
+ my $hostParams = parseParams( $hostNode, $globalParams );
+ normalizeParams( $hostParams );
+
+ my $outfile = $hostParams->{'output-file'};
+ if( not exists($perOutfileHostParams->{$outfile}) )
+ {
+ $perOutfileHostParams->{$outfile} = [];
+ }
+ push( @{$perOutfileHostParams->{$outfile}}, $hostParams );
+
+ my $outBundles = $hostParams->{'output-bundle'};
+ if( length( $outBundles ) > 0 )
+ {
+ foreach my $bundleName ( split( /\s*,\s*/, $outBundles ) )
+ {
+ $bundleName = absXmlFilename( $bundleName );
+ $outputBundles{$bundleName}{ relXmlFilename($outfile) } = 1;
+ }
+ }
+ }
+}
+
+
+# Start discovery
+my $jobQueue;
+my $bundleDeletionQueue;
+my $confBuildSemaphore;
+
+if( $workerThreads > 1 )
+{
+ require threads;
+ require threads::shared;
+ require Thread::Queue;
+ require Thread::Semaphore;
+
+ threads::shared::share( \$everythingsOk );
+
+ $jobQueue = new Thread::Queue;
+ $bundleDeletionQueue = new Thread::Queue;
+ $confBuildSemaphore = new Thread::Semaphore;
+
+ # Enqueue the output filenames
+ foreach my $outfile ( sort keys %{$perOutfileHostParams} )
+ {
+ if( not matchLimitRe( $outfile ) )
+ {
+ next;
+ }
+
+ $jobQueue->enqueue( $outfile );
+ }
+
+ # Start the worker threads
+ my @workers;
+ foreach my $i ( 1..$workerThreads )
+ {
+ push( @workers, threads->create( \&discoveryThread ) );
+ }
+
+ # Wait for workers to finish the jobs
+ while( my $thr = shift( @workers ) )
+ {
+ my $tid = $thr->tid();
+ $thr->join();
+ Debug('Cleaning up thread #' . $tid);
+ undef $thr;
+ }
+
+ # Process the files to be excluded from bundles
+
+ if( not $everythingsOk )
+ {
+ my $outfile;
+ while( defined( $outfile = $bundleDeletionQueue->dequeue_nb() ) )
+ {
+ removeFromBundle( $outfile );
+ }
+ }
+}
+else
+{
+ # Single-thread operation
+
+ foreach my $outfile ( sort keys %{$perOutfileHostParams} )
+ {
+ if( not matchLimitRe( $outfile ) )
+ {
+ next;
+ }
+
+ if( not doDiscover( $outfile ) )
+ {
+ removeFromBundle( $outfile );
+ }
+ }
+}
+
+# Discovery finished, do the bundles
+
+if( scalar( keys %outputBundles ) > 0 )
+{
+ if( defined( $limitre ) )
+ {
+ Warn('Cannot write bundles with --limit option specified. ' .
+ 'Bundle files remain unchanged');
+ }
+ elsif( $everythingsOk )
+ {
+ foreach my $bundleName ( sort keys %outputBundles )
+ {
+ my $cb = new Torrus::ConfigBuilder;
+
+ $cb->addCreatorInfo( $creator );
+
+ foreach my $bundleMember
+ ( sort keys %{$outputBundles{$bundleName}} )
+ {
+ $cb->addFileInclusion( $bundleMember );
+ }
+
+ my $ok = $cb->toFile( $bundleName );
+ if( $ok )
+ {
+ Verbose('Wrote bundle to ' . $bundleName);
+ }
+ else
+ {
+ Error('Cannot write bundle to ' . $bundleName . ': ' . $!);
+ $everythingsOk = 0;
+ }
+ }
+ }
+ else
+ {
+ Error('Skipping bundles generation because of errors');
+ }
+}
+
+
+exit($everythingsOk ? 0:1);
+
+
+sub parseParams
+{
+ my $parentNode = shift;
+ my $paramhash = shift;
+
+ # Clone the parameters hash
+ my $ret = {};
+ if( $paramhash )
+ {
+ while( my($key, $val) = each %{$paramhash} )
+ {
+ $ret->{$key} = $val;
+ }
+ }
+
+ foreach my $paramNode ( $parentNode->getChildrenByTagName('param') )
+ {
+ my $param = $paramNode->getAttribute('name');
+ my $value = $paramNode->getAttribute('value');
+
+ if( not $param )
+ {
+ Error("Parameter without name");
+ exit 1;
+ }
+
+ if( not defined( $value ) )
+ {
+ $value = $paramNode->textContent();
+ }
+
+ # Remove spaces in the head and tail.
+ $value =~ s/^\s+//;
+ $value =~ s/\s+$//;
+
+ $ret->{$param} = $value;
+ }
+ return $ret;
+}
+
+
+sub normalizeParams
+{
+ my $params = shift;
+
+ if( not defined( $params->{'output-file'} ) )
+ {
+ Warn('output-file parameter is not defined. Using routers.xml');
+ $params->{'output-file'} = 'routers.xml';
+ }
+ else
+ {
+ $params->{'output-file'} = absXmlFilename( $params->{'output-file'} );
+ }
+
+ if( defined( $params->{'host-subtree'} ) )
+ {
+ my $subtree = $params->{'host-subtree'};
+
+ if( $subtree !~ /^\/[0-9A-Za-z_\-\.\/]*$/ or
+ $subtree =~ /\.\./ )
+ {
+ Error("Invalid format for subtree name: " . $subtree);
+ exit 1;
+ }
+ }
+
+ if( defined( $params->{'snmp-community'} ) )
+ {
+ # Remove any possible Unicode character treatment
+ $params->{'snmp-community'} =
+ pack( 'A*', $params->{'snmp-community'} );
+ }
+}
+
+
+# Replaces $XMLCONFIG with the XML root directory
+sub absXmlFilename
+{
+ my $filename = shift;
+
+ my $subst = '$XMLCONFIG';
+ my $offset = index( $filename, $subst );
+ if( $offset >= 0 )
+ {
+ my $len = length( $subst );
+ substr( $filename, $offset, $len ) = $Torrus::Global::siteXmlDir;
+ }
+ else
+ {
+ if( $filename !~ /^\// )
+ {
+ $filename = $Torrus::Global::siteXmlDir . '/' . $filename;
+ }
+ }
+ return $filename;
+}
+
+
+# Removes XML root directory from path
+sub relXmlFilename
+{
+ my $filename = shift;
+
+ my $subst = $Torrus::Global::siteXmlDir;
+ my $len = length( $subst );
+
+ if( $filename =~ /^\// )
+ {
+ my $offset = index( $filename, $subst );
+ if( $offset == 0 )
+ {
+ $filename = substr( $filename, $len );
+ # we don't know if xmldir has a trailing slash
+ $filename =~ s/^\///;
+ }
+ }
+ return $filename;
+}
+
+
+sub matchLimitRe
+{
+ my $filename = shift;
+
+ if( defined( $limitre ) )
+ {
+ $filename =~ s/^.*\///;
+
+ if( $filename !~ $limitre )
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+# Pick up next available outfile until the job queue is empty
+
+sub discoveryThread
+{
+ Torrus::Log::setTID( threads->tid() );
+ Debug('Started thread #' . threads->tid());
+ my $outfile;
+ while( defined( $outfile = $jobQueue->dequeue_nb() ))
+ {
+ if( not doDiscover( $outfile ) )
+ {
+ $bundleDeletionQueue->enqueue( $outfile );
+ }
+ }
+ Debug('Finished thread #' . threads->tid());
+}
+
+
+
+sub doDiscover
+{
+ my $outfile = shift;
+
+ Verbose('Preparing to write ' . $outfile);
+
+ my $dd = new Torrus::DevDiscover;
+ my $ok = 1;
+
+ foreach my $hostParams ( @{$perOutfileHostParams->{$outfile}} )
+ {
+ $ok = $dd->discover( $hostParams );
+
+ if( not $ok )
+ {
+ Error($outfile . ' was not written because of errors');
+ $everythingsOk = 0;
+ last;
+ }
+ }
+
+ if( $ok )
+ {
+ # LibXML2 is not thread-safe, so we create the XML files
+ # one at a time
+ if( $workerThreads > 1 )
+ {
+ $confBuildSemaphore->down();
+ }
+
+ my $cb = new Torrus::ConfigBuilder;
+
+ $cb->addCreatorInfo( $creator );
+
+ $dd->buildConfig( $cb );
+ $cb->addRequiredFiles();
+ $cb->addStatistics();
+
+ $ok = $cb->toFile( $outfile );
+ if( $ok )
+ {
+ Verbose('Wrote ' . $outfile);
+ }
+ else
+ {
+ Error('Cannot write ' . $outfile . ': ' . $!);
+ $everythingsOk = 0;
+ }
+
+ if( $workerThreads > 1 )
+ {
+ $confBuildSemaphore->up();
+ }
+ }
+
+ if( $makedirs )
+ {
+ if( $everythingsOk )
+ {
+ # Not sure if these calls are reentrant
+ if( $workerThreads > 1 )
+ {
+ $confBuildSemaphore->down();
+ }
+
+ my ($login,$pass,$uid,$gid) = getpwnam('@torrus_user@')
+ or die "Cannot get user details for @torrus_user@";
+
+ foreach my $dir ( $dd->listDataDirs() )
+ {
+ if( not -d $dir )
+ {
+ Debug('Creating directory: ' . $dir);
+ mkdir( $dir ) or
+ Error('Cannot create directory: ' .
+ $dir . ': ' . $!);
+ chown( $uid, $gid, $dir ) or
+ Error('Cannot change ownership for ' .
+ $dir . ': ' . $!);
+ chmod( 02755, $dir ) or
+ Error('Cannot chmod 02755 for ' .
+ $dir . ': ' . $!);
+ }
+ }
+
+ if( $workerThreads > 1 )
+ {
+ $confBuildSemaphore->up();
+ }
+ }
+ else
+ {
+ Error('Skipping mkdir because of errors');
+ }
+ }
+
+ return $ok;
+}
+
+
+sub removeFromBundle
+{
+ my $outfile = shift;
+
+ my $relname = relXmlFilename($outfile);
+
+ my $removeFromBundle = 1;
+
+ if( $forcebundle )
+ {
+ if( defined( $fallback ) and
+ -e $outfile and -M $outfile <= $fallback )
+ {
+ Warn('Falling back to the old version of ' . $relname);
+ $removeFromBundle = 0;
+ }
+ $everythingsOk = 1;
+ }
+
+ if( $removeFromBundle )
+ {
+ foreach my $bundleName ( sort keys %outputBundles )
+ {
+ if( exists( $outputBundles{$bundleName}{$relname} ) )
+ {
+ delete $outputBundles{$bundleName}{$relname};
+ Warn('Bundle ' . $bundleName . ' will not have ' .
+ $relname . ' included because of errors');
+ }
+ }
+ }
+}
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/flushmonitors.in b/torrus/bin/flushmonitors.in
new file mode 100644
index 000000000..6c01269ac
--- /dev/null
+++ b/torrus/bin/flushmonitors.in
@@ -0,0 +1,143 @@
+#!@PERL@ -w
+# Copyright (C) 2010 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: flushmonitors.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use Getopt::Long;
+use strict;
+
+use Torrus::SiteConfig;
+use Torrus::ConfigTree;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+our @trees;
+our $all_trees;
+
+our $debug;
+our $verbose;
+our $help_needed;
+
+my $ok = GetOptions ('tree=s' => \@trees,
+ 'all' => \$all_trees,
+ 'debug' => \$debug,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not (scalar(@trees) or $all_trees) or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "The utility flushes all monitor alarms and dynamic tokenset members\n",
+ "Options:\n",
+ " --tree=NAME tree name(s) to flush\n",
+ " --all flush all trees\n",
+ " --debug set the log level to debug\n",
+ " --verbose set the log level to info\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( $all_trees )
+{
+ @trees = Torrus::SiteConfig::listTreeNames();
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+
+&Torrus::DB::setSafeSignalHandlers();
+
+Verbose(sprintf('Torrus version %s', '@VERSION@'));
+
+foreach my $tree ( @trees )
+{
+ if( not Torrus::SiteConfig::treeExists( $tree ) )
+ {
+ Error("Tree named \"" . $tree . "\" does not exist");
+ exit(1);
+ }
+
+ &Torrus::DB::checkInterrupted();
+
+ Verbose("Flushing alarms and tokensets for the tree: $tree");
+
+ my $config_tree = new Torrus::ConfigTree( -TreeName => $tree,
+ -Wait => 1 );
+ if( not defined( $config_tree ) )
+ {
+ next;
+ }
+
+ my $db = new Torrus::DB('monitor_alarms',
+ -Subdir => $tree,
+ -WriteAccess => 1);
+
+
+ my $cursor = $db->cursor(-Write => 1);
+ while( my ($key, $timers) = $db->next($cursor) )
+ {
+ Debug('Deleting alarm: ' . $key);
+ $db->c_del( $cursor );
+
+ }
+ undef $cursor;
+ undef $db;
+
+ &Torrus::DB::checkInterrupted();
+
+ my @members;
+ foreach my $ts ( $config_tree->getTsets() )
+ {
+ Debug('Processing tokenset: ' . $ts);
+
+ foreach my $member ( $config_tree->tsetMembers( $ts ) )
+ {
+ my $origin = $config_tree->tsetMembers( $ts, $member );
+
+ if( not defined( $origin ) or $origin ne 'static' )
+ {
+ my $path = $config_tree->path($member);
+ $config_tree->tsetDelMember($ts, $member);
+ Verbose('deleted ' . $path . ' from tokenset: ' . $ts);
+ }
+ }
+ }
+
+ undef $config_tree;
+ &Torrus::DB::cleanupEnvironment();
+}
+
+exit;
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/genddx.in b/torrus/bin/genddx.in
new file mode 100644
index 000000000..6e3464e66
--- /dev/null
+++ b/torrus/bin/genddx.in
@@ -0,0 +1,255 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: genddx.in,v 1.1 2010-12-27 00:04:00 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Generate the SNMP discovery instructions XML file out of plaintext
+# list of hosts.
+
+BEGIN { require '@devdiscover_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+use XML::LibXML;
+
+use Torrus::Log;
+
+our $outFormatVersion = '1.0';
+
+our @hosts = ();
+our $hostfile;
+
+our %globalParams =
+ (
+ 'output-file' => 'routers.xml',
+ 'domain-name' => '',
+ 'host-subtree' => '/Routers',
+ 'snmp-port' => '161',
+ 'snmp-community' => 'public',
+ 'snmp-version' => '2c',
+ 'snmp-timeout' => 10,
+ 'snmp-retries' => 2,
+ 'rrd-hwpredict' => 0,
+ 'data-dir' => '@defrrddir@',
+ );
+
+our $outfile = 'routers.ddx';
+
+
+my $creator = "Torrus version @VERSION@\n" .
+ "This file was generated by command:\n" .
+ $0 . " \\\n";
+foreach my $arg ( @ARGV )
+{
+ if( $arg =~ /^--/ )
+ {
+ $creator .= ' ' . $arg . ' ';
+ }
+ else
+ {
+ $creator .= "\'" . $arg . "\'\\\n";
+ }
+}
+$creator .= "\nOn " . scalar(localtime(time));
+
+my $ok = GetOptions(
+ 'host=s' => \@hosts,
+ 'hostfile=s' => \$hostfile,
+ 'out=s' => \$outfile,
+ 'discout=s' => \$globalParams{'output-file'},
+ 'domain=s' => \$globalParams{'domain-name'},
+ 'version=s' => \$globalParams{'snmp-version'},
+ 'community=s' => \$globalParams{'snmp-community'},
+ 'port=i' => \$globalParams{'snmp-port'},
+ 'timeout=i' => \$globalParams{'snmp-timeout'},
+ 'retries=i' => \$globalParams{'snmp-retries'},
+ 'subtree=s' => \$globalParams{'host-subtree'},
+ 'holtwinters' => \$globalParams{'rrd-hwpredict'},
+ 'datadir=s' => \$globalParams{'data-dir'},
+ );
+
+if( not $ok or
+ ( not $hostfile and scalar(@hosts) == 0 ) or
+ scalar( @ARGV ) > 0 )
+{
+ print STDERR "Generate devdiscover XML configuration\n";
+
+ print STDERR "Usage: $0 options...\n",
+ "Options:\n",
+ " --host=hostname router hostname\n",
+ " --hostfile=filename space-separated router hostnames file\n",
+ " --out=filename output file [".$outfile."]\n",
+
+ " --discout=filename discovery output file\n",
+ " [", $globalParams{'output-file'}, "]\n",
+
+ " --domain=domain optional DNS domain name\n",
+
+ " --version=v SNMP version [",
+ $globalParams{'snmp-version'}, "]\n",
+
+ " --community=string SNMP read community [",
+ $globalParams{'snmp-community'}, "]\n",
+
+ " --port=number SNMP port [",
+ $globalParams{'snmp-port'}, "]\n",
+
+ " --retries=number SNMP retries [",
+ $globalParams{'snmp-retries'}, "]\n",
+
+ " --timeout=number SNMP timeout [",
+ $globalParams{'snmp-timeout'}, "]\n",
+
+ " --subtree=string Subtree name [",
+ $globalParams{'host-subtree'}, "]\n",
+
+ " --datadir=path data-dir parameter [",
+ $globalParams{'data-dir'}, "]\n",
+
+ " --holtwinters Enable Holt-Winters analysis\n",
+ "\n",
+ "Host names may be of form \"host:devname\" where devname is a symbolic\n",
+ "device name.\n",
+ "Output file is placed into " . $Torrus::Global::discoveryDir,
+ "\n if no path is given.\n";
+ exit 1;
+}
+
+# Place the output file in discovery directory if the path is not given
+if( $outfile !~ /\// )
+{
+ $outfile = $Torrus::Global::discoveryDir . '/' . $outfile;
+}
+
+# Convert flags from true/false to yes/no
+foreach my $param ( 'rrd-hwpredict' )
+{
+ if( $globalParams{$param} )
+ {
+ $globalParams{$param} = 'yes';
+ }
+ else
+ {
+ $globalParams{$param} = 'no';
+ }
+}
+
+if( $globalParams{'host-subtree'} !~ /^\/[0-9A-Za-z_\-\.\/]*$/ or
+ $globalParams{'host-subtree'} =~ /\.\./ )
+{
+ Error("Invalid format for subtree name: " . $globalParams{'host-subtree'});
+ exit 1;
+}
+
+if( defined $hostfile )
+{
+ if( not open(HOSTS, $hostfile) )
+ {
+ print STDERR "Cannot open $hostfile: $!";
+ exit 1;
+ }
+ while(<HOSTS>)
+ {
+ s/^\s+//;
+ s/\s+$//;
+ push( @hosts, split( /\s+/ ) );
+ }
+}
+
+# Create XML DOM
+
+my $doc = XML::LibXML->createDocument( "1.0", "UTF-8" );
+my $root = $doc->createElement('snmp-discovery');
+$doc->setDocumentElement( $root );
+
+{
+ my $fileInfoNode = $doc->createElement('file-info');
+ $root->appendChild( $fileInfoNode );
+
+ my $formatNode = $doc->createElement('format-version');
+ $formatNode->appendText( $outFormatVersion );
+ $fileInfoNode->appendChild( $formatNode );
+}
+
+{
+ my $creatorNode = $doc->createElement('creator-info');
+ $creatorNode->appendText( $creator );
+ $root->appendChild( $creatorNode );
+}
+
+createParamsDom( \%globalParams, $doc, $root );
+
+
+foreach my $host ( @hosts )
+{
+ my $devname = $host;
+ if( $host =~ /([^:]+):(.+)/ )
+ {
+ $host = $1;
+ $devname = $2;
+ }
+
+ my $hostNode = $doc->createElement('host');
+ $root->appendChild( $hostNode );
+
+ my %hostParams = ( 'snmp-host' => $host );
+ if( $devname ne $host )
+ {
+ $hostParams{'symbolic-name'} = $devname;
+ }
+
+ createParamsDom( \%hostParams, $doc, $hostNode );
+}
+
+my $ok = $doc->toFile( $outfile, 2 );
+if( $ok )
+{
+ print STDERR ("Wrote $outfile\n");
+}
+else
+{
+ print STDERR ("Cannot write $outfile: $!\n");
+}
+
+
+exit($ok ? 0:1);
+
+
+sub createParamsDom
+{
+ my $params = shift;
+ my $doc = shift;
+ my $parentNode = shift;
+
+ foreach my $param ( sort keys %{$params} )
+ {
+ my $paramNode = $doc->createElement('param');
+ $paramNode->setAttribute( 'name', $param );
+ $paramNode->setAttribute( 'value', $params->{$param} );
+ $parentNode->appendChild( $paramNode );
+ }
+}
+
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/genlist.in b/torrus/bin/genlist.in
new file mode 100644
index 000000000..2b79fc126
--- /dev/null
+++ b/torrus/bin/genlist.in
@@ -0,0 +1,197 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: genlist.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::ConfigTree;
+use Torrus::SiteConfig;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+my $tree;
+my $initPath = '/';
+my $listWhat = 'rrdfiles';
+my $selectType = 'all';
+
+my $help_needed;
+
+my %listingsSupported =
+ (
+ 'rrdfiles' => {
+ 'collector' => 1,
+ 'readonly' => 1,
+ 'all' => 1,
+ },
+
+ 'snmphosts' => {
+ 'collector' => 1,
+ },
+ );
+
+my $ok = GetOptions ('tree=s' => \$tree,
+ 'path=s' => \$initPath,
+ 'what=s' => \$listWhat,
+ 'type=s' => \$selectType,
+ 'help' => \$help_needed);
+
+if( not $ok or not $tree or $help_needed or
+ not $listingsSupported{$listWhat}{$selectType} or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --path=/PATH [".$initPath."] subtree name\n",
+ " --what=WHAT [".$listWhat."] what to list\n",
+ " Supported listings:\n",
+ " rrdfiles List RRD file paths\n",
+ " snmphosts List SNMP hosts\n",
+ " --type=TYPE [".$selectType."] selection type\n",
+ " Supported types:\n",
+ " collector Collector leaves\n",
+ " readonly Read-only leaves\n",
+ " all All of above\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+
+if( not Torrus::SiteConfig::treeExists( $tree ) )
+{
+ Error('Tree ' . $tree . ' does not exist');
+ exit 1;
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+my $config_tree = new Torrus::ConfigTree( -TreeName => $tree, -Wait => 1 );
+if( not defined( $config_tree ) )
+{
+ exit 1;
+}
+
+my $initToken = $config_tree->token( $initPath );
+if( not defined( $initToken ) )
+{
+ Error('No such subtree: ' . $initPath);
+ exit 1;
+}
+
+my $listing = {};
+
+my $listParams = {};
+if( $selectType eq 'all' )
+{
+ foreach my $type ( keys %{$listingsSupported{$listWhat}} )
+ {
+ if( $type ne 'all' )
+ {
+ $listParams->{$type} = 1;
+ }
+ }
+}
+else
+{
+ $listParams->{$selectType} = 1;
+}
+
+pickup_data( $config_tree, $initToken, $listing, $listWhat, $listParams );
+
+foreach my $item ( sort keys %{$listing} )
+{
+ print $item, "\n";
+}
+
+exit 0;
+
+sub pickup_data
+{
+ my $config_tree = shift;
+ my $token = shift;
+ my $listing = shift;
+ my $listWhat = shift;
+ my $listParams = shift;
+
+ foreach my $ctoken ( $config_tree->getChildren( $token ) )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ if( $config_tree->isSubtree( $ctoken ) )
+ {
+ pickup_data( $config_tree, $ctoken,
+ $listing, $listWhat, $listParams );
+ }
+ elsif( $config_tree->isLeaf( $ctoken ) )
+ {
+ if( $listWhat eq 'rrdfiles' and
+ (
+ (
+ $listParams->{'collector'} and
+ $config_tree->getNodeParam( $ctoken, 'ds-type' ) eq
+ 'collector' and
+ $config_tree->getNodeParam( $ctoken, 'storage-type' ) eq
+ 'rrd'
+ ) or
+ (
+ $listParams->{'readonly'} and
+ $config_tree->getNodeParam( $ctoken, 'ds-type' ) eq
+ 'rrd-file' and
+ $config_tree->getNodeParam( $ctoken, 'leaf-type' ) eq
+ 'rrd-def'
+ )
+ )
+ )
+ {
+ my $datafile =
+ $config_tree->getNodeParam( $ctoken, 'data-file' );
+ my $datadir =
+ $config_tree->getNodeParam( $ctoken, 'data-dir' );
+ $listing->{$datadir . '/' . $datafile} = 1;
+ }
+ elsif( $listWhat eq 'snmphosts' and
+ $listParams->{'collector'} and
+ $config_tree->getNodeParam( $ctoken, 'ds-type' ) eq
+ 'collector' )
+ {
+ my $host =
+ $config_tree->getNodeParam( $ctoken, 'snmp-host' );
+ my $oid =
+ $config_tree->getNodeParam( $ctoken, 'snmp-object' );
+
+ if( defined( $host ) and length( $host ) > 0 and
+ defined( $oid ) and length( $oid ) > 0 )
+ {
+ $listing->{$host} = 1;
+ }
+ }
+ }
+ }
+}
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/genreport.in b/torrus/bin/genreport.in
new file mode 100644
index 000000000..6d21b4878
--- /dev/null
+++ b/torrus/bin/genreport.in
@@ -0,0 +1,181 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: genreport.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Collect the router information and create the XML file
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::ReportOutput::HTML;
+use Torrus::SiteConfig;
+
+my $report;
+my $date;
+my $time = '00:00';
+my $genhtml;
+my @trees;
+my $all2tree;
+
+my $debug = 0;
+my $verbose = 0;
+
+my $ok = GetOptions(
+ 'report=s' => \$report,
+ 'date=s' => \$date,
+ 'time=s' => \$time,
+ 'genhtml' => \$genhtml,
+ 'tree=s' => \@trees,
+ 'all2tree=s' => \$all2tree,
+ 'verbose' => \$verbose,
+ 'debug' => \$debug
+ );
+
+if( $report and not defined($Torrus::ReportGenerator::modules{$report}) )
+{
+ print STDERR "Unknown report name: ", $report, "\n\n";
+ $ok = 0;
+}
+
+if( not $ok or (not $report and not $genhtml) or
+ ($report and not $date) or
+ ($genhtml and scalar(@trees) > 0 and $all2tree) or
+ scalar( @ARGV ) > 0 )
+{
+ print STDERR
+ "Usage: $0 --report=ReportName --date=YYYY-MM-DD | ",
+ "--genhtml options...\n";
+ print STDERR "Options:\n",
+ " --report=ReportName Report name.\n",
+ " --date=YYYY-MM-DD Report start date. ",
+ "For monthly reports, 1st day in a month.\n",
+ " --time=hh:mm Report start time. Ignored for monthly reports\n",
+ " --genhtml Generate HTML output from the database\n",
+ " --tree=TREE Generate HTML for a given tree only\n",
+ " --all2tree=TREE Generate reports for all service IDs and place\n",
+ " into the given tree (excludes the option --tree)\n",
+ " --verbose print extra information\n",
+ " --debug print debugging information\n",
+ "\n",
+ "Report names supported:\n";
+
+ foreach my $rep ( sort keys %Torrus::ReportGenerator::modules )
+ {
+ print STDERR " ", $rep, "\n";
+ }
+ print STDERR "\n";
+
+ exit 1;
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+if( $report )
+{
+ my $class = $Torrus::ReportGenerator::modules{$report};
+ eval( 'require ' . $class );
+ die( $@ ) if $@;
+
+ my $generator = $class->new({
+ 'Name' => $report,
+ 'Date' => $date,
+ 'Time' => $time});
+
+ if( defined( $generator ) )
+ {
+ $generator->generate();
+ }
+ else
+ {
+ $ok = 0;
+ }
+}
+
+if( $genhtml )
+{
+ if( $all2tree )
+ {
+ push( @trees, $all2tree );
+ }
+
+ if( scalar( @trees ) == 0 )
+ {
+ @trees = Torrus::SiteConfig::listTreeNames();
+ }
+ else
+ {
+ foreach my $tree ( @trees )
+ {
+ if( not Torrus::SiteConfig::treeExists( $tree ) )
+ {
+ Error('Tree ' . $tree . ' does not exist');
+ $ok = 0;
+ }
+ }
+ }
+
+ if( $ok )
+ {
+ foreach my $tree ( @trees )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ Verbose('Generating HTML report for tree ' . $tree);
+
+ my $options = {'Tree' => $tree};
+
+ if( length( $all2tree ) > 0 )
+ {
+ $options->{'All_Service_IDs'} = 1;
+ }
+
+ my $out = new Torrus::ReportOutput::HTML( $options );
+
+ if( $out->init() )
+ {
+ $ok = $out->generate() ? $ok:0;
+ }
+ else
+ {
+ $ok = 0;
+ }
+ }
+ }
+}
+
+exit($ok ? 0:1);
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/install_plugin.in b/torrus/bin/install_plugin.in
new file mode 100644
index 000000000..31b44e730
--- /dev/null
+++ b/torrus/bin/install_plugin.in
@@ -0,0 +1,51 @@
+#!@SHELL@
+# Copyright (C) 2004 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: install_plugin.in,v 1.1 2010-12-27 00:04:00 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+#
+
+# Torrus plugin installation utility
+
+plugin=$1
+shift
+
+if test -z "$plugin"; then
+ echo "Usage: $0 plugin_dir [options...]" 1>&2
+ exit 1
+fi
+
+if test ! -d $plugin; then
+ echo "No such directory: $plugin" 1>&2
+ exit 1
+fi
+
+echo Installing Torrus plugin from $plugin
+
+cd $plugin
+eval './configure '`cat @cfgdefdir@/instvars`' '$@ || exit 1
+make || exit 1
+make install || exit 1
+
+echo Plugin installation finished
+
+
+# Local Variables:
+# mode: shell-script
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/monitor.in b/torrus/bin/monitor.in
new file mode 100644
index 000000000..c8579997b
--- /dev/null
+++ b/torrus/bin/monitor.in
@@ -0,0 +1,176 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: monitor.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Proc::Daemon;
+use Getopt::Long;
+
+use Torrus::Log;
+use Torrus::Monitor;
+use Torrus::SiteConfig;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+our $tree;
+our $nodaemon;
+our $runonce;
+our $delay = 0;
+our $debug;
+our $verbose;
+our $help_needed;
+
+# Derive the process name from the command line
+our $process_name = $0;
+$process_name =~ s/^.*\/([^\/]+)$/$1/;
+$process_name .= ' ' . join(' ', @ARGV);
+
+
+my $ok = GetOptions ('tree=s' => \$tree,
+ 'nodaemon' => \$nodaemon,
+ 'runonce' => \$runonce,
+ 'delay=i' => \$delay,
+ 'debug' => \$debug,
+ 'verbose' => \$verbose,
+ 'help' => \$help_needed);
+
+if( not $ok or not $tree or $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --nodaemon do not fork daemon and log to STDERR\n",
+ " --runonce run one time and exit. Implies --nodaemon\n",
+ " --delay delay the start of the first cycle, minutes\n",
+ " --debug set the log level to debug\n",
+ " --verbose set the log level to info\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+if( not Torrus::SiteConfig::mayRunMonitor( $tree ) )
+{
+ Error('Tree ' . $tree . ' is not configured to run monitor');
+ exit 1;
+}
+
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+my $logfile = $Torrus::Global::logDir . '/monitor.' . $tree . '.log';
+my $pidfile;
+
+my $rotateLogs = sub
+{
+ Info('Caught SIGHUP. Reopening log file');
+ close( STDERR );
+ open( STDERR, ">>$logfile" );
+};
+
+if( not $nodaemon and not $runonce )
+{
+ my $pidfilename =
+ $Torrus::Global::pidDir . '/monitor.' . $tree . '.pid';
+
+ if( -r $pidfilename )
+ {
+ Error("Another monitor daemon is running, pid=",
+ `cat $pidfilename`);
+ exit 1;
+ }
+
+ &Proc::Daemon::Init();
+ umask 0017; # Proc::Daemon::Init sets the mask to all-writable
+
+ $SIG{'HUP'} = $rotateLogs;
+
+ # At this point, we cannot tell anyone if "open" fails
+ open(STDERR, ">>$logfile");
+
+ $pidfile = $pidfilename;
+
+ if( open( PID, ">$pidfile" ) )
+ {
+ printf PID ( "%d", $$ );
+ close PID;
+ }
+ else
+ {
+ Error("Cannot open $pidfile for writing: $!");
+ }
+}
+
+Info(sprintf("Torrus version %s", '@VERSION@'));
+Info(sprintf("%s started for tree %s", $0, $tree));
+Debug(sprintf("Process ID %d", $$));
+
+if( $delay > 0 )
+{
+ Info(sprintf('Delaying for %d minutes', $delay));
+ sleep($delay * 60);
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+my %options =
+ (
+ '-ProcessName' => $process_name,
+ '-Tree' => $tree,
+ '-Delay' => $delay
+ );
+if( $runonce )
+{
+ $options{'-RunOnce'} = 1;
+}
+
+my $scheduler = new Torrus::MonitorScheduler( %options );
+$scheduler->run();
+
+if( not $options{'-RunOnce'} )
+{
+ Error("Monitor process exited: nothing to collect");
+ unlink $pidfile;
+}
+
+exit;
+
+
+END
+{
+ if( defined($pidfile) and -r $pidfile )
+ {
+ unlink $pidfile;
+ }
+}
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/nodeid.in b/torrus/bin/nodeid.in
new file mode 100644
index 000000000..b362a955b
--- /dev/null
+++ b/torrus/bin/nodeid.in
@@ -0,0 +1,252 @@
+#!@PERL@ -w
+# Copyright (C) 2010 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: nodeid.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+use JSON;
+use File::Copy;
+
+use Torrus::ConfigTree;
+use Torrus::SiteConfig;
+use Torrus::Renderer;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+
+my %commands =
+ ('info' => \&do_info,
+ 'search' => \&do_search,
+ 'render' => \&do_render);
+
+
+
+my $tree;
+my $cmd;
+
+my $nodeid;
+my $print_details;
+my $search_prefix;
+my $search_substring;
+my $render_view;
+my $render_out;
+
+
+my $help_needed;
+
+
+my $ok = GetOptions('tree=s' => \$tree,
+ 'cmd=s' => \$cmd,
+ 'nodeid=s' => \$nodeid,
+ 'details' => \$print_details,
+ 'prefix=s' => \$search_prefix,
+ 'substring=s' => \$search_substring,
+ 'view=s' => \$render_view,
+ 'out=s' => \$render_out,
+ 'help' => \$help_needed);
+
+if( not $ok or
+ not $tree or not $cmd or not $commands{$cmd} or
+ ( ($cmd eq 'info' or $cmd eq 'render') and not $nodeid ) or
+ ( $cmd eq 'search' and not ($search_prefix or $search_substring) ) or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME --cmd=CMD [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --cmd=CMD Command (info|search|render)\n",
+ " --nodeid=NODEID nodeid (mandatory for info and render)\n",
+ " --details print nodeid details (valid with info and search)\n",
+ " --prefix=STR search prefix\n",
+ " --substring=STR search substring\n",
+ " --view=VIEW render view (optional)\n",
+ " --out=FILE render output\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+
+if( not Torrus::SiteConfig::treeExists( $tree ) )
+{
+ Error('Tree ' . $tree . ' does not exist');
+ exit 1;
+}
+
+
+&Torrus::DB::setSafeSignalHandlers();
+
+{
+ my $config_tree = new Torrus::ConfigTree( -TreeName => $tree );
+ if( not defined($config_tree) )
+ {
+ Error("Configuration is not ready");
+ exit 1;
+ }
+
+ if( $cmd eq 'info' or $cmd eq 'render' )
+ {
+ my $token = $config_tree->getNodeByNodeid($nodeid);
+ if( not defined( $token ) )
+ {
+ Error('nodeid not found: ' . $nodeid);
+ exit(1);
+ }
+
+ if( $cmd eq 'info' )
+ {
+ print_nodeid($config_tree, [$token], $print_details);
+ }
+ else
+ {
+ render_node($config_tree, $token, $render_view, $render_out);
+ }
+ }
+ elsif( $cmd eq 'search' )
+ {
+ my $results;
+ if( defined($search_prefix) )
+ {
+ $results = $config_tree->searchNodeidPrefix($search_prefix);
+ }
+ else
+ {
+ $results = $config_tree->searchNodeidSubstring($search_substring);
+ }
+
+ if( defined( $results ) and scalar(@{$results}) > 0 )
+ {
+ my $tokens = [];
+ # results are pairs [nodeid,token]
+ foreach my $res ( @{$results} )
+ {
+ push(@{$tokens}, $res->[1]);
+ }
+ print_nodeid($config_tree, $tokens, $print_details);
+ }
+ else
+ {
+ print STDERR "Nothing found\n";
+ exit(1);
+ }
+ }
+ else
+ {
+ printf STDERR ("Unknown command: %s\n", $cmd);
+ exit(1);
+ }
+}
+
+exit(0);
+
+
+sub print_nodeid
+{
+ my $config_tree = shift;
+ my $tokens = shift;
+ my $details = shift;
+
+ my $json = new JSON;
+ $json->pretty();
+ $json->canonical();
+
+ my @all;
+
+ foreach my $token ( @{$tokens} )
+ {
+ my $info = {
+ 'nodeid' => $config_tree->getNodeParam($token, 'nodeid', 1),
+ };
+
+ if( $details )
+ {
+ $info->{'path'} = $config_tree->path($token);
+ $info->{'is_leaf'} = $config_tree->isLeaf($token) ? 1:0;
+ $info->{'tree'} = $config_tree->treeName();
+ if( $info->{'is_leaf'} )
+ {
+ my $dsType = $config_tree->getNodeParam( $token, 'ds-type' );
+ $info->{'param:ds-type'} = $dsType;
+ if( $dsType eq 'collector' )
+ {
+ foreach my $param
+ ('collector-type', 'collector-period',
+ 'storage-type', 'data-file', 'data-dir', 'rrd-ds',
+ 'ext-service-id',
+ 'snmp-host', 'domain-name', 'snmp-object')
+ {
+ my $val = $config_tree->getNodeParam($token, $param);
+
+ if( defined( $val ) )
+ {
+ $info->{'param:' . $param} = $val;
+ }
+ }
+ }
+ }
+ }
+
+ push(@all, $info);
+ }
+
+ print $json->encode(\@all);
+}
+
+
+
+sub render_node
+{
+ my $config_tree = shift;
+ my $token = shift;
+ my $view = shift;
+ my $out = shift;
+
+ my $r = new Torrus::Renderer;
+
+ my($fname, $mimetype) = $r->render($config_tree, $token, $view);
+
+ if( defined($out) )
+ {
+ if( not copy( $fname, $out ) )
+ {
+ printf STDERR ("Failed to write to %s: %s\n", $out, $!);
+ exit(1);
+ }
+
+ $fname = $out;
+ }
+
+ my $json = new JSON;
+ $json->pretty();
+
+ print $json->encode({'Content-type' => $mimetype,
+ 'Filename' => $fname});
+}
+
+
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/rrddir2xml.in b/torrus/bin/rrddir2xml.in
new file mode 100644
index 000000000..c82fcf871
--- /dev/null
+++ b/torrus/bin/rrddir2xml.in
@@ -0,0 +1,311 @@
+#!@PERL@
+# Copyright (C) 2002 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: rrddir2xml.in,v 1.1 2010-12-27 00:04:01 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Generate Torrus XML configuration from a directory containing RRD files
+#
+
+BEGIN { require '@devdiscover_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+use IO::Dir;
+use Fcntl qw(:mode);
+use RRDs;
+
+use Torrus::ConfigBuilder;
+use Torrus::Log;
+
+
+my $creator = "Torrus version @VERSION@\n" .
+ "This file was generated by command:\n" .
+ $0 . " \\\n";
+foreach my $arg ( @ARGV )
+{
+ if( $arg =~ /^--/ )
+ {
+ $creator .= ' ' . $arg . ' ';
+ }
+ else
+ {
+ $creator .= "\'" . $arg . "\'\\\n";
+ }
+}
+$creator .= "\nOn " . scalar(localtime(time));
+
+
+my $indir;
+my $recursive = 0;
+my $filter = '.*';
+my $outfile = 'rrddir.xml';
+my $topsubtree = '/';
+my $splitexpr = '_+';
+my $levels = 2;
+my $hwpredict = 0;
+my $comment;
+my $debug = 0;
+my $verbose = 0;
+
+
+my $ok = GetOptions(
+ 'dir=s' => \$indir,
+ 'recursive' => \$recursive,
+ 'filter=s' => \$filter,
+ 'out=s' => \$outfile,
+ 'subtree=s' => \$topsubtree,
+ 'split=s' => \$splitexpr,
+ 'levels=i' => \$levels,
+ 'comment=s' => \$comment,
+ 'holtwinters' => \$hwpredict,
+ 'verbose' => \$verbose,
+ 'debug' => \$debug
+ );
+
+if( not $ok or not $indir or scalar( @ARGV ) > 0 )
+{
+ print STDERR
+ "Generate Torrus XML configuration from a directory with RRD files\n";
+
+ print STDERR "Usage: $0 --dir=path options...\n",
+ "Options:\n",
+ " --dir=path directory to read RRD files from\n",
+ " --recursive read the directories recursively\n",
+ " --filter=re filter RE for file and directory names\n",
+ " --out=filename output file [".$outfile."]\n",
+ " --subtree=subtree XML config subtree [".$topsubtree."]\n",
+ " --split=regexp regexp to split file names [".$splitexpr."]\n",
+ " --levels=integer no. of subtree levels [".$levels."]\n",
+ " --comment=text top subtree comment\n",
+ " --holtwinters enable Holt-Winters boundaries diaplay\n",
+ " --verbose print extra information\n",
+ " --debug print debugging information\n";
+
+ exit 1;
+}
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+if( not -d $indir )
+{
+ Error('No such directory: ' . $indir);
+ exit 1;
+}
+
+if( $indir !~ /^\// )
+{
+ Error('Input directory must be an absolute path: ' . $indir);
+ exit 1;
+}
+
+# remove trailing slash from $indir
+$indir =~ s/\/$//;
+
+if( $topsubtree !~ /^\/[0-9A-Za-z_\-\.\/]*$/ or
+ $topsubtree =~ /\.\./ )
+{
+ Error("Invalid format for subtree name: " . $topsubtree);
+ exit 1;
+}
+
+
+if( $outfile !~ /^\// )
+{
+ $outfile = $Torrus::Global::siteXmlDir . '/' . $outfile;
+}
+
+my %rrdinfos;
+read_rrd_dir( \%rrdinfos, $indir, $filter, $recursive );
+
+Verbose(sprintf('Found %d RRD files', scalar( keys( %rrdinfos ) ) ));
+
+my $cb = new Torrus::ConfigBuilder;
+$cb->addCreatorInfo( $creator );
+
+# Chop the first and last slashes
+my $path = $topsubtree;
+$path =~ s/^\///;
+$path =~ s/\/$//;
+
+# generate subtree path XML
+my $topSubtreeNode = undef;
+foreach my $subtreeName ( split( '/', $path ) )
+{
+ $topSubtreeNode = $cb->addSubtree( $topSubtreeNode, $subtreeName );
+}
+
+if( length( $comment ) > 0 )
+{
+ $cb->addParam( $topSubtreeNode, 'comment', $comment );
+}
+
+foreach my $rrdfile ( sort keys %rrdinfos )
+{
+ my @nameparts = split( $splitexpr, $rrdfile, $levels );
+
+ my $subtreeNode = $topSubtreeNode;
+ foreach my $subtreeName ( @nameparts )
+ {
+ $subtreeNode = $cb->addSubtree( $subtreeNode, $subtreeName );
+ }
+
+ my $info = $rrdinfos{$rrdfile};
+
+ my $legend =
+ 'Directory:' . $info->{'dir'} . ';' .
+ 'File:' . $rrdfile . ';';
+
+ $cb->addParam( $subtreeNode, 'legend', $legend );
+
+ my %dsnames;
+ my $this_rrd_hwpredict = 0;
+
+ foreach my $prop ( keys %{$info->{'rrdinfo'}} )
+ {
+ if( $prop =~ /^ds\[(\S+)\]\./o )
+ {
+ $dsnames{$1} = 1;
+ }
+ else
+ {
+ if( $prop =~ /^rra\[\d+\]\.cf/o and
+ $info->{'rrdinfo'}->{$prop} eq 'FAILURES' )
+ {
+ $this_rrd_hwpredict = 1;
+ }
+ }
+ }
+
+ if( not $hwpredict )
+ {
+ $this_rrd_hwpredict = 0;
+ }
+
+ foreach my $dsname ( sort keys %dsnames )
+ {
+ my $dslegend = $legend . 'DS:' . $dsname . ';Type:' .
+ $info->{'rrdinfo'}->{'ds['.$dsname.'].type'};
+
+ my $params = {
+ 'legend' => $dslegend,
+ 'ds-type' => 'rrd-file',
+ 'leaf-type' => 'rrd-def',
+ 'rrd-cf' => 'AVERAGE',
+ 'data-file' => $rrdfile,
+ 'data-dir' => $info->{'dir'},
+ 'rrd-ds' => $dsname,
+ 'rrd-hwpredict' => ($this_rrd_hwpredict ? 'enabled':'disabled')
+ };
+
+ $cb->addLeaf( $subtreeNode, $dsname, $params );
+ }
+}
+
+my $ok = $cb->toFile( $outfile );
+if( $ok )
+{
+ Verbose('Wrote ' . $outfile);
+}
+else
+{
+ Error('Cannot write ' . $outfile . ': ' . $!);
+}
+
+exit( $ok ? 0:1);
+
+
+
+sub read_rrd_dir
+{
+ my $infos = shift;
+ my $indir = shift;
+ my $filter = shift;
+ my $recursive = shift;
+
+ Debug('Reading directory: ' . $indir);
+
+ my @subdirs;
+
+ my %dir;
+ tie( %dir, 'IO::Dir', $indir );
+
+ foreach my $file ( keys %dir )
+ {
+ if( $file =~ /^\./ or $file !~ $filter )
+ {
+ Debug('Skipping ' . $file);
+ next;
+ }
+
+ my $mode = $dir{$file}->mode();
+ if( S_ISDIR( $mode ) )
+ {
+ Debug($file . ' is a directory');
+ push( @subdirs, $file );
+ }
+ elsif( S_ISREG( $mode ) )
+ {
+ Debug($file . ' is a regular file');
+ if( defined( $infos->{$file} ) )
+ {
+ Warn("Duplicate file name: $file");
+ }
+ else
+ {
+ my $fullname = $indir . '/' . $file;
+ my $rrdinfo = RRDs::info( $fullname );
+ my $err = RRDs::error();
+ if( $err )
+ {
+ Verbose($fullname . ' is not an RRD file');
+ }
+ else
+ {
+ Debug('Found RRD file: ' . $file);
+ $infos->{$file}->{'fullname'} = $fullname;
+ $infos->{$file}->{'dir'} = $indir;
+ $infos->{$file}->{'rrdinfo'} = $rrdinfo;
+ }
+ }
+ }
+ }
+
+ untie %dir;
+
+ if( $recursive and scalar( @subdirs ) > 0 )
+ {
+ foreach my $subdir ( @subdirs )
+ {
+ read_rrd_dir( $infos, $indir . '/' . $subdir,
+ $filter, $recursive );
+ }
+ }
+}
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/schedulerinfo.in b/torrus/bin/schedulerinfo.in
new file mode 100644
index 000000000..42515b014
--- /dev/null
+++ b/torrus/bin/schedulerinfo.in
@@ -0,0 +1,454 @@
+#!@PERL@ -w
+# Copyright (C) 2003 Stanislav Sinyagin
+# Copyright (C) 2003 Christian Schnidrig
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: schedulerinfo.in,v 1.1 2010-12-27 00:04:00 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+
+use Torrus::ConfigTree;
+use Torrus::SiteConfig;
+use Torrus::SchedulerInfo;
+use Torrus::Log;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+my $tree;
+my $report_config;
+my $report_runtime;
+my $clear_treestats;
+
+my $help_needed;
+
+
+my $ok = GetOptions('tree=s' => \$tree,
+ 'config' => \$report_config,
+ 'runtime' => \$report_runtime,
+ 'clear' => \$clear_treestats,
+ 'help' => \$help_needed);
+
+if( not $ok or
+ not $tree or
+ not ( $report_config or $report_runtime or $clear_treestats ) or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --config report scheduler configuration\n",
+ " --runtime report scheduler runtime statistics\n",
+ " --clear clear scheduler statistics for specific tree\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+
+if( not Torrus::SiteConfig::treeExists( $tree ) )
+{
+ Error('Tree ' . $tree . ' does not exist');
+ exit 1;
+}
+
+
+&Torrus::DB::setSafeSignalHandlers();
+
+if( $clear_treestats )
+{
+ my $stats = new Torrus::SchedulerInfo( -Tree => $tree, -WriteAccess => 1 );
+ $stats->clearAll();
+ print STDERR "Statistics cleared for tree $tree\n";
+ exit 0;
+}
+
+thickLine();
+printf("Torrus version %s\n", '@VERSION@');
+printf("Datasources tree: %s\n", $tree);
+printf("Date: %s\n\n", scalar( localtime( time() ) ) );
+
+if( $report_config )
+{
+ my $config_tree = new Torrus::ConfigTree( -TreeName => $tree );
+ if( not defined($config_tree) )
+ {
+ Error("Configuration is not ready");
+ exit 1;
+ }
+
+ my $stats = { 'collectorLeaves' => {}, 'monitorLeaves' => 0 };
+
+ collectStats( $config_tree, $stats );
+
+ thickLine();
+ printf("Scheduler configuration report\n\n");
+
+ foreach my $instance ( sort {$a<=>$b} keys %{$stats->{'collectorLeaves'}} )
+ {
+ printf("Collector leaves for instance #%d: %d\n",
+ $instance,
+ $stats->{'collectorLeaves'}{$instance});
+ }
+
+ printf("Total monitor leaves: %d\n\n", $stats->{'monitorLeaves'});
+
+ printf("Scheduled leaves by type:\n");
+
+ foreach my $type ( sort keys %{$stats->{'leavesPerType'}} )
+ {
+ printf(" %10s %-10d\n", $type,
+ $stats->{'leavesPerType'}{$type});
+ }
+ printf("\n");
+
+ foreach my $instance ( sort {$a<=>$b} keys %{$stats->{'collectorLeaves'}} )
+ {
+ if( $stats->{'collectorLeaves'}{$instance} > 0 )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ printf("Collector execution timeline for instance #%d:\n",
+ $instance);
+ reportTimeline( $stats->{'collectorSchedule'}{$instance} );
+ }
+ }
+
+ if( $stats->{'monitorLeaves'} > 0 )
+ {
+ printf("Monitor execution timeline:\n");
+ reportTimeline( $stats->{'monitorSchedule'} );
+ }
+}
+
+if( $report_runtime )
+{
+ my @reportFormats =
+ (
+ { 'label' => 'Running Time',
+ 'varname' => 'RunningTime' },
+
+ { 'label' => 'Late Start',
+ 'varname' => 'LateStart' },
+
+ { 'label' => 'Too Long',
+ 'varname' => 'TooLong' },
+
+ { 'label' => 'RRD Queue',
+ 'varname' => 'RRDQueue' },
+
+ { 'label' => 'Raw Queue',
+ 'varname' => 'RawQueue' }
+
+ );
+
+ my @counterFormats =
+ (
+ { 'label' => 'running cycles passed',
+ 'varname' => 'NTimesRunningTime' },
+
+ { 'label' => 'late starts',
+ 'varname' => 'NTimesLateStart' },
+
+ { 'label' => 'too long runs',
+ 'varname' => 'NTimesTooLong' },
+
+ { 'label' => 'overrun periods',
+ 'varname' => 'CountOverrunPeriods' },
+
+ { 'label' => 'missed periods',
+ 'varname' => 'CountMissedPeriods' }
+ );
+
+ my $sInfo = new Torrus::SchedulerInfo( '-Tree' => $tree );
+ exit(1) if not defined( $sInfo );
+
+ my $stats = $sInfo->readStats();
+
+ thickLine();
+ printf("Scheduler runtime report\n\n");
+
+ my $periodicTasks = {};
+ foreach my $taskId ( keys %{$stats} )
+ {
+ my ($type, $taskName, $instance, $period, $offset) =
+ split( ':', $taskId );
+ if( $type eq 'P' )
+ {
+ $periodicTasks->{$taskName}{$instance}{$period}{$offset} = $taskId;
+ }
+ }
+
+ foreach my $taskName ( sort keys %{$periodicTasks} )
+ {
+ foreach my $instance ( sort {$a<=>$b}
+ keys %{$periodicTasks->{$taskName}} )
+ {
+ foreach my $period
+ ( sort {$a<=>$b}
+ keys %{$periodicTasks->{$taskName}{$instance}} )
+ {
+ foreach my $offset
+ ( sort {$a<=>$b}
+ keys %{$periodicTasks->{$taskName}{$instance}{$period}} )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ my $taskId =
+ $periodicTasks->{$taskName}{$instance}{
+ $period}{$offset};
+ my $ref = $stats->{$taskId};
+
+ printf("Task: %s, Instance: %d, " .
+ "Period: %d seconds, Offset: %d seconds\n",
+ $taskName, $instance, $period, $offset);
+
+ foreach my $format ( @counterFormats )
+ {
+ if( defined( $ref->{$format->{'varname'}} ) )
+ {
+ printf("%5d %s\n",
+ $ref->{$format->{'varname'}},
+ $format->{'label'} );
+ }
+ }
+
+ thinLine();
+ printf("%-15s%-10s%-10s%-10s%-10s\n",
+ '', 'Min', 'Max', 'Average', 'Exp Average');
+
+ foreach my $format ( @reportFormats )
+ {
+ my $varname = $format->{'varname'};
+ if( defined( $ref->{'Min' . $varname} ) )
+ {
+ printf("%-15s%-10d%-10d%-10.1f%-10.1f\n",
+ $format->{'label'},
+ $ref->{'Min' . $varname},
+ $ref->{'Max' . $varname},
+ $ref->{'Avg' . $varname},
+ $ref->{'ExpAvg' . $varname});
+ }
+ }
+
+ thinLine();
+ printf("\n");
+ }
+ }
+ }
+ }
+}
+
+thickLine();
+exit 0;
+
+
+sub collectStats
+{
+ my $config_tree = shift;
+ my $stats = shift;
+ my $token = shift;
+
+ if( not defined( $token ) )
+ {
+ $token = $config_tree->token('/');
+ }
+
+ my @children = $config_tree->getChildren( $token );
+
+ foreach my $ctoken ( @children )
+ {
+ &Torrus::DB::checkInterrupted();
+
+ if( $config_tree->isSubtree( $ctoken ) )
+ {
+ collectStats( $config_tree, $stats, $ctoken );
+ }
+ elsif( $config_tree->isLeaf( $ctoken ) )
+ {
+ if( $config_tree->getNodeParam( $ctoken, 'ds-type' )
+ eq 'collector' )
+ {
+ my $instance =
+ $config_tree->getNodeParam
+ ( $ctoken, 'collector-instance' );
+
+ $stats->{'collectorLeaves'}{$instance}++;
+
+ my $type = 'c:' .
+ $config_tree->getNodeParam( $ctoken, 'collector-type' );
+
+ my $period =
+ $config_tree->getNodeParam( $ctoken, 'collector-period' );
+ $period = int( $period ); # make sure we're talking integers
+
+ my $offset = $config_tree->
+ getNodeParam( $ctoken, 'collector-timeoffset' );
+
+ $stats->{'leavesPerType'}{$type}++;
+ $stats->{'collectorSchedule'}{$instance}{$period}{
+ $offset}{$type}++;
+ }
+
+ if( defined( $config_tree->getNodeParam( $ctoken, 'monitor' ) ) )
+ {
+ $stats->{'monitorLeaves'}++;
+ my $type = 'monitor';
+
+ my $period =
+ $config_tree->getNodeParam( $ctoken, 'monitor-period' );
+ $period = int( $period ); # make sure we're talking integers
+
+ my $offset = $config_tree->
+ getNodeParam( $ctoken, 'monitor-timeoffset' );
+ $offset = int($offset) % $period;
+
+ $stats->{'leavesPerType'}{$type}++;
+ $stats->{'monitorSchedule'}{$period}{$offset}{$type}++;
+ }
+ }
+ }
+}
+
+
+# caluclate and print the schedule
+sub reportTimeline
+{
+ my $schedule = shift;
+
+ # calculate the common period length (least common multiple)
+ my $lcm = 0;
+ foreach my $period ( keys %{$schedule} )
+ {
+ my $a = $period;
+ my $b = $lcm;
+ my $c;
+ if( $b == 0 )
+ {
+ $lcm = $a;
+ }
+ else
+ {
+ if( $a < $b )
+ {
+ my $tmp = $b;
+ $b = $a;
+ $a = $tmp;
+ }
+ while( $b != 0 )
+ {
+ $c = $a % $b;
+ $a = $b;
+ $b = $c;
+ }
+ $lcm = $lcm * $period / $a;
+ }
+ }
+
+ printf("Least common period: %d seconds\n", $lcm);
+
+ # populate the common period
+ my %cp;
+ my $chunks = 0;
+ foreach my $period ( keys %{$schedule} )
+ {
+ foreach my $offset ( keys %{$schedule->{$period}} )
+ {
+ $chunks++;
+ foreach my $type ( keys %{$schedule->{$period}{$offset}} )
+ {
+ for( my $i = 0; $i < ($lcm / $period); $i++ )
+ {
+ $cp{$i * $period + $offset}{'col'}{$type} +=
+ $schedule->{$period}{$offset}{$type};
+ }
+ }
+ }
+ }
+ printf("Number of chunks: %d \n\n", $chunks );
+
+ # calculate interval lengths
+
+ my $previous;
+ my $first;
+ foreach my $time ( sort { $a <=> $b } keys %cp )
+ {
+ if( not defined($first) )
+ {
+ $first = $time;
+ }
+ else
+ {
+ $cp{$previous}{'endtime'} = $time;
+ }
+ $previous = $time;
+ }
+ $cp{$previous}{'endtime'} = $lcm + $first;
+
+ # print results
+
+ thinLine();
+ printf("%-10s%-10s%-20s%-10s\n",
+ 'Offset', 'Interval', 'Type', 'Data');
+ printf("%-10s%-10s%-20s%-10s\n",
+ '(sec)', '(sec)', '', 'sources');
+ thinLine();
+
+ foreach my $time ( sort { $a <=> $b } keys %cp )
+ {
+ foreach my $type ( keys %{$cp{$time}{'col'}} )
+ {
+ printf("%-10d%-10d%-20s%-10d\n",
+ $time,
+ $cp{$time}{'endtime'} - $time,
+ $type,
+ $cp{$time}{'col'}{$type} );
+ }
+ }
+ thinLine();
+ printf("\n");
+}
+
+
+sub thickLine
+{
+ foreach my $i ( 1..75 )
+ {
+ print '=';
+ }
+ print "\n";
+}
+
+sub thinLine
+{
+ foreach my $i ( 1..70 )
+ {
+ print '-';
+ }
+ print "\n";
+}
+
+
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/snmpfailures.in b/torrus/bin/snmpfailures.in
new file mode 100644
index 000000000..f46cc2d4c
--- /dev/null
+++ b/torrus/bin/snmpfailures.in
@@ -0,0 +1,98 @@
+#!@PERL@ -w
+# Copyright (C) 2010 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: snmpfailures.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use Getopt::Long;
+use JSON;
+
+use Torrus::SiteConfig;
+use Torrus::DB;
+use Torrus::Log;
+use Torrus::SNMP_Failures;
+
+exit(1) if not Torrus::SiteConfig::verify();
+
+
+my $tree;
+my $print_details;
+
+my $help_needed;
+
+
+my $ok = GetOptions('tree=s' => \$tree,
+ 'details' => \$print_details,
+ 'help' => \$help_needed);
+
+if( not $ok or not $tree or
+ $help_needed or scalar(@ARGV) > 0 )
+{
+ print STDERR "Usage: $0 --tree=NAME [options...]\n",
+ "Options:\n",
+ " --tree=NAME tree name\n",
+ " --details print failure details\n",
+ " --help this help message\n";
+ exit 1;
+}
+
+
+if( not Torrus::SiteConfig::treeExists( $tree ) )
+{
+ Error('Tree ' . $tree . ' does not exist');
+ exit 1;
+}
+
+
+my $out = {};
+
+&Torrus::DB::setSafeSignalHandlers();
+
+my $nInstances = Torrus::SiteConfig::collectorInstances( $tree );
+for( my $instance = 0; $instance < $nInstances; $instance++ )
+{
+ my $db_failures = new Torrus::SNMP_Failures( -Tree => $tree,
+ -Instance => $instance );
+
+ if( not defined( $db_failures ) )
+ {
+ exit(1);
+ }
+
+
+ $db_failures->read( $out, -details => $print_details );
+ undef $db_failures;
+}
+
+
+my $json = new JSON;
+$json->canonical();
+$json->pretty();
+print $json->encode($out);
+
+
+exit(0);
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/srvderive.in b/torrus/bin/srvderive.in
new file mode 100644
index 000000000..17749170c
--- /dev/null
+++ b/torrus/bin/srvderive.in
@@ -0,0 +1,371 @@
+#!@PERL@
+# Copyright (C) 2008 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: srvderive.in,v 1.1 2010-12-27 00:04:02 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# Combine SUM or MAX from several service IDs and create a new one
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use POSIX qw(floor);
+use Getopt::Long;
+use Date::Parse;
+use Date::Format;
+use Math::BigFloat;
+
+use Torrus::Log;
+use Torrus::ServiceID;
+use Torrus::SQL::SrvExport;
+
+my $startdate;
+my $enddate;
+my $onemonth;
+
+my $function;
+my @input;
+my $output;
+
+my $step = 300;
+
+my $debug;
+my $verbose;
+my $help_needed;
+
+my %known_functions = ('MAX' => \&function_max, 'SUM' => \&function_sum);
+
+
+my $ok = GetOptions(
+ 'start=s' => \$startdate,
+ 'end=s' => \$enddate,
+ 'month' => \$onemonth,
+ 'func=s' => \$function,
+ 'in=s' => \@input,
+ 'out=s' => \$output,
+ 'step=i' => \$step,
+ 'verbose' => \$verbose,
+ 'debug' => \$debug,
+ 'help' => \$help_needed,
+ );
+
+if( $help_needed or not $ok or (not $startdate) or
+ (defined($enddate) + defined($onemonth) != 1) or
+ not $function or
+ (scalar(@input) < 2 and scalar( @ARGV ) < 2) or
+ not $output )
+{
+ print STDERR "Usage: $0 TIMESPAN OUTPUT FUNCTION SOURCES...\n\n",
+ "TIMESPAN:\n",
+ " --start=YYYY-MM-DD [mandatory] Start date\n",
+ " --month [optional] Calendar month timespan\n",
+ " --end=YYYY-MM-DD [optional] Next day after the timespan end\n",
+ " Either --month or --end option must be defined\n\n",
+ "OUTPUT:\n",
+ " --out=SERVICEID [mandatory] Output Service ID\n\n",
+ "FUNCTION:\n",
+ " --func=MAX|SUM [mandatory] Aggregation function\n\n",
+ "SOURCES:\n",
+ " Either --in=SERVICEID, or Service ID names as command line ",
+ "arguments.\n",
+ " Minimum 2 sources required\n\n",
+ "Options:\n",
+ " --step=N [300] service data interval\n",
+ " --verbose print extra information\n",
+ " --debug print debugging information\n",
+ " --help print usage information\n",
+ "\n";
+
+ exit 1;
+}
+
+push(@input, @ARGV);
+
+if( not defined($known_functions{$function}) )
+{
+ printf STDERR ("Unknown function: %s. Must be onne of: %s\n",
+ $function, join(', ', sort keys %known_functions));
+ exit 1;
+}
+
+
+
+if( $debug )
+{
+ Torrus::Log::setLevel('debug');
+}
+elsif( $verbose )
+{
+ Torrus::Log::setLevel('verbose');
+}
+
+
+my $starttime = str2time( $startdate );
+if( not defined($starttime) )
+{
+ Error('Cannot parse start date: ' . $startdate);
+ exit 1;
+}
+
+# Canonize the date
+$startdate = time2str('%Y-%m-%d', $starttime);
+
+my $endtime;
+
+if( defined($enddate) )
+{
+ $endtime = str2time( $startdate );
+ if( not defined($endtime) )
+ {
+ Error('Cannot parse end date: ' . $enddate);
+ exit 1;
+ }
+
+ if( $endtime < $starttime )
+ {
+ Error('End date is earlier than start date');
+ exit 1;
+ }
+}
+else
+{
+ # Calculate +1 calendar month
+
+ my ($ss,$mm,$hh,$day,$month,$year,$zone) =
+ strptime( $startdate );
+ $year += 1900;
+ $month++;
+ $day++;
+
+ my $endyear = $year;
+ my $endmonth = $month + 1;
+
+ if( $endmonth > 12 )
+ {
+ $endmonth = 1;
+ $endyear++;
+ }
+
+ $endtime = str2time( sprintf('%.4d-%.2d-%.2d',
+ $endyear, $endmonth, $day) );
+ if( not defined($endtime) )
+ {
+ # oops, it was past the end of the month
+ $day++;
+ $endmonth++;
+ if( $endmonth > 12 )
+ {
+ $endmonth = 1;
+ $endyear++;
+ }
+
+ $endtime = str2time( sprintf('%.4d-%.2d-%.2d',
+ $endyear, $endmonth, $day) );
+
+ if( not defined($endtime) )
+ {
+ Error('Cannot determine the end date');
+ exit 1;
+ }
+ }
+}
+
+# Canonize the date
+$enddate = time2str('%Y-%m-%d', $endtime);
+
+
+Verbose('Start time: ', scalar(localtime($starttime)));
+Verbose('End time: ', scalar(localtime($endtime)));
+
+my $srvExp = Torrus::SQL::SrvExport->new();
+if( not defined( $srvExp ) )
+{
+ Error('Cannot connect to the SQL database');
+ exit 1;
+}
+
+my $srvIDs = $srvExp->getServiceIDs();
+
+foreach my $serviceid ( @input )
+{
+ if( not grep {$serviceid eq $_} @{$srvIDs} )
+ {
+ Error('Input service ID not found in the database: ' . $serviceid);
+ exit 1;
+ }
+}
+
+&Torrus::DB::setSafeSignalHandlers();
+
+# Check if the output ServiceID exists in the local database
+# The database contains only IDs generated from datasource trees.
+
+my $srvIDParams = new Torrus::ServiceID();
+if( $srvIDParams->idExists( $output ) )
+{
+ Error('Output service ID was previously created from Torrus ' .
+ 'datasource tree. Cannot override it: ' . $output);
+ exit 1;
+}
+&Torrus::DB::cleanupEnvironment();
+&Torrus::DB::setUnsafeSignalHandlers();
+
+
+my %in_data;
+
+foreach my $serviceid ( @input )
+{
+ $in_data{$serviceid} =
+ $srvExp->getIntervalData( $startdate, $enddate, $serviceid );
+
+ Verbose(sprintf('Loaded %d rows of data for %s',
+ scalar( @{$in_data{$serviceid}} ),
+ $serviceid));
+}
+
+my $n_points = floor( ($endtime - $starttime) / $step );
+
+my %aligned_data;
+
+foreach my $serviceid ( @input )
+{
+ my @aligned = ();
+ $#aligned = $n_points;
+
+ # Fill in the aligned array. For each interval by modulo(step),
+ # we take the sum of values that get into that interval
+
+ foreach my $row ( @{$in_data{$serviceid}} )
+ {
+ my $rowtime = str2time( $row->{'srv_date'} . 'T' .
+ $row->{'srv_time'} );
+
+ my $pos = floor( ($rowtime - $starttime) / $step );
+ my $value = Math::BigFloat->new( $row->{'value'} );
+ if( $value->is_nan() )
+ {
+ $value->bzero();
+ }
+
+ if( not defined($aligned[$pos]))
+ {
+ $aligned[$pos] = $value;
+ }
+ else
+ {
+ $aligned[$pos]->badd($value);
+ }
+ }
+
+ $aligned_data{$serviceid} = \@aligned;
+}
+
+Verbose(sprintf('Aligned data into %d intervals', $n_points));
+
+# Store the derived data
+my $dbh = Torrus::SQL::SrvExport->dbh();
+if( not defined( $dbh ) )
+{
+ Error('Lost SQL connection');
+ exit 1;
+}
+
+my $sth = $dbh->prepare( Torrus::SQL::SrvExport->sqlInsertStatement() );
+if( not defined( $sth ) )
+{
+ Error('Error preparing the SQL statement: ' . $dbh->errstr);
+}
+
+
+
+for( my $pos = 0; $pos < $n_points; $pos++ )
+{
+ my @args;
+ foreach my $serviceid ( @input )
+ {
+ my $val = $aligned_data{$serviceid}->[$pos];
+ if( defined( $val ) )
+ {
+ push( @args, $val );
+ }
+ }
+
+ if( scalar( @args ) > 0 )
+ {
+ my $value = &{$known_functions{$function}}(@args);
+
+ my $timestamp = $starttime + $pos * $step;
+ my $datestr = time2str('%Y-%m-%d', $timestamp);
+ my $timestr = time2str('%H:%M:%S', $timestamp);
+
+ if( isDebug() )
+ {
+ Debug('Updating SQL database: ' .
+ join(', ', $datestr, $timestr,
+ $output, $value, $step ));
+ }
+
+ if( not $sth->execute( $datestr, $timestr,
+ $output, $value, $step ) )
+ {
+ Error('Error executing SQL: ' . $dbh->errstr);
+ exit 1;
+ }
+ }
+}
+
+Verbose('Database update finished');
+
+exit($ok ? 0:1);
+
+
+sub function_max
+{
+ my $value = Math::BigFloat->new();
+ $value->binf('-');
+
+ foreach my $a ( @_ )
+ {
+ if( $value->bcmp($a) < 0 )
+ {
+ $value = Math::BigFloat->new($a);
+ }
+ }
+
+ return $value;
+}
+
+
+sub function_sum
+{
+ my $value = Math::BigFloat->new(0);
+
+ foreach my $a ( @_ )
+ {
+ $value->badd($a);
+ }
+
+ return $value;
+}
+
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/torrus.fcgi.in b/torrus/bin/torrus.fcgi.in
new file mode 100644
index 000000000..fc6ee41a2
--- /dev/null
+++ b/torrus/bin/torrus.fcgi.in
@@ -0,0 +1,50 @@
+#!@PERL@ -w
+# Copyright (C) 2010 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: torrus.fcgi.in,v 1.1 2010-12-27 00:04:02 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+# FastCGI handler
+# Can be used as alternative to mod_perl in Apache
+# Can also be used with lighttpd
+
+
+BEGIN { require '@torrus_config_pl@'; }
+
+use strict;
+use CGI::Fast;
+use Torrus::Log;
+use Torrus::CGI;
+
+
+if( $Torrus::Renderer::globalDebug )
+{
+ &Torrus::Log::setLevel('debug');
+}
+
+
+while( my $q = new CGI::Fast )
+{
+ Torrus::CGI->process($q);
+}
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/torrus.in b/torrus/bin/torrus.in
new file mode 100644
index 000000000..7c5118c2c
--- /dev/null
+++ b/torrus/bin/torrus.in
@@ -0,0 +1,76 @@
+#!@SHELL@
+# Copyright (C) 2004 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: torrus.in,v 1.1 2010-12-27 00:04:00 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+#
+
+# CLI wrapper for Torrus utilities
+
+cmd=$1
+
+commands="acl=acledit acledit=acledit \
+ bs=buildsearchdb buildsearchdb=buildsearchdb \
+ cleanup=cleanup \
+ clc=clearcache clearcache=clearcache \
+ collector=collector \
+ compile=compilexml compilexml=compilexml \
+ configinfo=configinfo ci=configinfo \
+ snapshot=configsnapshot configsnapshot=configsnapshot \
+ dd=devdiscover discover=devdiscover devdiscover=devdiscover \
+ fm=flushmonitors flushmonitors=flushmonitors \
+ genddx=genddx \
+ genlist=genlist \
+ genreport=genreport report=genreport \
+ install_plugin=install_plugin \
+ monitor=monitor \
+ nodeid=nodeid ni=nodeid \
+ rrddir=rrddir2xml rrddir2xml=rrddir2xml \
+ schedulerinfo=schedulerinfo si=schedulerinfo \
+ snmpfailures=snmpfailures failures=snmpfailures \
+ srvderive=srvderive derive=srvderive \
+ ttproclist=ttproclist"
+
+for f in `ls -1 @plugwrapperdir@`; do
+ . @plugwrapperdir@/${f}
+done
+
+for pair in ${commands}; do
+ eval execcmd_${pair}
+done
+
+eval expanded_cmd='${execcmd_'${cmd}'}'
+
+
+if test ${expanded_cmd:-no} = no; then
+ echo "Usage: $0 cmd [options...]" 1>&2
+ echo " cmd is one of:" 1>&2
+ for pair in ${commands}; do
+ eval `echo ${pair} | sed -e 's/=.*//' -e 's/^/a=/'`
+ echo " "${a}
+ done
+else
+ shift
+ @pkgbindir@/${expanded_cmd} "$@"
+fi
+
+
+# Local Variables:
+# mode: shell-script
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End:
diff --git a/torrus/bin/ttproclist.in b/torrus/bin/ttproclist.in
new file mode 100644
index 000000000..614cdd618
--- /dev/null
+++ b/torrus/bin/ttproclist.in
@@ -0,0 +1,135 @@
+#!@PERL@
+# Copyright (C) 2005 Stanislav Sinyagin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# $Id: ttproclist.in,v 1.1 2010-12-27 00:04:03 ivan Exp $
+# Stanislav Sinyagin <ssinyagin@yahoo.com>
+
+
+use strict;
+use Template;
+use Getopt::Long;
+
+my $template;
+my $outfile;
+my $nodelist;
+my $parameters;
+
+
+my $creator = "Torrus version @VERSION@\n" .
+ "This file was generated by command:\n" .
+ $0 . " \\\n";
+foreach my $arg ( @ARGV )
+{
+ if( $arg =~ /^--/ )
+ {
+ $creator .= ' ' . $arg . ' ';
+ }
+ else
+ {
+ $creator .= "\'" . $arg . "\'\\\n";
+ }
+}
+$creator .= "\nOn " . scalar(localtime(time));
+
+
+my $ok = GetOptions( 'tmpl=s' => \$template,
+ 'out=s' => \$outfile,
+ 'nodes=s' => \$nodelist,
+ 'param=s' => \$parameters );
+
+if( not $ok or not $template or not $outfile or not $nodelist)
+{
+ print STDERR "Process a template with a nodelist\n\n";
+
+ print STDERR "Usage: $0 options...\n",
+ "Mandatory options:\n",
+ " --tmpl=filename template file name\n",
+ " --out=filename output file\n",
+ " --nodes=filename file with nodes\n",
+ "Options:\n",
+ " --param=NAME:VALUE,NAME:VALUE... parameters passed to template\n";
+ exit 1;
+}
+
+my @rawnodes;
+
+if( not open( NODES, $nodelist ) )
+{
+ print STDERR "Cannot open $nodelist: $!\n";
+ exit 1;
+}
+while(<NODES>)
+{
+ s/^\s+//;
+ s/\s+$//;
+ push( @rawnodes, split( /\s+/ ) );
+}
+close( NODES );
+
+my %nodes;
+foreach my $node ( @rawnodes )
+{
+ my $symname = $node;
+ if( $node =~ /([^:]+):(.+)/ )
+ {
+ $node = $1;
+ $symname = $2;
+ }
+
+ $nodes{$node} = $symname;
+}
+
+my %params;
+if( defined( $parameters ) )
+{
+ foreach my $pair ( split( '\s*,\s*', $parameters ) )
+ {
+ my ($name, $val) = split( '\s*:\s*', $pair );
+ $params{$name} = $val;
+ }
+}
+
+my $tt = new Template( INCLUDE_PATH => '@tmpluserdir@',
+ ABSOLUTE => 1,
+ RELATIVE => 1,
+ TRIM => 1 );
+
+my $vars =
+{
+ 'nodes' => \%nodes,
+ 'param' => \%params,
+ 'nodesfile' => $nodelist,
+ 'creator' => $creator,
+ 'lc' => sub{ return lc $_[0] },
+ 'uc' => sub{ return uc $_[0] }
+};
+
+my $result = $tt->process($template, $vars, $outfile);
+
+if( not $result )
+{
+ print STDERR "Error while processing template: ".$tt->error()."\n";
+}
+
+exit( $result ? 0:1 );
+
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 4
+# End: