From 797bccfa316be0da47872bcac7fa34f5e199fc30 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 18 Apr 2019 17:09:18 +0200 Subject: [PATCH] Imported Upstream version 4.4.3 --- .gitignore | 13 +- .travis.yml | 159 + CONTRIBUTING.md | 2 +- Changelog | 92 +- Makefile.in | 89 +- README | 1 - README.asciidoc => README.md | 39 +- THANKS | 8 + aclocal.m4 | 7 + autoconf-macros/.gitignore | 1 + autoconf-macros/CHANGELOG.md | 7 + autoconf-macros/LICENSE | 264 ++ autoconf-macros/LICENSE.md | 1 + autoconf-macros/README.md | 199 + autoconf-macros/add_group_user | 164 + autoconf-macros/ax_nagios_get_distrib | 160 + autoconf-macros/ax_nagios_get_files | 131 + autoconf-macros/ax_nagios_get_inetd | 146 + autoconf-macros/ax_nagios_get_init | 200 + autoconf-macros/ax_nagios_get_os | 101 + autoconf-macros/ax_nagios_get_paths | 783 ++++ autoconf-macros/ax_nagios_get_ssl | 303 ++ base/Makefile.in | 12 +- base/checks.c | 3726 ++++++++------- base/commands.c | 723 +-- base/config.c | 48 +- base/events.c | 237 +- base/flapping.c | 20 +- base/nagios.c | 66 +- base/nerd.c | 7 + base/notifications.c | 89 +- base/query-handler.c | 298 +- base/utils.c | 517 ++- base/workers.c | 416 +- cgi/Makefile.in | 4 +- cgi/archivejson.c | 6 +- cgi/avail.c | 4039 ++++++++++------- cgi/cgiutils.c | 12 +- cgi/cmd.c | 396 +- cgi/config.c | 2 +- cgi/extcmd_list.c | 79 +- cgi/extinfo.c | 9 +- cgi/getcgi.c | 16 +- cgi/histogram.c | 4 +- cgi/history.c | 2 +- cgi/notifications.c | 2 +- cgi/objectjson.c | 4 +- cgi/outages.c | 2 +- cgi/showlog.c | 2 +- cgi/status.c | 84 +- cgi/statusjson.c | 4 +- cgi/statusmap.c | 4 +- cgi/statuswml.c | 4 +- cgi/statuswrl.c | 21 +- cgi/summary.c | 4 +- cgi/tac.c | 34 +- cgi/trends.c | 4 +- common/Makefile.in | 4 +- common/downtime.c | 4 +- common/macros.c | 163 +- common/objects.c | 17 +- common/shared.c | 38 + configure | 1761 ++++++- configure.ac | 330 +- contrib/Makefile.in | 8 +- contrib/convertcfg.c | 8 +- contrib/exfoliation/stylesheets/status.css | 1 + docs/workers.dox | 17 - doxy.conf | 2 +- html/Makefile.in | 28 +- .../angularjs/ui-bootstrap-tpls-0.12.0.min.js | 10 - .../angularjs/ui-bootstrap-tpls-0.14.3.min.js | 12 + html/angularjs/ui-utils-0.2.1.zip | Bin 34494 -> 0 bytes html/angularjs/ui-utils-0.2.3.zip | Bin 0 -> 35437 bytes html/bootstrap-3.3.0-dist.zip | Bin 230095 -> 0 bytes html/bootstrap-3.3.7-dist.zip | Bin 0 -> 372910 bytes html/d3-3.5.17.zip | Bin 0 -> 129590 bytes html/d3-3.5.3.zip | Bin 128342 -> 0 bytes html/histogram-form.html | 2 +- html/histogram-links.html | 2 +- html/histogram.html | 10 +- html/includes/utils.inc.php | 166 +- html/index.php.in | 15 +- html/js/jquery-1.12.4.min.js | 5 + html/js/jquery-1.7.1.min.js | 4 - html/js/map-directive.js | 42 +- html/js/nagios-decorations.js | 13 +- html/js/trends-graph.js | 2 +- html/jsonquery.html | 8 +- html/main.php | 31 +- html/map-form.html | 2 +- html/map-links.html | 6 +- html/map.php | 47 +- html/side.php | 2 +- html/stylesheets/status.css | 2 +- html/trends.html | 8 +- include/cgiutils.h | 17 +- include/comments.h | 2 +- include/common.h | 4 +- include/config.h.in | 6 + include/locations.h.in | 2 +- include/logging.h | 5 +- include/macros.h | 6 +- include/nagios.h | 29 +- include/objects.h | 3 + include/shared.h | 1 + include/workers.h | 6 +- lib/iobroker.c | 2 +- lib/iobroker.h.in | 4 +- lib/iocache.c | 28 +- lib/iocache.h | 2 +- lib/kvvec.c | 18 +- lib/nsock.h | 2 +- lib/nspath.c | 4 +- lib/nspath.h | 2 +- lib/nwrite.h | 9 +- lib/pqueue.h | 2 +- lib/runcmd.c | 32 +- lib/runcmd.h | 3 +- lib/skiplist.c | 2 +- lib/snprintf.c | 2 +- lib/test-dkhash.c | 2 +- lib/worker.c | 28 +- lib/worker.h | 2 +- lib/wproc.c | 14 +- nagios.spec | 100 +- sample-config/cgi.cfg.in | 60 +- sample-config/nagios.cfg.in | 184 +- sample-config/resource.cfg.in | 6 +- sample-config/template-object/commands.cfg.in | 268 +- sample-config/template-object/contacts.cfg.in | 33 +- .../template-object/localhost.cfg.in | 151 +- sample-config/template-object/printer.cfg.in | 76 +- sample-config/template-object/switch.cfg.in | 101 +- .../template-object/templates.cfg.in | 273 +- .../template-object/timeperiods.cfg.in | 129 +- sample-config/template-object/windows.cfg.in | 125 +- startup/.gitignore | 2 + daemon-init.in => startup/default-init.in | 134 +- startup/default-service.in | 15 + openrc-init.in => startup/openrc-init.in | 10 +- startup/upstart-init.in | 25 + subst.in | 2 +- t-tap/Makefile.in | 22 +- t-tap/colorize.sh | 82 + t-tap/stub_broker.c | 59 +- t-tap/stub_checks.c | 45 +- t-tap/stub_commands.c | 7 +- t-tap/stub_comments.c | 40 +- t-tap/stub_downtime.c | 85 +- t-tap/stub_events.c | 15 +- t-tap/stub_flapping.c | 32 +- t-tap/stub_iobroker.c | 15 +- t-tap/stub_logging.c | 85 +- t-tap/stub_macros.c | 42 +- t-tap/stub_nebmods.c | 19 +- t-tap/stub_netutils.c | 11 +- t-tap/stub_notifications.c | 20 +- t-tap/stub_nsock.c | 8 +- t-tap/stub_objects.c | 44 +- t-tap/stub_perfdata.c | 13 +- t-tap/stub_sehandlers.c | 20 +- t-tap/stub_shared.c | 4 +- t-tap/stub_sretention.c | 7 +- t-tap/stub_statusdata.c | 23 +- t-tap/stub_utils.c | 19 +- t-tap/stub_workers.c | 15 +- t-tap/stub_xdddefault.c | 24 +- t-tap/stub_xodtemplate.c | 6 +- t-tap/test_checks.c | 1894 ++++++-- t-tap/test_commands.c | 47 +- t-tap/test_downtime.c | 246 +- t-tap/test_events.c | 510 ++- t-tap/test_logging.c | 145 +- t-tap/test_macros.c | 446 +- t-tap/test_nagios_config.c | 4 + t-tap/test_timeperiods.c | 4 + t-tap/var/reaper/no_files/.keep | 1 + t-tap/var/reaper/some_files/.keep | 0 t/615cgierror.t | 2 +- t/618cgisecurity.t | 2 +- t/var/objects.precache.expected | 20 +- tap/aclocal.m4 | 2 +- tap/config.guess | 2 +- tap/configure | 2 +- tap/src/tap.3 | 4 +- update-version | 7 +- worker/ping/worker-ping.c | 2 +- xdata/xodtemplate.c | 274 +- xdata/xrddefault.c | 6 + 190 files changed, 15702 insertions(+), 7150 deletions(-) create mode 100644 .travis.yml delete mode 100644 README rename README.asciidoc => README.md (61%) create mode 100755 aclocal.m4 create mode 100644 autoconf-macros/.gitignore create mode 100644 autoconf-macros/CHANGELOG.md create mode 100644 autoconf-macros/LICENSE create mode 120000 autoconf-macros/LICENSE.md create mode 100644 autoconf-macros/README.md create mode 100755 autoconf-macros/add_group_user create mode 100644 autoconf-macros/ax_nagios_get_distrib create mode 100644 autoconf-macros/ax_nagios_get_files create mode 100644 autoconf-macros/ax_nagios_get_inetd create mode 100644 autoconf-macros/ax_nagios_get_init create mode 100644 autoconf-macros/ax_nagios_get_os create mode 100644 autoconf-macros/ax_nagios_get_paths create mode 100644 autoconf-macros/ax_nagios_get_ssl delete mode 100644 html/angularjs/ui-bootstrap-tpls-0.12.0.min.js create mode 100644 html/angularjs/ui-bootstrap-tpls-0.14.3.min.js delete mode 100644 html/angularjs/ui-utils-0.2.1.zip create mode 100644 html/angularjs/ui-utils-0.2.3.zip delete mode 100644 html/bootstrap-3.3.0-dist.zip create mode 100644 html/bootstrap-3.3.7-dist.zip create mode 100644 html/d3-3.5.17.zip delete mode 100644 html/d3-3.5.3.zip create mode 100644 html/js/jquery-1.12.4.min.js delete mode 100644 html/js/jquery-1.7.1.min.js create mode 100644 startup/.gitignore rename daemon-init.in => startup/default-init.in (65%) create mode 100644 startup/default-service.in rename openrc-init.in => startup/openrc-init.in (98%) create mode 100644 startup/upstart-init.in create mode 100644 t-tap/colorize.sh create mode 100644 t-tap/var/reaper/no_files/.keep create mode 100644 t-tap/var/reaper/some_files/.keep diff --git a/.gitignore b/.gitignore index 256454b..154f66e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,6 @@ nbproject/ *.o *.la *.lo -*.gcda -*.gcno -*.gcov *.a *.so cgi/run* @@ -36,8 +33,14 @@ core.[1-9]* *.pre-indent *.swp +*.gcda +*.gcno +*.gcov +coverage-report/ +nagioscore.info-file + html/angularjs/angular-1.3.9 -html/angularjs/ui-utils-0.2.1 -html/bootstrap-3.3.0 +html/angularjs/ui-utils-0.2.3 +html/bootstrap-3.3.7 html/d3 html/index.php diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9ce1c84 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,159 @@ +language: c + +sudo: true + +matrix: + include: + - os: linux + dist: trusty + addons: + apt: + packages: + - apache2 + - build-essential + - gcovr + - gperf + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=gcc && CXX=g++" + + - os: linux + dist: trusty + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - apache2 + - build-essential + - gcovr + - gperf + - g++-5 + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + + - os: linux + dist: trusty + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - apache2 + - build-essential + - gcovr + - gperf + - g++-6 + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + + - os: linux + dist: trusty + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - apache2 + - build-essential + - gcovr + - gperf + - g++-7 + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + + - os: linux + dist: trusty + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - apache2 + - build-essential + - gcovr + - gperf + - g++-8 + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + + - os: linux + dist: trusty + addons: + apt: + sources: + - llvm-toolchain-trusty-5.0 + packages: + - apache2 + - build-essential + - clang-5.0 + - gcovr + - gperf + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + + - os: linux + dist: trusty + addons: + apt: + sources: + - llvm-toolchain-trusty-6.0 + - ubuntu-toolchain-r-test + packages: + - apache2 + - build-essential + - clang-6.0 + - gcovr + - gperf + - g++-4.9 + - lcov + - libgd-dev + - php5 + - php5-gd + - unzip + - valgrind + env: + - MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" + +before_install: + - eval "${MATRIX_EVAL}" + +script: + - ./configure --enable-testing + - make test + - gcovr -r . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e2e8b6..9b7fe3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,7 +155,7 @@ When you submit a Pull Request, make sure you follow the guidelines: * Keep commit messages as concise as possible. * Update the appropriate files in regards to your changes: - * `CHANGES` + * `Changelog` * `THANKS` diff --git a/Changelog b/Changelog index f0bbf75..ccdf094 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,92 @@ Nagios Core 4 Change Log ######################## +4.4.3 - 2019-01-15 +------------------ +FIXES +* Fixed services sending recovery emails when they recover if host in down state (#572) (Scott Wilkerson) +* Fixed a make error when building on the aarch64 architecture (#598) (Gareth Randall) +* Fixed --with-cgibindir and --with-webdir to actually set values given (#585) (lawsontyler) +* Fixed soft recovery states for services (#575) (Jake Omann) +* Fixed XSS vulnerability in Alert Summary report (CVE-2018-18245) (Jake Omann) +* Fixed services in soft states sometimes not switching into hard states (#576) (Jake Omann) +* Fixed last_state_change to update when a state goes from soft -> hard state (#592) (Jake Omann) +* Fixed Map link always being set to undefined host and don't show link for Nagios Process root note (#539) (Jake Omann) +* Fixed notifications sending when services went into hard state on a down or unreachable host (#584) (Jake Omann) +* Fixed log_host_retries not logging the host soft state checks (#599) (Jake Omann) +* Fixed stalking_options N option to properly log only when a notification is actually sent (#604) (Jake Omann) +* Fixed issue with service status totals being zero when servicegroup=all on servicegroup status page (#579) (Jake Omann) +* Fixed escalation notifications logic and recovery notifications not going out (#582) (Jake Omann) +* Fixed not finding child index causing duplicate hosts showing in the Map (#471) (Jake Omann) +* Fixed Map configuration popup checkboxes not working and Root Node not populating (#543) (Jake Omann) +* Fixed cleanup and deinit of neb modules on reload (#573) (Jake Omann) + + +4.4.2 - 2018-08-16 +------------------ +FIXES +* Fix comment data being duplicated after a `service nagios reload` or similar (#549) (Bryan Heden) +* Fix check_interval and retry_interval not changing at the appropriate times (#551) (Scott Wilkerson) +* Fixed passive checks sending recovery email when host was previously UP (#552) (Scott Wilkerson) +* Fixed flapping comments duplication on nagios reload (#554) (Christian Jung) +* Fix for CVE-2018-13441, CVE-2018-13458, CVE-2018-13457 null pointer dereference (Trevor McDonald) +* Fixed syntax error in file: default-init.in (#558) (Christian Zettel) +* Reset current notification number and state flags when the host recovers, reset all service variables when they recover fixes (#557) (Scott Wilkerson) +* Fixed wrong counting of service status totals when showing servicegroup details (#548) (Christian Zettel, Bryan Heden) +* Fixed avail.cgi not printing CSV output when checkbox is checked (for any type: host/service/hostgroup/servicegroup) (#570) (Bryan Heden) +* Fixed nagios not logging SOFT state changes after 1 (Scott Wilkerson) + + +4.4.1 - 2018-06-25 +------------------ +FIXES +* Revert some macro->kvvec changes causing problems when `enable_environment_macros` was enabled (Bryan Heden) +* Adjust `process_macro_r` function logic so that it handles macros properly (Bryan Heden) +* Fix spec file for systemd (Karsten Weiss, Fr3dY, Bryan Heden) +* Fix bug where `ssize_t` typedef to int on some systems (Bryan Heden) + + +4.4.0 - 2018-06-19 +------------------ +ENHANCEMENTS +* new status for check dependencies (John Frickson) +* Allow more flexible requirements for comments (John Frickson) +* Add a `statusCRITICALACK` class for the status column (John Frickson) +* CSV output based on groups (all options) (John Frickson) +* New Macro(s) to generate URL for host / service object to be used in notifications (John Frickson) +* New Macro(s) to determine if host/service notifications are enabled (#419) (Bryan Heden) +* New Macro(s) for obtaining the host/service notification periods (#350) (Bryan Heden) +* enable_page_tour interface option (Bryan Heden) +* Code cleanups in important sections (Workers, Handling Results) (Bryan Heden) +* Automatic mail program detection (with same /bin/mail failback) (Bryan Heden) +* Incorporated [autoconf-macros](https://github.com/NagiosEnterprises/autoconf-macros) into Core (Bryan Heden) +* Lots of enhancements/additions to configure/make process. (Bryan Heden) + * Moved all files to startup/ + * Added upstart job +* Added system limit detection (RLIMIT_NPROC) to check for anticipated fork() failures (#434) (Bryan Heden) +* Added stalking on notifications (`N` or `notifications` option when specifying `stalking_options`) (#342) (Bryan Heden) +* Added automatic `systemctl daemon-reload` and `initctl reload-configuration` where applicable on `make install-init` (Bryan Heden) +* Added case-insentive command submission. (#373) (Bryan Heden) +* Enabled `check_external_commands` by default (Bryan Heden) + +FIXES +* Command line macro detection skips potential macros with no ending dollar sign (Bryan Heden, Jake Omann) +* Fixed a lockup condition sometimes encountered on shutdown or restart (Aaron Beck) +* Fixed negative time offset calculations computing incorrectly sometimes (bbeutel) +* Fixed reloads causing defunct (zombie) processes (#441) (Bryan Heden) +* Fixed wait3(), wait4() implementations (replaced with waitpid()) (#326) (Bryan Heden) +* Fixed additive inheritance not testing for duplicates in hosts/services/(+escalations) (#392) (Bryan Heden) +* Fixed very very (around 600k chars or greater) large plugin output crashing Nagios (#432) (Bryan Heden) +* Fixed first_notification_delay not beeing calculated from last_hard_state_change (#425) (Christian Zettel) +* Fixed duplicate downtime ID occuring from downtimes in retention file (#506) (Franz [feisenko]) +* Fixed segfault when navbarsearch was used in status.cgi for something other than a host (#489) (Bryan Heden) +* Fixed some miscellaneous ./configure issues on Solaris (Bryan Heden, Troy Lea) +* Fixed "Locate host on map" link (#496) (Troy Lea) +* Fixed service groups defined with unknown service members (that aren't first in the list) not erroring out (#500) (Bryan Heden) +* Fixed tac.cgi to have consistent behavior with the other cgis (#481) (Bryan Heden, Matt Capra) +* Fixed clear_host/service_flapping command logic to broker/notify properly (#525) (Bryan Heden, Karsten Weiss) + + 4.3.4 - 2017-08-24 ------------------ * Improved config file parsing (Mark Felder) @@ -15,7 +101,7 @@ Nagios Core 4 Change Log ------------------ * xodtemplate.c wrong option-deprecation code warning (alex2grad / John Frickson) * On-demand host check always use cached host state (John Frickson) -* 'á' causes Serivce Status Information to not be displayed (John Frickson) +* 'á' causes Service Status Information to not be displayed (John Frickson) * New Macro(s) to generate URL for host / service object (John Frickson) * Fix minor map issues (Troy Lea) * Fix lockfile issues (Bryan Heden) @@ -25,7 +111,7 @@ Nagios Core 4 Change Log 4.3.2 - 2017-05-09 ------------------ -FIXED +FIXES * Every 15sec /var/log/messages is flooded with "nagios: set_environment_var" (John Frickson) * Changed release date to ISO format (yyyy-mm-dd) (John Frickson) * `make all` fails if unzip is not installed (John Frickson) @@ -410,5 +496,5 @@ FIXES 4.0.0 - 09/20/2013 ------------------ -See http://nagios.sourceforge.net/docs/nagioscore/4/en/whatsnew.html for a +See https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/4/en/whatsnew.html for a list of the changes in Nagios Core 4 diff --git a/Makefile.in b/Makefile.in index a6a520f..b992ab1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,11 +27,11 @@ LOGDIR=@localstatedir@ CHECKRESULTDIR=@CHECKRESULTDIR@ CFGDIR=@sysconfdir@ BINDIR=@bindir@ -CGIDIR=@sbindir@ +CGIDIR=@cgibindir@ LIBEXECDIR=@libexecdir@ LIBDIR=@libdir@ INCLUDEDIR=@includedir@/nagios -HTMLDIR=@datadir@ +HTMLDIR=@webdir@ datarootdir=@datarootdir@ LN_S=@LN_S@ INSTALL=@INSTALL@ @@ -39,9 +39,16 @@ INSTALL_OPTS=@INSTALL_OPTS@ COMMAND_OPTS=@COMMAND_OPTS@ HTTPD_CONF=@HTTPD_CONF@ LN_HTTPD_SITES_ENABLED=@LN_HTTPD_SITES_ENABLED@ -INIT_DIR=@init_dir@ +INIT_DIR=@initdir@ INIT_OPTS=@INIT_OPTS@ CGICFGDIR=$(CGIDIR) +NAGIOS_USER=@nagios_user@ +NAGIOS_GRP=@nagios_grp@ +DIST=@dist_type@ + +SRC_INIT=@src_init@ +INIT_FILE=@initname@ +INIT_TYPE=@init_type@ USE_EVENTBROKER=@USE_EVENTBROKER@ USE_LIBTAP=@USE_LIBTAP@ @@ -55,9 +62,17 @@ CP=@CP@ none: @echo "Please supply a command line argument (i.e. 'make all'). Other targets are:" @echo " nagios cgis contrib modules workers" - @echo " clean" - @echo " install install-base install-cgis install-html install-exfoliation install-config install-init install-commandmode fullinstall" + @echo " test" + @echo " install install-base" + @echo " install-cgis install-html" + @echo " install-webconf install-config" + @echo " install-init install-daemoninit" + @echo " install-commandmode install-groups-users" + @echo " install-exfoliation install-classicui" + @echo " install-basic install-unstripped" + @echo " fullinstall" # @echo " uninstall" + @echo " clean" # FreeBSD make does not support -C option, so we'll use the Apache style... (patch by Stanley Hopcroft 12/27/1999) @@ -82,8 +97,11 @@ all: @echo "*** Compile finished ***" @echo "" @echo "If the main program and CGIs compiled without any errors, you" - @echo "can continue with installing Nagios as follows (type 'make'" - @echo "without any arguments for a list of all possible options):" + @echo "can continue with testing or installing Nagios as follows (type" + @echo "'make' without any arguments for a list of all possible options):" + @echo "" + @echo " make test" + @echo " - This runs the test suite" @echo "" @echo " make install" @echo " - This installs the main program, CGIs, and HTML files" @@ -91,6 +109,13 @@ all: @echo " make install-init" @echo " - This installs the init script in $(DESTDIR)$(INIT_DIR)" @echo "" + @echo " make install-daemoninit" + @echo " - This will initialize the init script" + @echo " in $(DESTDIR)$(INIT_DIR)" + @echo "" + @echo " make install-groups-users" + @echo " - This adds the users and groups if they do not exist" + @echo "" @echo " make install-commandmode" @echo " - This installs and configures permissions on the" @echo " directory for holding the external command file" @@ -183,6 +208,11 @@ clean: cd $(SRC_WORKERS) && $(MAKE) $@ rm -f *.cfg core rm -f *~ *.*~ */*~ */*.*~ */*/*.*~ + rm -f nagioscore.info-file + rm -f *.gcno */*.gcno */*/*.gcno + rm -f *.gcda */*.gcda */*/*.gcda + rm -f *.gcov */*.gcov */*/*.gcov + rm -rf coverage-report distclean: clean cd $(SRC_LIB) && $(MAKE) $@ @@ -197,7 +227,7 @@ distclean: clean cd $(SRC_TTAP) && $(MAKE) $@ cd $(SRC_WORKERS) && $(MAKE) $@ rm -f sample-config/*.cfg sample-config/*.conf sample-config/template-object/*.cfg - rm -f daemon-init openrc-init pkginfo + rm -f daemon-init daemon-service daemon-openrc pkginfo rm -f Makefile subst rm -f config.log config.status config.cache rm -f tags @@ -222,6 +252,16 @@ tap/src/tap.o: test-perl: cgis cd t && $(MAKE) test +coverage: test + @if ! which lcov >/dev/null 2>&1; then \ + echo "ERROR: You must install lcov and genhtml first"; \ + else \ + lcov -c -d . -o nagioscore.info-file; \ + genhtml nagioscore.info-file -o coverage-report; \ + echo "Your coverage report is in coverage-report/index.html"; \ + fi + + install-html: cd $(SRC_HTM) && $(MAKE) install $(MAKE) install-exfoliation @@ -270,7 +310,6 @@ install-basic: @echo " - This installs sample config files in $(DESTDIR)$(CFGDIR)" @echo "" - install-config: $(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(CFGDIR) $(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(CFGDIR)/objects @@ -294,6 +333,9 @@ install-config: @echo "services, hosts, etc. to fit your particular needs." @echo "" +install-groups-users: + @autoconf-macros/add_group_user $(DIST) $(NAGIOS_USER) $(NAGIOS_GRP) 1 + install-webconf: $(INSTALL) -m 644 sample-config/httpd.conf $(DESTDIR)$(HTTPD_CONF)/nagios.conf if [ $(LN_HTTPD_SITES_ENABLED) -eq 1 ]; then \ @@ -338,11 +380,32 @@ install-classicui: @echo "NOTE: Use 'make install-exfoliation' to use new Nagios theme"; @echo "" -install-init: install-daemoninit - -install-daemoninit: +install-init: $(INSTALL) -m 755 -d $(INIT_OPTS) $(DESTDIR)$(INIT_DIR) - $(INSTALL) -m 755 $(INIT_OPTS) daemon-init $(DESTDIR)$(INIT_DIR)/nagios + $(INSTALL) -m 755 $(INIT_OPTS) startup/$(SRC_INIT) $(DESTDIR)$(INIT_DIR)/$(INIT_FILE) + +install-daemoninit: install-init + @if [ x$(INIT_TYPE) = xsysv ]; then \ + if which chkconfig >/dev/null 2>&1; then \ + chkconfig --add nagios; \ + elif which update-rc.d >/dev/null 2>&1; then \ + update-rc.d nagios defaults; \ + fi \ + elif [ x$(INIT_TYPE) = xsystemd ]; then \ + if which systemctl >/dev/null 2>&1; then \ + systemctl daemon-reload; \ + systemctl enable nagios.service; \ + fi; \ + chmod 0644 $(INIT_DIR)/$(INIT_FILE); \ + elif [ x$(INIT_TYPE) = xupstart ]; then \ + if which initctl >/dev/null 2>&1; then \ + initctl reload-configuration; \ + fi \ + elif [ x$(INIT_TYPE) = xopenrc ]; then \ + if which rc-update >/dev/null 2>&1; then \ + rc-update add nagios default; \ + fi \ + fi @echo "" @echo "*** Init script installed ***" diff --git a/README b/README deleted file mode 100644 index d469d9b..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -README.asciidoc \ No newline at end of file diff --git a/README.asciidoc b/README.md similarity index 61% rename from README.asciidoc rename to README.md index e24d296..148d677 100644 --- a/README.asciidoc +++ b/README.md @@ -1,5 +1,10 @@ -Nagios 4.x README -================= +Nagios 4.x +========== + +![Nagios!](https://www.nagios.com/wp-content/uploads/2015/05/Nagios-Black-500x124.png) + +[![Build Status](https://travis-ci.org/NagiosEnterprises/nagioscore.svg?branch=master)](https://travis-ci.org/NagiosEnterprises/nagioscore) + Nagios is a host/service/network monitoring program written in C and released under the GNU General Public License, version 2. CGI programs @@ -10,7 +15,7 @@ Visit the Nagios homepage at https://www.nagios.org for documentation, new releases, bug reports, information on discussion forums, and more. -https://www.nagios.org/about/features/[Features] +[Features](https://www.nagios.org/about/features/) ----------------------------------------------- * Monitoring of network services (via SMTP, POP3, HTTP, PING, etc). * Monitoring of host resources (processor load, disk usage, etc.). @@ -30,9 +35,9 @@ https://www.nagios.org/about/features/[Features] Changes ------- See the -https://raw.githubusercontent.com/NagiosEnterprises/nagioscore/master/Changelog[Changelog] +[Changelog](https://raw.githubusercontent.com/NagiosEnterprises/nagioscore/master/Changelog) for a summary of important changes and fixes, or the -https://github.com/NagiosEnterprises/nagioscore/commits/master[commit history] +[commit history](https://github.com/NagiosEnterprises/nagioscore/commits/master) for more detail. @@ -43,16 +48,16 @@ Latest releases can be downloaded from https://www.nagios.org/download/ Installation ------------ -http://nagios.sourceforge.net/docs/nagioscore/4/en/quickstart.html[Quickstart installation guides] +[Quickstart installation guides](http://nagios.sourceforge.net/docs/nagioscore/4/en/quickstart.html) are available to help you get Nagios up and monitoring. Documentation & Support ----------------------- -* http://nagios.sourceforge.net/docs/nagioscore/4/en/[User Guide] -* https://library.nagios.com/library/products/nagioscore/[Nagios Core Documentation Library] -* https://support.nagios.com/forum/viewforum.php?f=7[Support Forums] -* https://www.nagios.org/support/[Additional Support Resources] +* [User Guide](http://nagios.sourceforge.net/docs/nagioscore/4/en/) +* [Nagios Core Documentation Library](https://library.nagios.com/library/products/nagioscore/) +* [Support Forums](https://support.nagios.com/forum/viewforum.php?f=7) +* [Additional Support Resources](https://www.nagios.org/support/) Contributing @@ -60,13 +65,11 @@ Contributing The Nagios source code is hosted on GitHub: https://github.com/NagiosEnterprises/nagioscore -Do you have an idea or feature request to make Nagios better? Join or -start a discussion on the -https://support.nagios.com/forum/viewforum.php?f=34[Nagios Core Development forum]. -Bugs can be reported by -https://github.com/NagiosEnterprises/nagioscore/issues/new[opening an -issue on GitHub]. If you have identified a security related issue in -Nagios, please contact security@nagios.com. +Do you have an idea or feature request to make Nagios better? Join or start a +discussion on the [Nagios Core Development forum](https://support.nagios.com/forum/viewforum.php?f=34). +Bugs can be reported by [opening an issue on GitHub](https://github.com/NagiosEnterprises/nagioscore/issues/new). +If you have identified a security related issue in Nagios, please contact +security@nagios.com. Patches and GitHub pull requests are welcome. Pull requests on GitHub link commits in version control to review and discussion of the @@ -76,5 +79,5 @@ who was involved. Created by Ethan Galstad, the success of Nagios has been due to the fantastic community members that support it and provide bug reports, patches, and great ideas. See the -https://raw.githubusercontent.com/NagiosEnterprises/nagioscore/master/THANKS[THANKS file] +[THANKS file](https://raw.githubusercontent.com/NagiosEnterprises/nagioscore/master/THANKS) for some of the many who have contributed since 1999. diff --git a/THANKS b/THANKS index 3789bd9..818576c 100644 --- a/THANKS +++ b/THANKS @@ -8,6 +8,7 @@ few of the many members that have contributed to Nagios in various ways since 1999. If I missed your name, misspelled it or otherwise got it wrong, please let me know. +* Aaron Beck * Adam Bowen * Ahmon Dancy * Alain Radix @@ -53,8 +54,10 @@ wrong, please let me know. * Chris Kolquist * Chris Rothecker * Chris Witterholt +* Christian Jung * Christian Masopust * Christian Mies +* Christian Zettel * Christoph Biedl * Christoph Kron * Christoph Maser @@ -89,10 +92,12 @@ wrong, please let me know. * Evan Winter * Felipe Almeida * Florian Weimer +* Fr3dY * Fran Boon * Franky Van Liedekerke * Frederic Schaer * Frederic Van Espen +* Gareth Randall * Garry Cook * Gary Berger * Gary Miller @@ -185,9 +190,11 @@ wrong, please let me know. * Luiz Felipe R E * Luke Ross * Emmanuel Dreyfus +* Manuel Lanctot * Marc Powell * Marcus Fleige * Marcus Hildenbrand +* Mario Trangoni * Mark DeTrano * Mark Felder * Mark Frost @@ -320,6 +327,7 @@ wrong, please let me know. * Todd Wheeler * Tom Bertelson * Tom De Blende +* Tom Ryder * Tom Welsh * Tomer Okavi * Ton Voon diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100755 index 0000000..db98452 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,7 @@ +m4_include([autoconf-macros/ax_nagios_get_os]) +m4_include([autoconf-macros/ax_nagios_get_distrib]) +m4_include([autoconf-macros/ax_nagios_get_init]) +m4_include([autoconf-macros/ax_nagios_get_inetd]) +m4_include([autoconf-macros/ax_nagios_get_paths]) +m4_include([autoconf-macros/ax_nagios_get_files]) +m4_include([autoconf-macros/ax_nagios_get_ssl]) diff --git a/autoconf-macros/.gitignore b/autoconf-macros/.gitignore new file mode 100644 index 0000000..80f408e --- /dev/null +++ b/autoconf-macros/.gitignore @@ -0,0 +1 @@ +nbproject/ diff --git a/autoconf-macros/CHANGELOG.md b/autoconf-macros/CHANGELOG.md new file mode 100644 index 0000000..f71288f --- /dev/null +++ b/autoconf-macros/CHANGELOG.md @@ -0,0 +1,7 @@ +1.0.1 +----- + * Fix bug determining inetd,xinetd if neither are running (Bryan Heden) + +1.0.0 +----- + * Initial Release (John Frickson) \ No newline at end of file diff --git a/autoconf-macros/LICENSE b/autoconf-macros/LICENSE new file mode 100644 index 0000000..a983462 --- /dev/null +++ b/autoconf-macros/LICENSE @@ -0,0 +1,264 @@ +The GNU General Public License, Version 2, June 1991 (GPLv2) +============================================================ + +> Copyright (C) 1989, 1991 Free Software Foundation, Inc. +> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + + +Preamble +-------- + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to most +of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom to +distribute copies of free software (and charge for this service if you wish), +that you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs; and that you know you can +do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny +you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a +fee, you must give the recipients all the rights that you have. You must make +sure that they, too, receive or can get the source code. And you must show them +these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer +you this license which gives you legal permission to copy, distribute and/or +modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If the +software is modified by someone else and passed on, we want its recipients to +know that what they have is not the original, so that any problems introduced by +others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish +to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's free +use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + + +Terms And Conditions For Copying, Distribution And Modification +--------------------------------------------------------------- + +**0.** This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms of +this General Public License. The "Program", below, refers to any such program or +work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is included without +limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by +this License; they are outside its scope. The act of running the Program is not +restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by +running the Program). Whether that is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this License +and to the absence of any warranty; and give any other recipients of the Program +a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at +your option offer warranty protection in exchange for a fee. + +**2.** You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that you also +meet all of these conditions: + +* **a)** You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + +* **b)** You must cause any work that you distribute or publish, that in whole + or in part contains or is derived from the Program or any part thereof, to + be licensed as a whole at no charge to all third parties under the terms of + this License. + +* **c)** If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use in the + most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may redistribute + the program under these conditions, and telling the user how to view a copy + of this License. (Exception: if the Program itself is interactive but does + not normally print such an announcement, your work based on the Program is + not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, and +its terms, do not apply to those sections when you distribute them as separate +works. But when you distribute the same sections as part of a whole which is a +work based on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the entire whole, +and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise the +right to control the distribution of derivative or collective works based on the +Program. + +In addition, mere aggregation of another work not based on the Program with the +Program (or with a work based on the Program) on a volume of a storage or +distribution medium does not bring the other work under the scope of this +License. + +**3.** You may copy and distribute the Program (or a work based on it, under +Section 2) in object code or executable form under the terms of Sections 1 and 2 +above provided that you also do one of the following: + +* **a)** Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 above on + a medium customarily used for software interchange; or, + +* **b)** Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + +* **c)** Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only for + noncommercial distribution and only if you received the program in object + code or executable form with such an offer, in accord with Subsection b + above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all the +source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the source code +from the same place counts as distribution of the source code, even though third +parties are not compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program except as +expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, or +rights, from you under this License will not have their licenses terminated so +long as such parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you do +not accept this License. Therefore, by modifying or distributing the Program (or +any work based on the Program), you indicate your acceptance of this License to +do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these terms and +conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +**7.** If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), conditions +are imposed on you (whether by court order, agreement or otherwise) that +contradict the conditions of this License, they do not excuse you from the +conditions of this License. If you cannot distribute so as to satisfy +simultaneously your obligations under this License and any other pertinent +obligations, then as a consequence you may not distribute the Program at all. +For example, if a patent license would not permit royalty-free redistribution of +the Program by all those who receive copies directly or indirectly through you, +then the only way you could satisfy both it and this License would be to refrain +entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and the +section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or +other property right claims or to contest validity of any such claims; this +section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many +people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit +geographical distribution limitation excluding those countries, so that +distribution is permitted only in or among countries not thus excluded. In such +case, this License incorporates the limitation as if written in the body of this +License. + +**9.** The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose any +version ever published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software generally. + + +No Warranty +----------- + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER +OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. \ No newline at end of file diff --git a/autoconf-macros/LICENSE.md b/autoconf-macros/LICENSE.md new file mode 120000 index 0000000..7a694c9 --- /dev/null +++ b/autoconf-macros/LICENSE.md @@ -0,0 +1 @@ +LICENSE \ No newline at end of file diff --git a/autoconf-macros/README.md b/autoconf-macros/README.md new file mode 100644 index 0000000..11e5223 --- /dev/null +++ b/autoconf-macros/README.md @@ -0,0 +1,199 @@ +autoconf-macros +=============== + +The purpose of Nagios autoconf-macros is to have a central place for +autoconf macros that can be maintained in one place, but be used by any +of the Nagios software. It is intended to be used as a git subtree. +See the [Usage](#usage) and [References](#references) sections below. + +Since this project will be included in several parent projects, any +changes must be as project-neutral as possible. + +Make sure to check out the [CHANGELOG](CHANGELOG.md) for relevant +information, as well. + + +Contents +-------- + +The collection consists of the following macros: + +### AX_NAGIOS_GET_OS alias AC_NAGIOS_GET_OS + +> Output Variable : `opsys` + +This macro detects the operating system, and transforms it into a generic +label. The most common OS's that use Nagios software are recognized and +used in subsequent macros. + +### AX_NAGIOS_GET_DISTRIB_TYPE alias AC_NAGIOS_GET_DISTRIB_TYPE + +> Output Variables : `dist_type`, `dist_ver` + +This macro detects the distribution type. For Linux, this would be rh +(for Red Hat and derivatives), suse (OpenSUSE, SLES, derivatives), gentoo +(Gentoo and derivatives), debian (Debian and derivatives), and so on. +For BSD, this would be openbsd, netbsd, freebsd, dragonfly, etc. It can +also be aix, solaris, osx, and so on for Unix operating systems. + +### AX_NAGIOS_GET_INIT alias AC_NAGIOS_GET_INIT + +> Output Variable : `init_type` + +This macro detects what software is used to start daemons on bootup +or on request, generally knows as the "init system". The init_type +will generally be one of sysv (many), bsd (Slackware), newbsd (*BSD), +launchd (OS X), smf10 or smf11 (Solaris), systemd (newer Linux), +gentoo (older Gentoo), upstart (several), or unknown. + +### AX_NAGIOS_GET_INETD alias AC_NAGIOS_GET_INETD + +> Output Variable : `inetd_type` + +This macro detects what software is used to start daemons or services +on demand, which historically has been "inetd". The inetd_type +will generally be one of inetd, xinetd, launchd (OS X), smf10 or smf11 +(Solaris), systemd (newer Linux), upstart (several), or unknown. + +### AX_NAGIOS_GET_PATHS alias AC_NAGIOS_GET_PATHS + +> Output Variables : **many!** + +This macro determines the installation paths for binaries, config files, +PID files, and so on. For a "standard" install of Nagios, NRPE, NDO Utils, +etc., most will be in the /usr/local/nagios hierarchy with startup files +located in /etc. For distributions or software repositories, the +"--enable-install-method=os" option can be used. This will determine the +O/S dependent directories, such as /usr/bin, /usr/sbin, /var/lib/nagios, +/usr/lib/nagios, etc. or for OS X, /Library/LaunchDaemons. + +### AX_NAGIOS_GET_FILES alias AC_NAGIOS_GET_FILES + +> Output Variables : `src_init`, `src_inetd`, `src_tmpfile` + +Each Nagios project will have a top-level directory named "/startup/". +In that directory will be "*.in" files for the various "init_type" and +"inetd_type" systems. This macro will determine which file(s) from +that directory will be needed. + +### AX_NAGIOS_GET_SSL alias AC_NAGIOS_GET_SSL + +> Output Variables : `HAVE_KRB5_H`, `HAVE_SSL`, `SSL_INC_DIR`, `SSL_LIB_DIR`, `CFLAGS`, `LDFLAGS`, `LIBS` + +This macro checks various directories for SSL libraries and header files. +The searches are based on known install locations on various operating +systems and distributions, for openssl, gnutls-openssl, and nss_compat_ossl. +If it finds the headers and libraries, it will then do an `AC_LINK_IFELSE` +on a simple program to make sure a compile and link will work correctly. + + +Usage +----- + +This repo is intended to be used as a git subtree, so changes will +automatically propagate, and still be reasonably easy to use. + +* First, Create, checkout, clone, or branch your project. If you do an +`ls -AF` it might look something like this: + + .git/ .gitignore ChangeLog LICENSE Makefile.in + README configure.ac include/ src/ + +* Then make a reference to _this_ project inside your project. + + git remote add autoconf-macros git@github.com:NagiosEnterprises/autoconf-macros + git subtree add --prefix=macros/ autoconf-macros master + +* After executing the above two commands, if you do an `ls -AF` now, +it should look like this: + + .git/ .gitignore ChangeLog LICENSE Makefile.in + README configure.ac include/ macros/ src/ + +* The `macros/` directory has been added. + +* Now do a `git push` to save everything. + +* If you make any changes to autoconf-macros, commit them separately +from any parent-project changes to keep from polluting the commit +history with unrelated comments. + +* To submit your changes to autoconf-macros: + + git subtree push --prefix=macros autoconf-macros peters-updates +This will create a new branch called `peters-updates`. You then need to +create a _pull request_ to get your changes merged into autoconf-macros +master. + +* To get the latest version of `autoconf-macros` into your parent project: + + git subtgree pull --squash --prefix=macros autoconf-macros master + + +References +---------- + +Now that autoconf-macros is available to your project, you will need to +reference it. + +* Create (or add these lines to) file `YourProject/aclocal.m4` + + m4_include([macros/ax_nagios_get_os]) + m4_include([macros/ax_nagios_get_distrib]) + m4_include([macros/ax_nagios_get_init]) + m4_include([macros/ax_nagios_get_inetd]) + m4_include([macros/ax_nagios_get_paths]) + m4_include([macros/ax_nagios_get_files]) + m4_include([macros/ax_nagios_get_ssl]) + +* In your `YourProject/configure.ac` add the following lines. A good place +to put them would be right after any `AC_PROG_*` entries: + + AC_NAGIOS_GET_OS + AC_NAGIOS_GET_DISTRIB_TYPE + AC_NAGIOS_GET_INIT + AC_NAGIOS_GET_INETD + AC_NAGIOS_GET_PATHS + AC_NAGIOS_GET_FILES + +* If you need SSL functionality, add the following to `YourProject/configure.ac` +where you want to check for SSL: + + AC_NAGIOS_GET_SSL + +* You will now be able to reference any of the variables in `config.h.in` +and any files listed in the `AC_CONFIG_FILES` macro in `configure.ac`. + + +License Notice +-------------- + +Copyright (c) 2016-2017 Nagios Enterprises, LLC + +This work is made available to you under the terms of Version 2 of +the GNU General Public License. A copy of that license should have +been provided with this software, but in any event can be obtained +from http://www.fsf.org. + +This work 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., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 or visit their web page on the internet at +http://www.fsf.org. + + +Questions? +---------- + +If you have questions about this addon, or problems getting things +working, first try searching the nagios-users mailing list archives. +Details on searching the list archives can be found at +http://www.nagios.org + +If you don't find an answer there, post a message in the Nagios +Plugin Development forum at https://support.nagios.com/forum/viewforum.php?f=35 diff --git a/autoconf-macros/add_group_user b/autoconf-macros/add_group_user new file mode 100755 index 0000000..cf18ae9 --- /dev/null +++ b/autoconf-macros/add_group_user @@ -0,0 +1,164 @@ +#!/bin/sh + +#---------------------- +# Initialize variables +#---------------------- +dist="$1" +uid="$2" +gid="$3" +rc=0 + +#------------------------------------------------------------------ +# Determine if the user should be created with a shell environment +# 0 = no shell (more secure) +# 1 = shell (less secure but sometimes required) +#------------------------------------------------------------------ +shell=0 +if [ $# -eq 4 ]; then + if [ x$4 = x1 ]; then + shell=1 + fi +fi + +#------------------------------------- +# Check if the specified group exists +#------------------------------------- +group_exists(){ + case $dist in + osx) rc=`dscl . -read /Groups/$gid >/dev/null 2>&1; echo $?` ;; + hpux) rc=`grget -n $gid >/dev/null 2>&1; echo $?` ;; + aix) rc=`lsgroup -a $gid >/dev/null 2>&1; echo $?` ;; + *) rc=`getent group $gid > /dev/null 2>&1; echo $?` ;; + esac + + echo $rc +} + +#------------------------ +# Add the specified user +#------------------------ +add_user(){ + rc=`id "$uid" > /dev/null 2>&1; echo $?` + if test $rc -eq 0; then + echo "User $uid already exists" > /dev/stderr + echo 0 + return + fi + + case $dist in + aix) + echo useradd -g $gid $uid > /dev/stderr + rc=`useradd -g $gid $uid; echo $?` + ;; + + hpux) + echo useradd -m -g $gid $uid > /dev/stderr + rc=`useradd -m -g $gid $uid; echo $?` + ;; + + solaris) + echo useradd -m -d /export/home/$uid -g $gid $uid > /dev/stderr + rc=`useradd -m -d /export/home/$uid -g $gid $uid; echo $?` + ;; + + osx) + newid=`dscl . -list /Users UniqueID | tr -s ' ' | cut -d' ' -f2 | sort -n | tail -1` + newid=`expr 1 + $newid` + echo dscl . -create /Users/$uid > /dev/stderr + dscl . -create /Users/$uid + echo dscl . -create /Users/$uid UniqueID $newid > /dev/stderr + dscl . -create /Users/$uid UniqueID $newid + if [ $shell = 0 ]; then + echo dscl . -create /Users/$uid UserShell /usr/bin/false > /dev/stderr + dscl . -create /Users/$uid UserShell /usr/bin/false + fi + echo dscl . -create /Users/$uid PrimaryGroupID 20 > /dev/stderr + dscl . -create /Users/$uid PrimaryGroupID 20 + echo dscl . -append /Groups/$gid GroupMembership $uid > /dev/stderr + rc=`dscl . -append /Groups/$gid GroupMembership $uid; echo $?` + ;; + + freebsd) + if [ $shell = 0 ]; then + echo pw add user $uid -g $gid -s /usr/bin/false > /dev/stderr + rc=`pw add user $uid -g $gid -s /usr/bin/false; echo $?` + else + echo pw add user $uid -g $gid > /dev/stderr + rc=`pw add user $uid -g $gid; echo $?` + fi + ;; + + netbsd|openbsd) + echo useradd -g $gid $uid > /dev/stderr + rc=`useradd -g $gid $uid; echo $?` + ;; + + *) + if [ $shell = 0 ]; then + echo useradd -r -g $gid $uid > /dev/stderr + rc=`useradd -r -g $gid $uid; echo $?` + else + echo useradd -g $gid $uid > /dev/stderr + rc=`useradd -g $gid $uid; echo $?` + fi + ;; + esac + + echo $rc +} + +#------------------------- +# Add the specified group +#------------------------- +add_group(){ + rc=`group_exists` + if test $rc -eq 0; then + echo "Group $gid already exists" > /dev/stderr + echo 0 + return + fi + + case $dist in + aix) + echo mkgroup $gid > /dev/stderr + rc=`mkgroup "$gid"; echo $?` + ;; + + hpux|solaris) + echo groupadd $gid > /dev/stderr + rc=`groupadd "$gid"; echo $?` + ;; + + osx) + newid=`dscl . -list /Groups gid | tr -s ' ' | cut -d' ' -f2 | sort -n | tail -1` + newid=`expr 1 + $newid` + echo dscl . -create /Groups/$gid gid $newid > /dev/stderr + rc=`dscl . -create /Groups/$gid gid $newid; echo $?` + ;; + + freebsd) + echo pw add group $gid > /dev/stderr + rc=`pw add group $gid; echo $?` + ;; + + netbsd|openbsd) + echo groupadd $gid > /dev/stderr + rc=`groupadd $gid; echo $?` + ;; + + *) + echo groupadd -r $gid > /dev/stderr + rc=`groupadd -r $gid; echo $?` + ;; + esac + + echo $rc +} + + +rc=`add_group` +if test $rc -ne 0; then + exit 1; +fi +rc=`add_user` +exit $rc diff --git a/autoconf-macros/ax_nagios_get_distrib b/autoconf-macros/ax_nagios_get_distrib new file mode 100644 index 0000000..3bb26b0 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_distrib @@ -0,0 +1,160 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_DISTRIB_TYPE +# +# DESCRIPTION +# +# This macro determines the O/S distribution of the computer it is run on. +# $dist_type will be set and will be one of: +# unknown (could not be determined) +# freebsd, netbsd, openbsd, dragonfly, etc (The BSDs) +# suse, rh, debian, gentoo (and possibly their descendants) +# Other major Linux distributions (and possibly their descendants) +# The O/S name for the rest +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_DISTRIB_TYPE], [AX_NAGIOS_GET_DISTRIB_TYPE]) +AC_DEFUN([AX_NAGIOS_GET_DISTRIB_TYPE], +[ + +AC_SUBST(dist_type) +AC_SUBST(dist_ver) + +# +# Get user hints for possible cross-compile +# + AC_MSG_CHECKING(what the distribution type is ) + AC_ARG_WITH(dist-type, AC_HELP_STRING([--with-dist-type=type], + [specify distribution type (suse, rh, debian, etc.)]), + [ + # + # Run this if --with was specified + # + if test "x$withval" = x -o x$withval = xno; then + dist_type_wanted=yes + else + dist_type_wanted=no + dist_type="$withval" + dist_ver="unknown" + AC_MSG_RESULT($dist_type) + fi + ], [ + # + # Run this if --with was not specified + # + dist_type_wanted=yes + ]) + + if test x$dist_type = xno; then + dist_type_wanted=yes + elif test x$dist_type = xyes; then + AC_MSG_ERROR([you must enter a distribution type if '--with-dist-type' is specified]) + fi + + # + # Determine distribution type if it wasn't supplied + # + dist_ver="unknown" + + if test $dist_type_wanted=yes; then + dist_type="unknown" + + if test "$opsys" != "linux"; then + dist_type="$opsys" + AS_CASE([$opsys], + [bsd], + dist_type=`uname -s | tr ["[A-Z]" "[a-z]"]` + dist_ver=`uname -r`, + [aix], + dist_ver="`uname -v`.`uname -r`", + [hp-ux], + dist_ver=`uname -r | cut -d'.' -f1-3`, + [solaris], + dist_ver=`uname -r | cut -d'.' -f2`, + [*], + dist_ver=$OSTYPE + ) + + else + + if test -r "/etc/gentoo-release"; then + dist_type="gentoo" + dist_ver=`cat /etc/gentoo-release` + + elif test -r "/etc/os-release"; then + . /etc/os-release + if test x"$ID_LIKE" != x; then + dist_type=`echo $ID_LIKE | cut -d' ' -f1 | tr ["[A-Z]" "[a-z]"]` + elif test x"$ID" = xol; then + dist_type=rh + else + dist_type=`echo $ID | tr ["[A-Z]" "[a-z]"]` + fi + if test x"$dist_type" = sles; then + dist_type=suse + fi + if test x"$VERSION_ID" != x; then + dist_ver=$VERSION_ID + elif test x"$VERSION" != x; then + dist_ver=`echo $VERSION | cut -d'.' -f1 | tr -d [:alpha:][:blank:][:punct:]` + fi + + elif test -r "/etc/redhat-release"; then + dist_type=rh + dist_ver=`cat /etc/redhat-release` + + elif test -r "/etc/debian_version"; then + dist_type="debian" + if test -r "/etc/lsb-release"; then + . /etc/lsb-release + dist_ver=`echo "$DISTRIB_RELEASE"` + else + dist_ver=`cat /etc/debian_version` + fi + + elif test -r "/etc/SuSE-release"; then + dist_type=suse + dist_ver=`grep VERSION /etc/SuSE-release` + + fi + + fi + + if test "$dist_ver" != "unknown"; then + dist_ver=`echo "$dist_ver" | cut -d'.' -f1 | tr -d [:alpha:][:blank:][:punct:]` + fi + fi + + AC_MSG_RESULT($dist_type) +]) diff --git a/autoconf-macros/ax_nagios_get_files b/autoconf-macros/ax_nagios_get_files new file mode 100644 index 0000000..e2e4a0e --- /dev/null +++ b/autoconf-macros/ax_nagios_get_files @@ -0,0 +1,131 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_FILES +# +# DESCRIPTION +# +# This macro figures out which init and/or inetd files to use based +# on the results of the AX_NAGIOS_GET_OS, AX_NAGIOS_GET_DISTRIB_TYPE, +# AX_NAGIOS_GET_INIT and AX_NAGIOS_GET_INETD macros. It will select +# the appropriate files(s) from the 'startup' directory and copy it. +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_FILES], [AX_NAGIOS_GET_FILES]) +AC_DEFUN([AX_NAGIOS_GET_FILES], +[ + +AC_SUBST(src_init) +AC_SUBST(src_inetd) +AC_SUBST(src_tmpfile) +AC_SUBST(bsd_enable) + +src_inetd="" +src_init="" +bsd_enable="" + +AC_MSG_CHECKING(for which init file to use ) + +AS_CASE([$init_type], + + [sysv], + src_init=default-init, + + [systemd], + src_tmpfile=tmpfile.conf + src_init=default-service, + + [bsd], + src_init=bsd-init, + + [newbsd], + if test $dist_type = freebsd ; then + bsd_enable="_enable" + src_init=default-init + elif test $dist_type = openbsd ; then + bsd_enable="_flags" + src_init=openbsd-init + elif test $dist_type = netbsd ; then + bsd_enable="" + src_init=newbsd-init + fi, + +# [gentoo], + + [openrc], + src_init=openrc-init, + + [smf*], + src_init="solaris-init.xml" + src_inetd="solaris-inetd.xml", + + [upstart], + if test $dist_type = rh ; then + src_init=rh-upstart-init + else + src_init=upstart-init + fi, + + [launchd], + src_init="mac-init.plist", + + [*], + src_init="unknown" +) +AC_MSG_RESULT($src_init) + +AC_MSG_CHECKING(for which inetd files to use ) + +if test x$src_inetd = x; then + + AS_CASE([$inetd_type], + [inetd*], + src_inetd=default-inetd, + + [xinetd], + src_inetd=default-xinetd, + + [systemd], + src_inetd=default-socket, + + [launchd], + src_inetd="mac-inetd.plist", + + [*], + src_inetd="unknown" + ) + +fi +AC_MSG_RESULT($src_inetd) + +]) diff --git a/autoconf-macros/ax_nagios_get_inetd b/autoconf-macros/ax_nagios_get_inetd new file mode 100644 index 0000000..7c75372 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_inetd @@ -0,0 +1,146 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_INETD +# +# DESCRIPTION +# +# This macro determines whether inetd or xinetd is being used +# The argument are: +# the init type as determined by AX_NAGIOS_GET_INIT +# $inetd_type will be set and will be one of: +# unknown (could not be determined) +# launchd (Mac OS X) +# smf10 (Solaris) +# smf11 (Solaris) +# upstart (Older Debian) +# xinetd (Most Linux, BSD) +# inetd (The rest) +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_INETD], [AX_NAGIOS_GET_INETD]) +AC_DEFUN([AX_NAGIOS_GET_INETD], +[ + +AC_SUBST(inetd_type) + +# +# Get user hints for possible cross-compile +# + AC_MSG_CHECKING(what inetd is being used ) + AC_ARG_WITH(inetd_type, AC_HELP_STRING([--with-inetd-type=type], + [which super-server the system runs (inetd, xinetd, systemd, launchd, + smf10, smf11, etc.)]), + [ + inetd_type_wanted=yes + # + # Run this if --with was specified + # + if test "x$withval" = x -o x$withval = xno; then + inetd_type_wanted=yes + else + inetd_type_wanted=no + inetd_type="$withval" + AC_MSG_RESULT($inetd_type) + fi + ], [ + # + # Run this if --with was not specified + # + inetd_type_wanted=yes + ]) + + if test x$inetd_type = xno; then + inetd_type_wanted=yes + elif test x$inetd_type = xyes; then + AC_MSG_ERROR([you must enter an inetd type if '--with-inetd-type' is specified]) + fi + + # + # Determine inetd type if it wasn't supplied + # + if test $inetd_type_wanted = yes; then + + inetd_disabled="" + + AS_CASE([$dist_type], + [solaris], + if test x"$init_type" = "xsmf10" -o x"$init_type" = "xsmf11"; then + inetd_type="$init_type" + else + inetd_type="inetd" + fi, + + [*bsd*], + inetd_type=`ps -A -o comm -c | grep inetd`, + + [osx], + inetd_type=`launchd`, + + [aix|hp-ux], + inetd_type=`UNIX95= ps -A -o comm | grep inetd | head -1`, + + [*], + inetd_type=[`ps -C "inetd,xinetd" -o fname | grep -vi COMMAND | head -1`]) + + if test x"$inetd_type" = x; then + if test -f /etc/xinetd.conf -a -d /etc/xinetd.d; then + inetd_disabled="(Not running)" + inetd_type=xinetd + elif test -f /etc/inetd.conf -o -f /usr/sbin/inetd; then + inetd_type=inetd + inetd_disabled="(Not running)" + fi + fi + + if test x"$inetd_type" = x; then + if test x"$init_type" = "xupstart"; then + inetd_type="upstart" + fi + fi + + if test x"$inetd_type" = x; then + if test x"$init_type" = "xsystemd"; then + inetd_type="systemd" + else + inetd_type="unknown" + fi + fi + + if test -n "$inetd_disabled"; then + AC_MSG_RESULT($inetd_type $inetd_disabled) + else + AC_MSG_RESULT($inetd_type) + fi + fi +]) diff --git a/autoconf-macros/ax_nagios_get_init b/autoconf-macros/ax_nagios_get_init new file mode 100644 index 0000000..5ef27f4 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_init @@ -0,0 +1,200 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_INIT +# +# DESCRIPTION +# +# This macro determines the O/S distribution of the computer it is run on. +# $init_type will be set and will be one of: +# unknown (could not be determined) +# launchd (Mac OS X) +# bsd (Slackware Linux) +# newbsd (FreeBSD, OpenBSD, NetBSD, Dragonfly, etc) +# smf10 (Solaris) +# smf11 (Solaris) +# systemd (Linux SystemD) +# gentoo (Older Gentoo) +# openrc (Recent Gentoo and some others) +# upstart (Older Debian) +# sysv (The rest) +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_INIT], [AX_NAGIOS_GET_INIT]) +AC_DEFUN([AX_NAGIOS_GET_INIT], +[ + +AC_SUBST(init_type) + +# +# Get user hints for possible cross-compile +# + AC_MSG_CHECKING(what init system is being used ) + AC_ARG_WITH(init_type,AC_HELP_STRING([--with-init-type=type], + [specify init type (bsd, sysv, systemd, launchd, smf10, smf11, upstart, + openrc, etc.)]), + [ + # + # Run this if --with was specified + # + if test "x$withval" = x -o x$withval = xno; then + init_type_wanted=yes + else + init_type_wanted=no + init_type="$withval" + AC_MSG_RESULT($init_type) + fi + ], [ + # + # Run this if --with was not specified + # + init_type_wanted=yes + ]) + + if test x$init_type = xno; then + init_type_wanted=yes + elif test x$init_type = xyes; then + AC_MSG_ERROR([you must enter an init type if '--with-init-type' is specified]) + fi + + # + # Determine init type if it wasn't supplied + # + if test $init_type_wanted = yes; then + init_type="" + + if test x"$opsys" = x; then + init_type="unknown" + init_type_wanted=no + elif test x"$dist_type" = x; then + init_type="unknown" + init_type_wanted=no + elif test "$opsys" = "osx"; then + init_type="launchd" + init_type_wanted=no + elif test "$opsys" = "bsd"; then + init_type="newbsd" + init_type_wanted=no + elif test "$dist_type" = "solaris"; then + if test -d "/lib/svc/manifest"; then + init_type="smf11" + init_type_wanted=no + elif test -d "/lib/svc/monitor"; then + init_type="smf10" + init_type_wanted=no + else + init_type="sysv" + init_type_wanted=no + fi + elif test "$dist_type" = "slackware"; then + init_type="bsd" + init_type_wanted=no + elif test "$dist_type" = "aix"; then + init_type="bsd" + init_type_wanted=no + elif test "$dist_type" = "hp-ux"; then + init_type="unknown" + init_type_wanted=no + fi + fi + + PSCMD="ps -p1 -o args" + if test $dist_type = solaris; then + PSCMD="env UNIX95=1; ps -p1 -o args" + fi + + if test "$init_type_wanted" = yes; then + pid1=`$PSCMD | grep -vi COMMAND | cut -d' ' -f1` + if test x"$pid1" = "x"; then + init_type="unknown" + init_type_wanted=no + fi + if `echo $pid1 | grep "systemd" > /dev/null`; then + init_type="systemd" + init_type_wanted=no + fi + + if test "$init_type_wanted" = yes; then + if test "$pid1" = "init"; then + if test -e "/sbin/init"; then + pid1="/sbin/init"; + elif test -e "/usr/sbin/init"; then + pid1="/usr/sbin/init" + else + init_type="unknown" + init_type_wanted=no + fi + fi + if test -L "$pid1"; then + pid1=`readlink "$pid1"` + fi + fi + + if test "$init_type_wanted" = yes; then + if `echo $pid1 | grep "systemd" > /dev/null`; then + init_type="systemd" + init_type_wanted=no + elif test -f "/sbin/rc"; then + if test -f /sbin/runscript; then + init_type_wanted=no + if `/sbin/start-stop-daemon -V | grep "OpenRC" > /dev/null`; then + init_type="openrc" + else + init_type="gentoo" + fi + fi + fi + fi + + if test "$init_type_wanted" = yes; then + if test "$pid1" = "/sbin/init" -o "$pid1" = "/usr/sbin/init"; then + if `$pid1 --version 2>/dev/null | grep "upstart" >/dev/null`; then + init_type="upstart" + init_type_wanted=no + elif test -f "/etc/rc" -a ! -L "/etc/rc"; then + init_type="newbsd" + init_type_wanted=no + else + init_type="sysv" + init_type_wanted=no + fi + fi + fi + + if test "$init_type_wanted" = yes; then + init_type="unknown" + fi + fi + + AC_MSG_RESULT($init_type) +]) diff --git a/autoconf-macros/ax_nagios_get_os b/autoconf-macros/ax_nagios_get_os new file mode 100644 index 0000000..5683158 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_os @@ -0,0 +1,101 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_OS +# +# DESCRIPTION +# +# This macro determines the operating system of the computer it is run on. +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_OS], [AX_NAGIOS_GET_OS]) +AC_DEFUN([AX_NAGIOS_GET_OS], +[ + +AC_SUBST(opsys) +AC_SUBST(arch) + +# +# Get user hints +# + AC_MSG_CHECKING(what the operating system is ) + AC_ARG_WITH(opsys, AC_HELP_STRING([--with-opsys=OS], + [specify operating system (linux, osx, bsd, solaris, irix, cygwin, + aix, hp-ux, etc.)]), + [ + # + # Run this if --with was specified + # + if test "x$withval" = x -o x$withval = xno; then + opsys_wanted=yes + else + opsys_wanted=no + opsys="$withval" + AC_MSG_RESULT($opsys) + fi + ], [ + # + # Run this if --with was not specified + # + opsys_wanted=yes + ]) + + if test x$opsys = xno; then + opsys="" + opsys_wanted=yes + elif test x$opsys = xyes; then + AC_MSG_ERROR([you must enter an O/S type if '--with-opsys' is specified]) + fi + + # + # Determine operating system if it wasn't supplied + # + if test $opsys_wanted=yes; then + opsys=`uname -s | tr ["[A-Z]" "[a-z]"]` + if test x"$opsys" = "x"; then opsys="unknown"; fi + AS_CASE([$opsys], + [darwin*], opsys="osx", + [*bsd*], opsys="bsd", + [dragonfly], opsys="bsd", + [sunos], opsys="solaris", + [gnu/hurd], opsys="linux", + [irix*], opsys="irix", + [cygwin*], opsys="cygwin", + [mingw*], opsys="mingw", + [msys*], opsys="msys") + fi + + arch=`uname -m | tr ["[A-Z]" "[a-z]"]` + + AC_MSG_RESULT($opsys) +]) diff --git a/autoconf-macros/ax_nagios_get_paths b/autoconf-macros/ax_nagios_get_paths new file mode 100644 index 0000000..bd25812 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_paths @@ -0,0 +1,783 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_PATHS +# +# DESCRIPTION +# +# This macro figures out the installation & run paths for various systems +# The argument are: +# the O/S determined by the AX_NAGIOS_GET_OS macro. +# the distribution type as determined by AX_NAGIOS_GET_DISTRIB_TYPE +# the init type as determined by AX_NAGIOS_GET_INIT +# the inetd type as determined by AX_NAGIOS_GET_INETD +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_PATHS], [AX_NAGIOS_GET_PATHS]) +AC_DEFUN([AX_NAGIOS_GET_PATHS], +[ + +AC_SUBST(pkgsysconfdir) +AC_SUBST(objsysconfdir) +AC_SUBST(initname) +AC_SUBST(inetdname) +AC_SUBST(pluginsdir) +AC_SUBST(brokersdir) +AC_SUBST(cgibindir) +AC_SUBST(webdir) +AC_SUBST(privatesysconfdir) +AC_SUBST(pkglocalstatedir) +AC_SUBST(logdir) +AC_SUBST(piddir) +AC_SUBST(pipedir) +AC_SUBST(spooldir) +AC_SUBST(initdir) +AC_SUBST(initdiroverridden) +AC_SUBST(inetddir) +AC_SUBST(tmpfilesd) +AC_SUBST(subsyslockdir) +AC_SUBST(subsyslockfile) + +if test x$DBG_PATHS != x; then + echo + echo Incoming paths: + echo " prefix $prefix" + echo " exec_prefix $exec_prefix" + echo " bindir $bindir" + echo " libexecdir $libexecdir" + echo " sysconfdir $sysconfdir" + echo " localstatedir $localstatedir" + echo " datarootdir $datarootdir" + echo " datadir $datadir" + echo " localedir $localedir" + echo +fi + +AC_MSG_CHECKING(for which paths to use ) + +AC_ARG_ENABLE(install_method, + AC_HELP_STRING([--enable-install-method=], + [sets the install method to use: 'default' (the default) will install to + /usr/local/nagios, 'os' will try to determine which method to use based + on OS type and distribution. Fine tuning using the '--bindir', etc. + overrides above will still work]), + install_method=$enableval, + install_method=default +) + +AC_ARG_ENABLE(showdirs_only, + AC_HELP_STRING([--enable-showdirs-only=yes], + [This option will cause 'configure' to stop after determining the install + locations based on '--enable-install-method', so you can see the + destinations before a full './configure', 'make', 'make install' + process.]), + showdirs_only=$enableval, + showdirs_only=no +) + +AS_CASE([$install_method], + [yes], install_method="os", + [no], install_method="default", + [default|os], :, + [*], echo >&6; AC_MSG_ERROR(['--enable-install-method=$install_method' is invalid]) +) + +if test $showdirs_only != "no"; then showdirs_only="yes"; fi + +AS_CASE([$dist_type], + [*solaris*|*hp-ux*|*aix*|*osx*], opsys=unix) + + + # Does this package need to know: +need_cgi=no # where the cgi-bin directory is +need_web=no # where the website directory is +need_brk=no # where the event broker modules directory is +need_plg=no # where the plugins directory is +need_pipe=no # where the pipe directory is +need_spl=no # where the spool directory is +need_loc=no # where the locale directory is +need_log_subdir=no # where the loc sub-directory is +need_etc_subdir=no # where the etc sub-directory is +need_pls_dir=no # where the package locate state directory is + +if test x"$INIT_PROG" = x; then + INIT_PROG="$PKG_NAME" +fi + +AS_CASE([$PKG_NAME], + [nagios], + need_log_subdir=yes + need_etc_subdir=yes + need_pls_dir=yes + need_brk=yes + need_pipe=yes + need_spl=yes + need_loc=yes + need_cgi=yes + need_web=yes, + + [ndoutils], + need_brk=yes + need_spl=yes, + + [nrpe], + need_plg=yes, + + [nsca], + need_cgi=no, + + [plugins], + need_loc=yes + need_plg=yes +) + +AC_ARG_WITH(pkgsysconfdir, AC_HELP_STRING([--with-pkgsysconfdir=DIR], + [where configuration files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + pkgsysconfdir="$withval" + fi) +AC_ARG_WITH(objsysconfdir, AC_HELP_STRING([--with-objsysconfdir=DIR], + [where object configuration files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + objsysconfdir="$withval" + fi) +AC_ARG_WITH(privatesysconfdir, AC_HELP_STRING([--with-privatesysconfdir=DIR], + [where private configuration files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + privatesysconfdir="$withval" + fi) +AC_ARG_WITH(webdir, AC_HELP_STRING([--with-webdir=DIR], + [where the website files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + webdir="$withval" + fi) +AC_ARG_WITH(pluginsdir, AC_HELP_STRING([--with-pluginsdir=DIR], + [where the plugins should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + pluginsdir="$withval" + fi) +AC_ARG_WITH(brokersdir, AC_HELP_STRING([--with-brokersdir=DIR], + [where the broker modules should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + brokersdir="$withval" + fi) +AC_ARG_WITH(cgibindir, AC_HELP_STRING([--with-cgibindir=DIR], + [where the CGI programs should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + cgibindir="$withval" + fi) +AC_ARG_WITH(logdir, AC_HELP_STRING([--with-logdir=DIR], + [where log files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + logdir="$withval" + fi) +AC_ARG_WITH(piddir, AC_HELP_STRING([--with-piddir=DIR], + [where the PID file should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + piddir="$withval" + fi) +AC_ARG_WITH(pipedir, AC_HELP_STRING([--with-pipedir=DIR], + [where socket and pipe files should be placed]), + if test x$withval != x -a x$withval != xno -a x$withval != xyes; then + pipedir="$withval" + fi) + + +# +# Setup the base directory +# + +if test $install_method = "default"; then + if test $opsys = "unix"; then + if test x"$prefix" = "xNONE"; then prefix="/usr/local/nagios"; fi + else + if test x"$prefix" = "xNONE"; then prefix=${ac_default_prefix}; fi + fi + datarootdir=${datarootdir="$prefix"} + +else + if test x"$datadir" = x'${datarootdir}'; then AS_UNSET(datadir); fi + if test x"$sysconfdir" = x'${prefix}/etc'; then AS_UNSET(sysconfdir); fi + + if test x"$prefix" = "xNONE"; then + if test $dist_type = freebsd -o $dist_type = openbsd -o $dist_type = osx; then + prefix="/usr/local" + elif test $dist_type = netbsd; then + prefix="/usr/pkg" + else + prefix="/usr" + fi + fi + if test x"$exec_prefix" = "xNONE"; then exec_prefix=$prefix; fi + if test x"$localstatedir" = x'${prefix}/var'; then + if test $dist_type = "osx"; then + localstatedir="/private/var" + else + localstatedir="/var" + fi + fi + + if test $opsys = "unix"; then + if test x"$datarootdir" = x'${prefix}/share'; then + if test $dist_type = "hp-ux"; then + datarootdir="/usr/local/share" + if test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir="/usr/nagios" + fi + elif test $dist_type = "osx"; then + datarootdir="/usr/local/share" + if test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir="/usr/local/nagios" + fi + elif test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir="/usr/lib/nagios" + fi + fi + if test $dist_type = "osx"; then + if test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir="/usr/local/libexec/nagios" + fi + fi + elif test $opsys = "bsd"; then + if test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir=${exec_prefix}/libexec/nagios; + fi + elif test x"$libexecdir" = x'${exec_prefix}/lib'; then + libexecdir=${libexecdir}/nagios; + elif test x"$libexecdir" = x'${exec_prefix}/libexec'; then + libexecdir=${exec_prefix}/lib/nagios; + fi + +fi + +if test x"$exec_prefix" = "xNONE"; then exec_prefix=${prefix}; fi + +tmpfilesd=${tmpfilesd="/usr/lib/tmpfiles.d"} +if test ! -d "$tmpfilesd"; then + tmpfilesd="N/A" +else + tmpfilesd="$tmpfilesd/$INIT_PROG.conf" +fi +subsyslockdir=${subsyslockdir="/run"} +if test ! -d "$subsyslockdir"; then + subsyslockdir="N/A" + subsyslockfile="N/A" +else + subsyslockfile="$subsyslockdir/$INIT_PROG.lock" +fi +if test "$need_loc" = no; then + localedir="N/A" +fi + +if test $install_method = "default" ; then + # + # Do the default setup + # + datadir=${datadir="$datarootdir"} + if test $need_web = yes; then + webdir=${webdir="$datadir"} + else + webdir="N/A" + fi + if test $opsys = "unix"; then + sysconfdir=${sysconfdir="/etc/opt"} + fi + pkgsysconfdir=${pkgsysconfdir="$sysconfdir"} + if test $need_etc_subdir = yes; then + objsysconfdir=${objsysconfdir="$pkgsysconfdir/objects"} + else + objsysconfdir="N/A" + fi + privatesysconfdir=${privatesysconfdir="$pkgsysconfdir"} + logdir=${logdir="$localstatedir"} + piddir=${piddir="$localstatedir"} + if test "$need_pipe" = yes; then + pipedir=${pipedir="$localstatedir/rw"} + else + pipedir="N/A" + fi + if test "$need_pls_dir" = yes; then + pkglocalstatedir=${pkglocalstatedir="$localstatedir"} + else + pkglocalstatedir="N/A" + fi + if test "$need_spl" = yes; then + spooldir=${spooldir="$localstatedir/var"} + else + spooldir="N/A" + fi + if test $need_brk = yes; then + brokersdir=${brokersdir="$bindir"} + else + brokersdir="N/A" + fi + if test $need_plg = yes; then + pluginsdir=${pluginsdir="$libexecdir"} + else + pluginsdir="N/A" + fi + if test $need_cgi = yes; then + cgibindir=${cgibindir="$prefix/sbin"} + else + cgibindir="N/A" + fi + +elif test $opsys = "linux"; then + + # + # Linux "Standard" install + # + install_method="$install_method : FHS" + datadir=${datadir="$datarootdir/nagios"} + if test $need_web = yes; then + webdir=${webdir="$datadir/html"} + else + webdir="N/A" + fi + sysconfdir=${sysconfdir="/etc"} + pkgsysconfdir=${pkgsysconfdir="$sysconfdir/nagios"} + if test $need_etc_subdir = yes; then + objsysconfdir=${objsysconfdir="$pkgsysconfdir/objects"} + else + objsysconfdir="N/A" + fi + privatesysconfdir=${privatesysconfdir="$pkgsysconfdir/private"} + if test $need_log_subdir = yes; then + logdir=${logdir="$localstatedir/log/$INIT_PROG"} + else + logdir=${logdir="$localstatedir/log"} + fi + piddir=${piddir="$localstatedir/run/${INIT_PROG}"} + if test "$need_pipe" = yes; then + pipedir=${pipedir="$localstatedir/run/${INIT_PROG}"} + else + pipedir="N/A" + fi + if test "$need_pls_dir" = yes; then + pkglocalstatedir=${pkglocalstatedir="$localstatedir/lib/$INIT_PROG"} + else + pkglocalstatedir="N/A" + fi + if test "$need_spl" = yes; then + spooldir=${spooldir="$localstatedir/spool/$INIT_PROG"} + else + spooldir="N/A" + fi + if test $need_brk = yes; then + brokersdir=${brokersdir="$libexecdir/brokers"} + else + brokersdir="N/A" + fi + if test $need_plg = yes; then + pluginsdir=${pluginsdir="$libexecdir/plugins"} + else + pluginsdir="N/A" + fi + if test $need_cgi = yes; then + cgibindir=${cgibindir="$libexecdir/cgi-bin"} + else + cgibindir="N/A" + fi + +elif test $opsys = "unix"; then + + # + # "Standard" Unix install + # + install_method="$install_method : Unix Standard" + if test $dist_type = osx; then + install_method="$install_method : OS X Standard" + fi + datadir=${datadir="$datarootdir/nagios"} + if test $need_web = yes; then + webdir=${webdir="$datadir/html"} + else + webdir="N/A" + fi + if test $dist_type = osx; then + sysconfdir=${sysconfdir="/private/etc"} + else + sysconfdir=${sysconfdir="/etc"} + fi + pkgsysconfdir=${pkgsysconfdir="$sysconfdir/nagios"} + if test $need_etc_subdir = yes; then + objsysconfdir=${objsysconfdir="$pkgsysconfdir/objects"} + else + objsysconfdir="N/A" + fi + privatesysconfdir=${privatesysconfdir="$pkgsysconfdir/private"} + if test "$need_pls_dir" = yes; then + pkglocalstatedir=${pkglocalstatedir="$localstatedir/lib/$INIT_PROG"} + else + pkglocalstatedir="N/A" + fi + if test "$need_loc" = yes; then + localedir=${localedir="/usr/local/share/locale//LC_MESSAGES/nagios-plugins.mo"} + fi + if test "$need_spl" = yes; then + spooldir=${spooldir="$localstatedir/spool/$INIT_PROG"} + else + spooldir="N/A" + fi + if test $need_brk = yes; then + brokersdir=${brokersdir="$libexecdir/brokers"} + else + brokersdir="N/A" + fi + if test $need_plg = yes; then + pluginsdir=${pluginsdir="$libexecdir/plugins"} + else + pluginsdir="N/A" + fi + if test $need_cgi = yes; then + cgibindir=${cgibindir="$libexecdir/cgi-bin"} + else + cgibindir="N/A" + fi + AS_CASE([$dist_type], + [*hp-ux*], + piddir=${piddir="$pkgsysconfdir"} + pipedir=${pipedir="$pkglocalstatedir"} + logdir=${logdir="$pkglocalstatedir/log"}, + + [*], + piddir=${piddir="$localstatedir/run/${INIT_PROG}"} + if test "$need_pipe" = yes; then + pipedir=${pipedir="$localstatedir/run/${INIT_PROG}"} + else + pipedir="N/A" + fi + if test $need_log_subdir = yes; then + logdir=${logdir="$localstatedir/log/$INIT_PROG"} + else + logdir=${logdir="$localstatedir/log"} + fi + ) + +elif test $opsys = "bsd"; then + + # + # "Standard" BSD install + # + install_method="$install_method : BSD" + if test $dist_type = freebsd -o $dist_type = openbsd; then + prefix=${prefix="/usr/local"} + exec_prefix=${exec_prefix="/usr/local"} + if test $dist_type = freebsd; then + install_method="$install_method : FreeBSD" + else + install_method="$install_method : OpenBSD" + fi + elif test $dist_type = netbsd; then + prefix=${prefix="/usr/pkg"} + exec_prefix=${exec_prefix="/usr/pkg"} + install_method="$install_method : NetBSD" + fi + datadir=${datadir="$datarootdir/nagios"} + if test $need_web = yes -o $need_cgi = yes; then + if test $dist_type = freebsd; then + webdir=${webdir="$prefix/www/nagios"} + elif test $dist_type = netbsd; then + webdir=${webdir="$prefix/share/nagios"} + elif test $dist_type = openbsd; then + webdir=${webdir="/var/www/nagios"} + fi + else + webdir="N/A" + fi + if test $dist_type = freebsd; then + sysconfdir=${sysconfdir="/usr/local/etc"} + else + sysconfdir=${sysconfdir="/etc"} + fi + pkgsysconfdir=${pkgsysconfdir="$sysconfdir/nagios"} + if test $need_etc_subdir = yes; then + objsysconfdir=${objsysconfdir="$pkgsysconfdir/objects"} + else + objsysconfdir="N/A" + fi + privatesysconfdir=${privatesysconfdir="$pkgsysconfdir/private"} + if test "$need_pls_dir" = yes; then + pkglocalstatedir=${pkglocalstatedir="$localstatedir/lib/$INIT_PROG"} + else + pkglocalstatedir="N/A" + fi + if test "$need_loc" = yes; then + localedir=${localedir="/usr/local/share/locale//LC_MESSAGES/nagios-plugins.mo"} + fi + if test "$need_spl" = yes; then + spooldir=${spooldir="$localstatedir/spool/$INIT_PROG"} + else + spooldir="N/A" + fi + if test $need_brk = yes; then + brokersdir=${brokersdir="$libexecdir/brokers"} + else + brokersdir="N/A" + fi + if test $need_plg = yes; then + pluginsdir=${pluginsdir="$libexecdir/plugins"} + else + pluginsdir="N/A" + fi + if test $need_cgi = yes; then + if test $dist_type = freebsd; then + cgibindir=${cgibindir="$webdir/cgi-bin"} + elif test $dist_type = netbsd; then + cgibindir=${pluginsdir="$libexecdir/cgi-bin"} + elif test $dist_type = openbsd; then + cgibindir=${pluginsdir="/var/www/cgi-bin/nagios"} + fi + else + cgibindir="N/A" + fi + piddir=${piddir="$localstatedir/run/${INIT_PROG}"} + if test "$need_pipe" = yes; then + pipedir=${pipedir="$localstatedir/run/${INIT_PROG}"} + else + pipedir="N/A" + fi + if test $need_log_subdir = yes; then + logdir=${logdir="$localstatedir/log/$INIT_PROG"} + else + logdir=${logdir="$localstatedir/log"} + fi + +else + + # + # Unknown install + # + install_method="unknown" + webdir=unknown + pkgsysconfdir=unknown + objsysconfdir=unknown + privatesysconfdir=unknown + logdir=unknown + piddir=unknown + pipedir=unknown + pkglocalstatedir=unknown + spooldir=unknown + brokersdir=unknown + pluginsdir=unknown + cgibindir=unknown + +fi + +eval prefix=$prefix +eval exec_prefix=$exec_prefix +eval bindir=$bindir +eval datarootdir=$datarootdir +eval datadir=$datadir +eval libexecdir=$libexecdir +eval brokersdir=$brokersdir +eval pluginsdir=$pluginsdir +eval cgibindir=$cgibindir +eval localstatedir=$localstatedir +eval pkglocalstatedir=$pkglocalstatedir +eval webdir=$webdir +eval localedir=$localedir +eval sysconfdir=$sysconfdir +eval pkgsysconfdir=$pkgsysconfdir +eval piddir=$piddir + + +# We test systemd first because in case +# someone tries to install Nagios on a +# system with a newer version, that doesn't +# have the defined versions ..we can just +# (hopefully) fall back to SysV +# And if that doesn't work, well... +AS_CASE([$init_type], + + [systemd], + if test -d "/lib/systemd/system"; then + initdir=${initdir="/lib/systemd/system"} + elif test -d "/usr/lib/systemd/system"; then + initdir=${initdir="/usr/lib/systemd/system"} + elif test -d "/usr/local/lib/systemd/system"; then + initdir=${initdir="/usr/local/lib/systemd/system"} + elif test -d "/run/systemd/system"; then + initdir=${initdir="/run/systemd/system"} + elif test -d "/etc/systemd/system"; then + initdir=${initdir="/etc/systemd/system"} + elif test -d "/etc/systemd/user"; then + initdir=${initdir="/etc/systemd/user"} + elif test -d "/run/systemd/user"; then + initdir=${initdir="/run/systemd/user"} + elif test -d "/usr/lib/systemd/user"; then + initdir=${initdir="/usr/lib/systemd/user"} + elif test -d "/usr/local/lib/systemd/user"; then + initdir=${initdir="/usr/local/lib/systemd/user"} + elif test -d "/usr/share/systemd/user"; then + initdir=${initdir="/usr/share/systemd/user"} + elif test -d "/usr/local/share/systemd/user"; then + initdir=${initdir="/usr/local/share/systemd/user"} + elif test -d "$HOME/.config/systemd/user"; then + initdir=${initdir="$HOME/.config/systemd/user"} + elif test -d "$HOME/.local/share/systemd/user"; then + initdir=${initdir="$HOME/.local/share/systemd/user"} + elif test -d "$XDG_CONFIG_HOME/systemd/user/"; then + initdir=${initdir="$XDG_CONFIG_HOME/systemd/user/"} + elif test -d "$XDG_RUNTIME_DIR/systemd/user/"; then + initdir=${initdir="$XDG_RUNTIME_DIR/systemd/user/"} + elif test -d "$XDG_DATA_HOME/systemd/user/"; then + initdir=${initdir="$XDG_DATA_HOME/systemd/user/"} + else + init_type="sysv" + fi + initname=${initname="$INIT_PROG.service"}, +) + +# +# Init scripts/files +# +AS_CASE([$init_type], + + [sysv], + if test $dist_type = "hp-ux"; then + initdir=${initdir="/sbin/init.d"} + else + initdir=${initdir="/etc/init.d"} + fi + initname=${initname="$INIT_PROG"} + initconfdir=${initconfdir="/etc/conf.d"} + initconf=${initconf="$initconfdir/$INIT_PROG"}, + + + [bsd], + if test $dist_type = "aix"; then + initdir=${initdir="/sbin/rc.d/init.d"} + initname=${initname="$INIT_PROG"} + else + initdir=${initdir="/etc/rc.d"} + initname=${initname="rc.$INIT_PROG"} + fi, + + [newbsd], + initdir=${initdir="/usr/local/etc/rc.d"} + initname=${initname="$INIT_PROG"}, + + [gentoo], + initdir=${initdir="/etc/init.d"} + initname=${initname="$INIT_PROG"} + initconfdir=${initconfdir="/etc/init.d"} + initconf=${initconf="$initconfdir/$INIT_PROG"}, + + [openrc], + initdir=${initdir="/etc/init.d"} + initname=${initname="$INIT_PROG"} + initconfdir=${initconfdir="/etc/conf.d"} + initconf=${initconf="$initconfdir/$INIT_PROG"}, + + [smf*], + if test $init_type = smf10; then + initdir=${initdir="/var/svc/manifest/network/nagios"} + else + initdir=${initdir="/lib/svc/manifest/network/nagios"} + fi + initname=${initname="$INIT_PROG.xml"} + initconfdir=unknown + initconf=unknown, + + [upstart], + initdir=${initdir="/etc/init"} + initname=${initname="$INIT_PROG.conf"} + initconfdir=${initconfdir="/etc/default"} + initconf=${initconf="$initconfdir/$INIT_PROG"}, + + [launchd], + initdir=${initdir="/Library/LaunchDaemons"} + initname=${initname="org.nagios.$INIT_PROG.plist"}, +# initconfdir=${initconfdir="/private/etc"} +# initconf=${initconf="$initconfdir/$INIT_PROG"}, + + [systemd], + init_type=systemd, + + [*], + initdir=unknown + initname=unknown) + +# Now see if they supplied any overwriting values +initdiroverridden=no +AC_ARG_WITH(initdir, + AC_HELP_STRING([--with-initdir=], + [overrides path for initdir]), + initdir=$withval + initdiroverridden=yes, + initdir=$initdir +) + +# +# Inetd (per connection) scripts/files +# +AS_CASE([$inetd_type], + [inetd*], + inetddir=${inetddir="/etc"} + inetdname=${inetdname="inetd.conf"}, + + [xinetd], + inetddir=${inetddir="/etc/xinetd.d"} + inetdname=${inetdname="$INIT_PROG"}, + + [systemd], + if test $dist_type = "debian"; then + inetddir=${inetddir="/lib/systemd/system"} + else + inetddir=${inetddir="/usr/lib/systemd/system"} + fi + netdname=${inetdname="$INIT_PROG.socket"}, + + [smf*], + if test $init_type = smf10; then + inetddir=${inetddir="/var/svc/manifest/network/nagios"} + else + inetddir=${inetddir="/lib/svc/manifest/network/nagios"} + fi + inetdname=${inetdname="$INIT_PROG.xml"}, + +# [upstart], +# inetddir=${inetddir="/etc/init.d"} +# inetdname=${inetdname="$INIT_PROG"}, + + [launchd], + inetddir=${inetddir="/Library/LaunchDaemons"} + inetdname=${inetdname="org.nagios.$INIT_PROG.plist"}, + + [*], + inetddir=${inetddir="unknown"} + inetdname=${inetdname="unknown"}) + +AC_MSG_RESULT($install_method) +]) diff --git a/autoconf-macros/ax_nagios_get_ssl b/autoconf-macros/ax_nagios_get_ssl new file mode 100644 index 0000000..ca32333 --- /dev/null +++ b/autoconf-macros/ax_nagios_get_ssl @@ -0,0 +1,303 @@ +# =========================================================================== +# SYNOPSIS +# +# AX_NAGIOS_GET_SSL +# +# DESCRIPTION +# +# This macro finds the openssl binary, the header files directory and +# the library files directory. It will also search for the gnutls +# compatibility library/headers and the nss compatibility library/headers. +# +# LICENSE +# +# Copyright (c) 2016 Nagios Core Development Team +# +# 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, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. +# =========================================================================== + +AU_ALIAS([AC_NAGIOS_GET_SSL], [AX_NAGIOS_GET_SSL]) +AC_DEFUN([AX_NAGIOS_GET_SSL], +[ + +# ------------------------------- +# SSL library and include paths +# ------------------------------- + +SSL_TYPE=openssl +try_pkg_config=1 +ssl_dir= +ssl_inc_dir= +ssl_lib_dir= +SSL_INC_DIR= +SSL_INC_PREFIX= +SSL_HDR= +SSL_LIB_DIR= + +AC_SUBST(HAVE_SSL) +AC_SUBST(SSL_TYPE) +AC_SUBST(SSL_INC_DIR) +AC_SUBST(SSL_HDR) +AC_SUBST(SSL_INC_PREFIX) +AC_SUBST(SSL_LIB_DIR) + + +# gnutls/openssl.h +# nss_compat_ossl/nss_compat_ossl.h + +dnl # Which type - openssl, gnutls-openssl, nss +dnl AC_ARG_WITH([ssl-type], +dnl dnl AS_HELP_STRING([--with-ssl-type=TYPE],[replace TYPE with gnutls or nss to use one of these instead of openssl]), +dnl AS_HELP_STRING([--with-ssl-type=TYPE],[replace TYPE with gnutls to use that instead of openssl]), +dnl [SSL_TYPE=$withval]) + +AC_ARG_WITH([ssl], + AS_HELP_STRING([--with-ssl=DIR],[sets location of the SSL installation]), + [ssl_dir=$withval]) +AC_ARG_WITH([ssl-inc], + AS_HELP_STRING([--with-ssl-inc=DIR], + [sets location of the SSL include files]), + [ssl_inc_dir=$withval]) +AC_ARG_WITH([ssl-lib], + AS_HELP_STRING([--with-ssl-lib=DIR],[sets location of the SSL libraries]), + [ssl_lib_dir=$withval]) + +if test x$ssl_inc_dir != x -o x$ssl_lib_dir != x; then + try_pkg_config=0 +fi + +AC_ARG_WITH([kerberos-inc], + AS_HELP_STRING([--with-kerberos-inc=DIR], + [sets location of the Kerberos include files]), + [kerberos_inc_dir=$withval]) + +if test x$SSL_TYPE = xyes; then + SSL_TYPE=openssl +fi + + +dflt_hdrs="$ssl_inc_dir $ssl_dir $ssl_inc_dir/include $ssl_dir/include \ + /usr/local/opt/{BBB} /usr/include/{BBB} /usr/local/include/{BBB} \ + /usr/local/{AAA} /usr/local/{BBB} /usr/lib/{AAA} /usr/lib/{BBB} \ + /usr/{AAA} /usr/pkg /usr/local /usr /usr/freeware/lib/{BBB} \ + /usr/sfw /usr/sfw/include /opt/{BBB}" + +dflt_libs="$ssl_lib_dir {ssldir} {ssldir}/lib {ssldir}/lib64 /usr/lib64 \ + /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu \ + /usr/local/lib /usr/lib/{AAA} /usr/{AAA}/lib /usr/{BBB}/lib \ + /usr/pkg/lib /usr/freeware/lib/{BBB} /usr/sfw/lib /opt/freeware/lib \ + /opt/{BBB}/lib/hpux64 /opt/{BBB}/lib/pa20_64 /opt/{BBB}/lib/hpux32 \ + /opt/{BBB}/lib /opt/{BBB}"; + + +AS_CASE([$SSL_TYPE], + [no], [SSL_TYPE=NONE], + [yes|openssl], + [ssl_hdr_dirs=`echo "$dflt_hdrs" | sed -e 's/{AAA}/ssl/g' | sed -e 's/{BBB}/openssl/g'` + ssl_lib_dirs=`echo "$dflt_libs" | sed -e 's/{AAA}/ssl/g' | sed -e 's/{BBB}/openssl/g'` + SSL_INC_PREFIX=openssl + SSL_HDR=ssl.h + ssl_lib=libssl], + [gnutls], + [ssl_hdr_dirs=`echo "$dflt_hdrs" | sed -e 's/{AAA}/gnutls/g' | sed -e 's/{BBB}/gnutls/g'` + ssl_lib_dirs=`echo "$dflt_libs" | sed -e 's/{AAA}/gnutls/g' | sed -e 's/{BBB}/gnutls/g'` + SSL_INC_PREFIX=gnutls + SSL_TYPE=gnutls_compat + SSL_HDR=compat.h + ssl_lib=libgnutls], + [nss], + [ssl_hdr_dirs=`echo "$dflt_hdrs" | sed -e 's/{AAA}/nss_compat_ossl/g' | sed -e 's/{BBB}/nss_compat_ossl/g'` + ssl_lib_dirs=`echo "$dflt_libs" | sed -e 's/{AAA}/nss_compat_ossl/g' | sed -e 's/{BBB}/nss_compat_ossl/g'` + SSL_HDR=nss_compat_ossl.h + ssl_lib=libnss_compat], + [*], echo >&6; AC_MSG_ERROR(['--with-ssl-type=$SSL_TYPE' is invalid]) +) + + +# Check for SSL support + +if test x$SSL_TYPE != xNONE; then + + found_ssl=no + + # RedHat 8.0 and 9.0 include openssl compiled with kerberos, + # so we must include header file + # Must come before openssl checks for Redhat EL 3 + AC_MSG_CHECKING(for Kerberos include files) + found_kerberos=no + for dir in $kerberos_inc_dir /usr/kerberos/include /usr/include/krb5 \ + /usr/include; do + kerbdir="$dir" + if test -f "$dir/krb5.h"; then + found_kerberos=yes + CFLAGS="$CFLAGS -I$kerbdir" + AC_DEFINE_UNQUOTED(HAVE_KRB5_H,[1],[Have the krb5.h header file]) + break + fi + done + + if test x_$found_kerberos != x_yes; then + AC_MSG_WARN(could not find include files) + else + AC_MSG_RESULT(found Kerberos include files in $kerbdir) + fi + + # First, try using pkg_config + AC_CHECK_TOOL([PKG_CONFIG], [pkg-config]) + if test x"$PKG_CONFIG" != x -a $try_pkg_config -ne 0 ; then + cflags=`$PKG_CONFIG $SSL_TYPE --cflags-only-I 2>/dev/null` + if test $? -eq 0; then + CFLAGS="$CFLAGS $cflags" + LDFLAGS="$LDFLAGS `$PKG_CONFIG $SSL_TYPE --libs-only-L 2>/dev/null`" + LIBS="$LIBS `$PKG_CONFIG $SSL_TYPE --libs-only-l 2>/dev/null`" + found_ssl=yes + AC_DEFINE_UNQUOTED(HAVE_SSL,[1],[Have SSL support]) + fi + fi + + if test x_$found_ssl != x_yes; then + + # Find the SSL Headers + AC_MSG_CHECKING(for SSL headers) + for dir in $ssl_hdr_dirs; do + if test "$dir" = "/include"; then + continue + fi + ssldir="$dir" + if test -f "$dir/include/$SSL_INC_PREFIX/$SSL_HDR"; then + found_ssl=yes + CFLAGS="$CFLAGS -I$dir/include/$SSL_INC_PREFIX -I$ssldir/include" + SSL_INC_DIR="$dir/include/$SSL_INC_PREFIX" + break + fi + if test -f "$dir/include/$SSL_HDR"; then + found_ssl=yes + if test "$SSL_HDR" != compat.h ; then + SSL_INC_PREFIX="" + fi + CFLAGS="$CFLAGS -I$dir/include" + SSL_INC_DIR="$dir/include" + break + fi + if test -f "$dir/$SSL_HDR"; then + found_ssl=yes + SSL_INC_PREFIX="" + CFLAGS="$CFLAGS -I$dir" + SSL_INC_DIR="$dir" + break + fi + if test -f "$dir/$SSL_INC_PREFIX/$SSL_HDR"; then + found_ssl=yes + CFLAGS="$CFLAGS -I$dir/$SSL_INC_PREFIX" + SSL_INC_DIR="$dir/$SSL_INC_PREFIX" + ssldir="$dir/.." + break + fi + done + + if test x_$found_ssl != x_yes; then + AC_MSG_ERROR(Cannot find ssl headers) + else + AC_MSG_RESULT(found in $ssldir) + + # Now try and find SSL libraries + + AC_MSG_CHECKING(for SSL libraries) + found_ssl=no + ssl_lib_dirs=`echo "$ssl_lib_dirs" | sed -e "s|{ssldir}|$ssldir|g"` + + if test "`uname -s`" = "Darwin" ; then + soext="dylib" + elif test "`uname -s`" = "HP-UX" ; then + if test x$arch = "xia64"; then + soext="so" + else + soext="sl" + fi + elif test "`uname -s`" = "AIX" ; then + soext="a" + else + soext="so" + fi + + for dir in $ssl_lib_dirs; do + if test -f "$dir/$ssl_lib.$soext"; then + found_ssl=yes + SSL_LIB_DIR="$dir" + break + fi + done + + if test x_$found_ssl != x_yes; then + AC_MSG_ERROR(Cannot find ssl libraries) + else + AC_MSG_RESULT(found in $SSL_LIB_DIR) + + LDFLAGS="$LDFLAGS -L$SSL_LIB_DIR"; + LIBS="$LIBS -l`echo $ssl_lib | sed -e 's/^lib//'` -lcrypto"; + AC_DEFINE_UNQUOTED(HAVE_SSL,[1],[Have SSL support]) + fi + fi + fi + + if test x$found_ssl = xyes ; then + if test -n "$SSL_INC_PREFIX" ; then + SSL_INC_PREFIX="${SSL_INC_PREFIX}/" + fi + + # try to compile and link to see if SSL is set up properly + AC_MSG_CHECKING([whether compiling and linking against SSL works]) + + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include <${SSL_INC_PREFIX}${SSL_HDR}>], [SSL_new(NULL)])], + [ + AC_MSG_RESULT([yes]) + $1 + ], [ + AC_MSG_ERROR([no]) + $2 + ]) + fi + + if test x$found_ssl = xyes -a x$need_dh = xyes; then + + # Find the openssl program + + if test x$need_dh = xyes; then + AC_PATH_PROG(sslbin,openssl,value-if-not-found,$ssl_dir/sbin$PATH_SEPARATOR$ssl_dir/bin$PATH_SEPARATOR$PATH) + AC_DEFINE(USE_SSL_DH) + # Generate DH parameters + if test -f "$sslbin"; then + echo "" + echo "*** Generating DH Parameters for SSL/TLS ***" + # awk to strip off meta data at bottom of dhparam output + $sslbin dhparam -C 2048 | awk '/^-----/ {exit} {print}' > include/dh.h + fi + fi + fi +fi +]) diff --git a/base/Makefile.in b/base/Makefile.in index 74a8211..d21934d 100644 --- a/base/Makefile.in +++ b/base/Makefile.in @@ -14,13 +14,13 @@ CC=@CC@ CFLAGS=-Wall -I.. @CFLAGS@ @DEFS@ -DNSCORE # Compiler flags for use with gprof -#CFLAGS=-pg -DHAVE_CONFIG_H -DNSCORE +#CFLAGS=-pg -I.. -DHAVE_CONFIG_H -DNSCORE # Compiler flags for use with Valgrind -#CFLAGS=-O0 -g -DHAVE_CONFIG_H -DNSCORE +#CFLAGS=-O0 -I.. -g -DHAVE_CONFIG_H -DNSCORE # Compiler flags for optimization (overrides default) -#CFLAGS=-O3 -Wall -fno-strict-aliasing -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -DHAVE_CONFIG_H -DNSCORE +#CFLAGS=-O3 -Wall -I.. -fno-strict-aliasing -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -DHAVE_CONFIG_H -DNSCORE # Compiler flags for optimization (complements default) #CFLAGS_WARN=-Wall -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs @@ -36,8 +36,8 @@ exec_prefix=@exec_prefix@ LOGDIR=@localstatedir@ CFGDIR=@sysconfdir@ BINDIR=@bindir@ -CGIDIR=@sbindir@ -HTMLDIR=@datarootdir@ +CGIDIR=@cgibindir@ +HTMLDIR=@webdir@ INSTALL=@INSTALL@ INSTALL_OPTS=@INSTALL_OPTS@ COMMAND_OPTS=@COMMAND_OPTS@ @@ -92,7 +92,7 @@ DDATAHDRS= DDATADEPS=$(DDATALIBS) -OBJS=$(BROKER_O) $(SRC_COMMON)/shared.o nerd.o query-handler.o workers.o checks.o config.o commands.o events.o flapping.o logging.o macros-base.o netutils.o notifications.o sehandlers.o utils.o $(RDATALIBS) $(CDATALIBS) $(ODATALIBS) $(SDATALIBS) $(PDATALIBS) $(DDATALIBS) $(BASEEXTRALIBS) +OBJS=$(BROKER_O) $(SRC_COMMON)/shared.o @NERD_O@ query-handler.o workers.o checks.o config.o commands.o events.o flapping.o logging.o macros-base.o netutils.o notifications.o sehandlers.o utils.o $(RDATALIBS) $(CDATALIBS) $(ODATALIBS) $(SDATALIBS) $(PDATALIBS) $(DDATALIBS) $(BASEEXTRALIBS) OBJDEPS=$(ODATADEPS) $(ODATADEPS) $(RDATADEPS) $(CDATADEPS) $(SDATADEPS) $(PDATADEPS) $(DDATADEPS) $(BROKER_H) all: nagios nagiostats diff --git a/base/checks.c b/base/checks.c index 1a777ba..55c0d84 100644 --- a/base/checks.c +++ b/base/checks.c @@ -34,6 +34,7 @@ /*#define DEBUG_CHECKS*/ /*#define DEBUG_HOST_CHECKS 1*/ +#define replace_semicolons(output, ptr) do { ptr = output; while ((ptr = strchr(ptr, ';')) != NULL) { * ptr = ':'; } } while (0) #ifdef USE_EVENT_BROKER #include "../include/neberrors.h" @@ -44,20 +45,19 @@ /******************************************************************/ /* reaps host and service check results */ -int reap_check_results(void) { +int reap_check_results(void) +{ int reaped_checks = 0; log_debug_info(DEBUGL_FUNCTIONS, 0, "reap_check_results() start\n"); - log_debug_info(DEBUGL_CHECKS, 0, "Starting to reap check results.\n"); /* process files in the check result queue */ reaped_checks = process_check_result_queue(check_result_path); - log_debug_info(DEBUGL_CHECKS, 0, "Finished reaping %d check results\n", reaped_checks); - log_debug_info(DEBUGL_FUNCTIONS, 0, "reap_check_results() end\n"); + log_debug_info(DEBUGL_FUNCTIONS, 0, "reap_check_results() reaped %d checks end\n", reaped_checks); return OK; - } +} @@ -67,15 +67,17 @@ int reap_check_results(void) { /******************************************************************/ /* executes a scheduled service check */ -int run_scheduled_service_check(service *svc, int check_options, double latency) { +int run_scheduled_service_check(service *svc, int check_options, double latency) +{ int result = OK; time_t current_time = 0L; time_t preferred_time = 0L; time_t next_valid_time = 0L; int time_is_valid = TRUE; - if(svc == NULL) + if (svc == NULL) { return ERROR; + } log_debug_info(DEBUGL_FUNCTIONS, 0, "run_scheduled_service_check() start\n"); log_debug_info(DEBUGL_CHECKS, 0, "Attempting to run scheduled check of service '%s' on host '%s': check options=%d, latency=%lf\n", svc->description, svc->host_name, check_options, latency); @@ -90,20 +92,21 @@ int run_scheduled_service_check(service *svc, int check_options, double latency) result = run_async_service_check(svc, check_options, latency, TRUE, TRUE, &time_is_valid, &preferred_time); /* an error occurred, so reschedule the check */ - if(result == ERROR) { + if (result == ERROR) { log_debug_info(DEBUGL_CHECKS, 1, "Unable to run scheduled service check at this time\n"); /* only attempt to (re)schedule checks that should get checked... */ - if(svc->should_be_scheduled == TRUE) { + if (svc->should_be_scheduled == TRUE) { /* get current time */ time(¤t_time); /* determine next time we should check the service if needed */ /* if service has no check interval, schedule it again for 5 minutes from now */ - if(current_time >= preferred_time) + if (current_time >= preferred_time) { preferred_time = current_time + ((svc->check_interval <= 0) ? 300 : (svc->check_interval * interval_length)); + } /* make sure we rescheduled the next service check at a valid time */ get_next_valid_time(preferred_time, &next_valid_time, svc->check_period_ptr); @@ -113,52 +116,53 @@ int run_scheduled_service_check(service *svc, int check_options, double latency) * just push the check to preferred_time plus some reasonable * random value and try again then. */ - if(time_is_valid == FALSE && check_time_against_period(next_valid_time, svc->check_period_ptr) == ERROR) { + if (time_is_valid == FALSE && check_time_against_period(next_valid_time, svc->check_period_ptr) == ERROR) { - svc->next_check = preferred_time + - ranged_urand(0, check_window(svc)); + svc->next_check = preferred_time + ranged_urand(0, check_window(svc)); logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of service '%s' on host '%s' could not be rescheduled properly. Scheduling check for %s...\n", svc->description, svc->host_name, ctime(&preferred_time)); log_debug_info(DEBUGL_CHECKS, 1, "Unable to find any valid times to reschedule the next service check!\n"); - } + } /* this service could be rescheduled... */ else { svc->next_check = next_valid_time; - if(next_valid_time > preferred_time) { + if (next_valid_time > preferred_time) { /* Next valid time is further in the future because of * timeperiod constraints. Add a random amount so we * don't get all checks subject to that timeperiod * constraint scheduled at the same time */ svc->next_check += ranged_urand(0, check_window(svc)); - } + } svc->should_be_scheduled = TRUE; log_debug_info(DEBUGL_CHECKS, 1, "Rescheduled next service check for %s", ctime(&next_valid_time)); - } } + } /* * reschedule the next service check - unless we couldn't * find a valid next check time, but keep original options */ - if(svc->should_be_scheduled == TRUE) + if (svc->should_be_scheduled == TRUE) { schedule_service_check(svc, svc->next_check, check_options); + } /* update the status log */ update_service_status(svc, FALSE); return ERROR; - } + } return OK; - } +} /* forks a child process to run a service check, but does not wait for the service check result */ -int run_async_service_check(service *svc, int check_options, double latency, int scheduled_check, int reschedule_check, int *time_is_valid, time_t *preferred_time) { +int run_async_service_check(service *svc, int check_options, double latency, int scheduled_check, int reschedule_check, int *time_is_valid, time_t *preferred_time) +{ nagios_macros mac; char *raw_command = NULL; char *processed_command = NULL; @@ -175,16 +179,19 @@ int run_async_service_check(service *svc, int check_options, double latency, int log_debug_info(DEBUGL_FUNCTIONS, 0, "run_async_service_check()\n"); /* make sure we have something */ - if(svc == NULL) + if (svc == NULL) { return ERROR; + } /* is the service check viable at this time? */ - if(check_service_check_viability(svc, check_options, time_is_valid, preferred_time) == ERROR) + if (check_service_check_viability(svc, check_options, time_is_valid, preferred_time) == ERROR) { return ERROR; + } /* find the host associated with this service */ - if((temp_host = svc->host_ptr) == NULL) + if ((temp_host = svc->host_ptr) == NULL) { return ERROR; + } /******** GOOD TO GO FOR A REAL SERVICE CHECK AT THIS POINT ********/ @@ -198,23 +205,25 @@ int run_async_service_check(service *svc, int check_options, double latency, int /* send data to event broker */ neb_result = broker_service_check(NEBTYPE_SERVICECHECK_ASYNC_PRECHECK, NEBFLAG_NONE, NEBATTR_NONE, svc, CHECK_TYPE_ACTIVE, start_time, end_time, svc->check_command, svc->latency, 0.0, 0, FALSE, 0, NULL, NULL, NULL); - if (neb_result == NEBERROR_CALLBACKCANCEL || neb_result == NEBERROR_CALLBACKOVERRIDE) { - log_debug_info(DEBUGL_CHECKS, 0, "Check of service '%s' on host '%s' (id=%u) was %s by a module\n", - svc->description, svc->host_name, svc->id, - neb_result == NEBERROR_CALLBACKCANCEL ? "cancelled" : "overridden"); - } /* neb module wants to cancel the service check - the check will be rescheduled for a later time by the scheduling logic */ - if(neb_result == NEBERROR_CALLBACKCANCEL) { - if(preferred_time) + if (neb_result == NEBERROR_CALLBACKCANCEL) { + + log_debug_info(DEBUGL_CHECKS, 0, "Check of service '%s' on host '%s' (id=%u) was cancelled by a module\n", svc->description, svc->host_name, svc->id); + + if (preferred_time) { *preferred_time += (svc->check_interval * interval_length); - return ERROR; } + return ERROR; + } /* neb module wants to override (or cancel) the service check - perhaps it will check the service itself */ /* NOTE: if a module does this, it has to do a lot of the stuff found below to make sure things don't get whacked out of shape! */ /* NOTE: if would be easier for modules to override checks when the NEBTYPE_SERVICECHECK_INITIATE event is called (later) */ - if(neb_result == NEBERROR_CALLBACKOVERRIDE) + if (neb_result == NEBERROR_CALLBACKOVERRIDE) { + + log_debug_info(DEBUGL_CHECKS, 0, "Check of service '%s' on host '%s' (id=%u) was overridden by a module\n", svc->description, svc->host_name, svc->id); return OK; + } #endif @@ -222,8 +231,9 @@ int run_async_service_check(service *svc, int check_options, double latency, int /* clear check options - we don't want old check options retained */ /* only clear check options for scheduled checks - ondemand checks shouldn't affected retained check options */ - if(scheduled_check == TRUE) + if (scheduled_check == TRUE) { svc->check_options = CHECK_OPTION_NONE; + } /* update latency for macros, event broker, save old value for later */ old_latency = svc->latency; @@ -236,26 +246,28 @@ int run_async_service_check(service *svc, int check_options, double latency, int /* get the raw command line */ get_raw_command_line_r(&mac, svc->check_command_ptr, svc->check_command, &raw_command, macro_options); - if(raw_command == NULL) { + if (raw_command == NULL) { clear_volatile_macros_r(&mac); log_debug_info(DEBUGL_CHECKS, 0, "Raw check command for service '%s' on host '%s' was NULL - aborting.\n", svc->description, svc->host_name); - if(preferred_time) + if (preferred_time) { *preferred_time += (svc->check_interval * interval_length); + } svc->latency = old_latency; return ERROR; - } + } /* process any macros contained in the argument */ process_macros_r(&mac, raw_command, &processed_command, macro_options); my_free(raw_command); - if(processed_command == NULL) { + if (processed_command == NULL) { clear_volatile_macros_r(&mac); log_debug_info(DEBUGL_CHECKS, 0, "Processed check command for service '%s' on host '%s' was NULL - aborting.\n", svc->description, svc->host_name); - if(preferred_time) + if (preferred_time) { *preferred_time += (svc->check_interval * interval_length); + } svc->latency = old_latency; return ERROR; - } + } /* get the command start time */ gettimeofday(&start_time, NULL); @@ -290,13 +302,13 @@ int run_async_service_check(service *svc, int check_options, double latency, int neb_result = broker_service_check(NEBTYPE_SERVICECHECK_INITIATE, NEBFLAG_NONE, NEBATTR_NONE, svc, CHECK_TYPE_ACTIVE, start_time, end_time, svc->check_command, svc->latency, 0.0, service_check_timeout, FALSE, 0, processed_command, NULL, cr); /* neb module wants to override the service check - perhaps it will check the service itself */ - if(neb_result == NEBERROR_CALLBACKOVERRIDE) { + if (neb_result == NEBERROR_CALLBACKOVERRIDE) { clear_volatile_macros_r(&mac); svc->latency = old_latency; free_check_result(cr); my_free(processed_command); return OK; - } + } #endif /* reset latency (permanent value will be set later) */ @@ -319,764 +331,1342 @@ int run_async_service_check(service *svc, int check_options, double latency, int clear_volatile_macros_r(&mac); return runchk_result; - } +} +/* Start of inline helper functions for handle async host/service check result functions + BH 03 Dec 2017 + The giant monolithic async helper functions were becoming difficult to maintain + So I broke them out into smaller manageable chunks where a side-by-side comparison + of the two functions is a bit more reasonable. This would have been a lot easier with + dynamic type casting, or even some macro magic - but at least this way it isn't as + messy as it would have been with macros. -static int get_service_check_return_code(service *temp_service, - check_result *queued_check_result) { + When introducing new inline helper functions, the goal is so that both of the functions + can sit on the same screen at the same time - for obvious reasons (I hope). + Try to keep them concise */ +/* Bit of logic for determining an adequate return code */ +int get_service_check_return_code(service *svc, check_result *cr) +{ int rc; - char *temp_plugin_output = NULL; log_debug_info(DEBUGL_FUNCTIONS, 0, "get_service_check_return_code()\n"); - if(NULL == temp_service || NULL == queued_check_result) { + if (NULL == svc || NULL == cr) { return STATE_UNKNOWN; - } - - /* grab the return code */ - rc = queued_check_result->return_code; - - /* adjust return code (active checks only) */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE) { - if(queued_check_result->early_timeout == TRUE) { - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of service '%s' on host '%s' timed out after %.3fs!\n", temp_service->description, temp_service->host_name, temp_service->execution_time); - my_free(temp_service->plugin_output); - my_free(temp_service->long_plugin_output); - my_free(temp_service->perf_data); - asprintf(&temp_service->plugin_output, "(Service check timed out after %.2lf seconds)", temp_service->execution_time); - rc = service_check_timeout_state; - } - /* if there was some error running the command, just skip it (this shouldn't be happening) */ - else if(queued_check_result->exited_ok == FALSE) { - - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of service '%s' on host '%s' did not exit properly!\n", temp_service->description, temp_service->host_name); - - my_free(temp_service->plugin_output); - my_free(temp_service->long_plugin_output); - my_free(temp_service->perf_data); - - temp_service->plugin_output = (char *)strdup("(Service check did not exit properly)"); - - rc = STATE_CRITICAL; - } - - /* make sure the return code is within bounds */ - else if(queued_check_result->return_code < 0 || queued_check_result->return_code > 3) { - - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of %d for check of service '%s' on host '%s' was out of bounds.%s\n", queued_check_result->return_code, temp_service->description, temp_service->host_name, (queued_check_result->return_code == 126 ? "Make sure the plugin you're trying to run is executable." : (queued_check_result->return_code == 127 ? " Make sure the plugin you're trying to run actually exists." : ""))); - - asprintf(&temp_plugin_output, "(Return code of %d is out of bounds%s : %s)", queued_check_result->return_code, (queued_check_result->return_code == 126 ? " - plugin may not be executable" : (queued_check_result->return_code == 127 ? " - plugin may be missing" : "")), temp_service->plugin_output); - my_free(temp_service->plugin_output); - - asprintf(&temp_service->plugin_output, "%s)", temp_plugin_output); - my_free(temp_plugin_output); - my_free(temp_service->long_plugin_output); - my_free(temp_service->perf_data); - - rc = STATE_CRITICAL; - } - } - - return rc; } - -/* handles asynchronous service check results */ -int handle_async_service_check_result(service *temp_service, check_result *queued_check_result) { - host *temp_host = NULL; - time_t next_service_check = 0L; - time_t preferred_time = 0L; - time_t next_valid_time = 0L; - int reschedule_check = FALSE; - int state_change = FALSE; - int hard_state_change = FALSE; - int first_host_check_initiated = FALSE; - int route_result = HOST_UP; - time_t current_time = 0L; - int state_was_logged = FALSE; - char *old_plugin_output = NULL; - char *temp_plugin_output = NULL; - char *temp_ptr = NULL; - servicedependency *temp_dependency = NULL; - service *master_service = NULL; - int flapping_check_done = FALSE; - - - log_debug_info(DEBUGL_FUNCTIONS, 0, "handle_async_service_check_result()\n"); - - /* make sure we have what we need */ - if(temp_service == NULL || queued_check_result == NULL) - return ERROR; - - /* get the current time */ - time(¤t_time); - - if (current_time < temp_service->next_check) - next_service_check = temp_service->next_check + check_window(temp_service); - else - next_service_check = current_time + check_window(temp_service); - - log_debug_info(DEBUGL_CHECKS, 0, "** Handling check result for service '%s' on host '%s' from '%s'...\n", temp_service->description, temp_service->host_name, check_result_source(queued_check_result)); - log_debug_info(DEBUGL_CHECKS, 1, "HOST: %s, SERVICE: %s, CHECK TYPE: %s, OPTIONS: %d, SCHEDULED: %s, RESCHEDULE: %s, EXITED OK: %s, RETURN CODE: %d, OUTPUT: %s\n", temp_service->host_name, temp_service->description, (queued_check_result->check_type == CHECK_TYPE_ACTIVE) ? "Active" : "Passive", queued_check_result->check_options, (queued_check_result->scheduled_check == TRUE) ? "Yes" : "No", (queued_check_result->reschedule_check == TRUE) ? "Yes" : "No", (queued_check_result->exited_ok == TRUE) ? "Yes" : "No", queued_check_result->return_code, queued_check_result->output); - - /* decrement the number of service checks still out there... */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE && currently_running_service_checks > 0) - currently_running_service_checks--; - - /* skip this service check results if its passive and we aren't accepting passive check results */ - if(queued_check_result->check_type == CHECK_TYPE_PASSIVE) { - if(accept_passive_service_checks == FALSE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive service check result because passive service checks are disabled globally.\n"); - return ERROR; - } - if(temp_service->accept_passive_checks == FALSE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive service check result because passive checks are disabled for this service.\n"); - return ERROR; - } - } - - /* clear the freshening flag (it would have been set if this service was determined to be stale) */ - if(queued_check_result->check_options & CHECK_OPTION_FRESHNESS_CHECK) - temp_service->is_being_freshened = FALSE; - - /* clear the execution flag if this was an active check */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE) - temp_service->is_executing = FALSE; - - /* DISCARD INVALID FRESHNESS CHECK RESULTS */ - /* If a services goes stale, Nagios will initiate a forced check in order to freshen it. There is a race condition whereby a passive check - could arrive between the 1) initiation of the forced check and 2) the time when the forced check result is processed here. This would - make the service fresh again, so we do a quick check to make sure the service is still stale before we accept the check result. */ - if((queued_check_result->check_options & CHECK_OPTION_FRESHNESS_CHECK) && is_service_result_fresh(temp_service, current_time, FALSE) == TRUE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding service freshness check result because the service is currently fresh (race condition avoided).\n"); - return OK; - } - - /* check latency is passed to us */ - temp_service->latency = queued_check_result->latency; - - /* update the execution time for this check (millisecond resolution) */ - temp_service->execution_time = (double)((double)(queued_check_result->finish_time.tv_sec - queued_check_result->start_time.tv_sec) + (double)((queued_check_result->finish_time.tv_usec - queued_check_result->start_time.tv_usec) / 1000.0) / 1000.0); - if(temp_service->execution_time < 0.0) - temp_service->execution_time = 0.0; - - /* get the last check time */ - temp_service->last_check = queued_check_result->start_time.tv_sec; - - /* was this check passive or active? */ - temp_service->check_type = (queued_check_result->check_type == CHECK_TYPE_ACTIVE) ? CHECK_TYPE_ACTIVE : CHECK_TYPE_PASSIVE; - - /* update check statistics for passive checks */ - if(queued_check_result->check_type == CHECK_TYPE_PASSIVE) - update_check_stats(PASSIVE_SERVICE_CHECK_STATS, queued_check_result->start_time.tv_sec); - - /* should we reschedule the next service check? NOTE: This may be overridden later... */ - reschedule_check = queued_check_result->reschedule_check; - - /* save the old service status info */ - temp_service->last_state = temp_service->current_state; - - /* save old plugin output */ - if(temp_service->plugin_output) - old_plugin_output = (char *)strdup(temp_service->plugin_output); - - /* clear the old plugin output and perf data buffers */ - my_free(temp_service->plugin_output); - my_free(temp_service->long_plugin_output); - my_free(temp_service->perf_data); - - /* parse check output to get: (1) short output, (2) long output, (3) perf data */ - parse_check_output(queued_check_result->output, &temp_service->plugin_output, &temp_service->long_plugin_output, &temp_service->perf_data, TRUE, FALSE); - - /* make sure the plugin output isn't null */ - if(temp_service->plugin_output == NULL) - temp_service->plugin_output = (char *)strdup("(No output returned from plugin)"); - - /* replace semicolons in plugin output (but not performance data) with colons */ - else if((temp_ptr = temp_service->plugin_output)) { - while((temp_ptr = strchr(temp_ptr, ';'))) - * temp_ptr = ':'; - } + /* return now if it's a passive check */ + if (cr->check_type != CHECK_TYPE_ACTIVE) { + return cr->return_code; + } /* grab the return code */ - temp_service->current_state = get_service_check_return_code(temp_service, - queued_check_result); + rc = cr->return_code; - log_debug_info(DEBUGL_CHECKS, 2, "Parsing check output...\n"); - log_debug_info(DEBUGL_CHECKS, 2, "Short Output: %s\n", (temp_service->plugin_output == NULL) ? "NULL" : temp_service->plugin_output); - log_debug_info(DEBUGL_CHECKS, 2, "Long Output: %s\n", (temp_service->long_plugin_output == NULL) ? "NULL" : temp_service->long_plugin_output); - log_debug_info(DEBUGL_CHECKS, 2, "Perf Data: %s\n", (temp_service->perf_data == NULL) ? "NULL" : temp_service->perf_data); + /* did the check result have an early timeout? */ + if (cr->early_timeout == TRUE) { - /* record the time the last state ended */ - switch(temp_service->last_state) { - case STATE_OK: - temp_service->last_time_ok = temp_service->last_check; - break; - case STATE_WARNING: - temp_service->last_time_warning = temp_service->last_check; - break; - case STATE_UNKNOWN: - temp_service->last_time_unknown = temp_service->last_check; - break; - case STATE_CRITICAL: - temp_service->last_time_critical = temp_service->last_check; - break; - default: - break; + my_free(svc->plugin_output); + my_free(svc->long_plugin_output); + my_free(svc->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of service '%s' on host '%s' timed out after %.3fs!\n", svc->description, svc->host_name, svc->execution_time); + asprintf(&svc->plugin_output, "(Service check timed out after %.2lf seconds)", svc->execution_time); + + rc = service_check_timeout_state; + } + + /* if there was some error running the command, just skip it (this shouldn't be happening) */ + else if (cr->exited_ok == FALSE) { + + my_free(svc->plugin_output); + my_free(svc->long_plugin_output); + my_free(svc->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of service '%s' on host '%s' did not exit properly!\n", svc->description, svc->host_name); + svc->plugin_output = (char *)strdup("(Service check did not exit properly)"); + + rc = STATE_CRITICAL; + } + + /* 126 is a return code for non-executable */ + else if (cr->return_code == 126) { + + my_free(svc->plugin_output); + my_free(svc->long_plugin_output); + my_free(svc->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of 126 for service '%s' on host '%s' may indicate a non-executable plugin.\n", + svc->description, svc->host_name); + svc->plugin_output = strdup("(Return code of 126 is out of bounds. Check if plugin is executable)"); + rc = STATE_CRITICAL; + } + + /* 127 is a return code for non-existent */ + else if (cr->return_code == 127) { + + my_free(svc->plugin_output); + my_free(svc->long_plugin_output); + my_free(svc->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of 127 for service '%s' on host '%s' may indicate this plugin doesn't exist.\n", + svc->description, svc->host_name); + svc->plugin_output = strdup("(Return code of 127 is out of bounds. Check if plugin exists)"); + rc = STATE_CRITICAL; + } + + /* make sure the return code is within bounds */ + else if (cr->return_code < 0 || cr->return_code > 3) { + + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: Return code of %d for check of service '%s' on host '%s' was out of bounds.\n", + cr->return_code, + svc->description, + svc->host_name); + + asprintf(&svc->plugin_output, "(Return code of %d for service '%s' on host '%s' was out of bounds)", + cr->return_code, + svc->description, + svc->host_name); + + rc = STATE_CRITICAL; + } + + return rc; +} + +/* Bit of logic for determining an adequate return code */ +int get_host_check_return_code(host *hst, check_result *cr) +{ + int rc; + + log_debug_info(DEBUGL_FUNCTIONS, 0, "get_host_check_return_code()\n"); + + if (hst == NULL || cr == NULL) { + return HOST_UNREACHABLE; + } + + /* return now if it's a passive check */ + if (cr->check_type != CHECK_TYPE_ACTIVE) { + return cr->return_code; + } + + /* get the unprocessed return code */ + rc = cr->return_code; + + /* did the check result have an early timeout? */ + if (cr->early_timeout) { + + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' timed out after %.2lf seconds\n", hst->name, hst->execution_time); + asprintf(&hst->plugin_output, "(Host check timed out after %.2lf seconds)", hst->execution_time); + + rc = HOST_UNREACHABLE; + } + + /* if there was some error running the command, just skip it (this shouldn't be happening) */ + else if (cr->exited_ok == FALSE) { + + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' did not exit properly!\n", hst->name); + hst->plugin_output = (char *)strdup("(Host check did not exit properly)"); + + rc = HOST_UNREACHABLE; + } + + /* 126 is a return code for non-executable */ + else if (cr->return_code == 126) { + + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of 126 for host '%s' may indicate a non-executable plugin.\n", + hst->name); + hst->plugin_output = strdup("(Return code of 126 is out of bounds. Check if plugin is executable)"); + rc = HOST_UNREACHABLE; + } + + /* 127 is a return code for non-existent */ + else if (cr->return_code == 127) { + + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of 127 for host '%s' may indicate this plugin doesn't exist.\n", + hst->name); + hst->plugin_output = strdup("(Return code of 127 is out of bounds. Check if plugin exists)"); + rc = HOST_UNREACHABLE; + } + + /* make sure the return code is within bounds */ + else if (cr->return_code < 0 || cr->return_code > 3) { + + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); + + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: Return code of %d for check of host '%s' was out of bounds.\n", + cr->return_code, + hst->name); + + asprintf(&hst->plugin_output, "(Return code of %d for host '%s' was out of bounds)", + cr->return_code, + hst->name); + + rc = HOST_UNREACHABLE; + } + + /* a NULL host check command means we should assume the host is UP */ + if (hst->check_command == NULL) { + my_free(hst->plugin_output); + hst->plugin_output = (char *)strdup("(Host assumed to be UP)"); + rc = HOST_UP; + } + + /* if we're not doing aggressive host checking, let WARNING states indicate the host is up (fake the result to be HOST_UP) */ + else if (use_aggressive_host_checking == FALSE && rc == STATE_WARNING) { + rc = HOST_UP; + } + + /* any problem state indicates the host is not UP */ + else if (rc != HOST_UP) { + rc = HOST_DOWN; + } + + return rc; +} + +/****************************************************************************** + ******* Calculate check result exec time + *****************************************************************************/ +static inline double calculate_check_result_execution_time(check_result *cr) +{ + double execution_time = 0.0; + + if (cr != NULL) { + + double start_s = cr->start_time.tv_sec; + double start_us = cr->start_time.tv_usec; + double finish_s = cr->finish_time.tv_sec; + double finish_us = cr->finish_time.tv_usec; + + execution_time = ((finish_s - start_s) + ((finish_us - start_us) / 1000.0) / 1000.0); + if (execution_time < 0.0) { + execution_time = 0.0; + } + } + + return execution_time; +} + +/****************************************************************************** + ******* Last state ended + *****************************************************************************/ +static inline void record_last_service_state_ended(service * svc) +{ + switch(svc->last_state) { + case STATE_OK: + svc->last_time_ok = svc->last_check; + break; + case STATE_WARNING: + svc->last_time_warning = svc->last_check; + break; + case STATE_UNKNOWN: + svc->last_time_unknown = svc->last_check; + break; + case STATE_CRITICAL: + svc->last_time_critical = svc->last_check; + break; + default: + break; + } +} +/*****************************************************************************/ +static inline void record_last_host_state_ended(host * hst) +{ + switch(hst->last_state) { + case HOST_UP: + hst->last_time_up = hst->last_check; + break; + case HOST_DOWN: + hst->last_time_down = hst->last_check; + break; + case HOST_UNREACHABLE: + hst->last_time_unreachable = hst->last_check; + break; + default: + break; + } +} + +/****************************************************************************** + ******* Logic chunks for when an object is passive + *****************************************************************************/ +static inline int service_is_passive(service *svc, check_result *cr) +{ + if (accept_passive_service_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive service check result because passive service checks are disabled globally.\n"); + return FALSE; + } + + if (svc->accept_passive_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive service check result because passive checks are disabled for this service.\n"); + return FALSE; + } + + svc->check_type = CHECK_TYPE_PASSIVE; + + /* update check statistics for passive checks */ + update_check_stats(PASSIVE_SERVICE_CHECK_STATS, cr->start_time.tv_sec); + + /* log passive checks - we need to do this here, as some may bypass external commands by getting dropped in checkresults dir */ + if (log_passive_checks == TRUE) { + logit(NSLOG_PASSIVE_CHECK, FALSE, "PASSIVE SERVICE CHECK: %s;%s;%d;%s\n", + svc->host_name, + svc->description, + svc->current_state, + svc->plugin_output); + } + + return TRUE; +} +/*****************************************************************************/ +static inline int host_is_passive(host *hst, check_result *cr) +{ + if (accept_passive_host_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive host check result because passive host checks are disabled globally.\n"); + return FALSE; + } + if (hst->accept_passive_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive host check result because passive checks are disabled for this host.\n"); + return FALSE; + } + + hst->check_type = CHECK_TYPE_PASSIVE; + + /* update check stats for passive checks */ + update_check_stats(PASSIVE_HOST_CHECK_STATS, cr->start_time.tv_sec); + + /* log passive checks - we need to do this here as some may bypass external commands by getting dropped in checkresults dir */ + /* todo - check if current_state is right - i don't think it is! */ + if (log_passive_checks == TRUE) { + logit(NSLOG_PASSIVE_CHECK, FALSE, "PASSIVE HOST CHECK: %s;%d;%s\n", + hst->name, + hst->current_state, + hst->plugin_output); + } + + return TRUE; +} + +/****************************************************************************** + ******* Logic chunks for when an object is active + *****************************************************************************/ +static inline void service_is_active(service *svc) +{ + svc->check_type = CHECK_TYPE_ACTIVE; + + /* decrement the number of service checks still out there... */ + if (currently_running_service_checks > 0) { + currently_running_service_checks--; + } + + svc->is_executing = FALSE; +} +/*****************************************************************************/ +static inline void host_is_active(host *hst) +{ + hst->check_type = CHECK_TYPE_ACTIVE; + + /* decrement the number of host checks still out there... */ + if (currently_running_host_checks > 0) { + currently_running_host_checks--; + } + + hst->is_executing = FALSE; +} + +/****************************************************************************** + ******* Generic debugging functions + *****************************************************************************/ +static inline void debug_async_service(service *svc, check_result *cr) +{ + log_debug_info(DEBUGL_CHECKS, 0, "** Handling %s async check result for service '%s' on host '%s' from '%s'...\n", + (cr->check_type == CHECK_TYPE_ACTIVE) ? "ACTIVE" : "PASSIVE", + svc->description, + svc->host_name, + check_result_source(cr)); + + log_debug_info(DEBUGL_CHECKS, 1, + " * OPTIONS: %d, SCHEDULED: %d, RESCHEDULE: %d, EXITED OK: %d, RETURN CODE: %d, OUTPUT:\n%s\n", + cr->check_options, + cr->scheduled_check, + cr->reschedule_check, + cr->exited_ok, + cr->return_code, + (cr == NULL) ? "NULL" : cr->output); +} +/*****************************************************************************/ +static inline void debug_async_host(host *hst, check_result *cr) +{ + log_debug_info(DEBUGL_CHECKS, 0, "** Handling %s async check result for host '%s' from '%s'...\n", + (cr->check_type == CHECK_TYPE_ACTIVE) ? "ACTIVE" : "PASSIVE", + hst->name, + check_result_source(cr)); + + log_debug_info(DEBUGL_CHECKS, 1, + " * OPTIONS: %d, SCHEDULED: %d, RESCHEDULE: %d, EXITED OK: %d, RETURN CODE: %d, OUTPUT:\n%s\n", + cr->check_options, + cr->scheduled_check, + cr->reschedule_check, + cr->exited_ok, + cr->return_code, + (cr == NULL) ? "NULL" : cr->output); +} + +/****************************************************************************** + ******* Logic chunks for checking object freshness + *****************************************************************************/ +static inline void service_fresh_check(service *svc, check_result *cr, time_t current_time) +{ + /* check freshness */ + if (cr->check_options & CHECK_OPTION_FRESHNESS_CHECK) { + + /* DISCARD INVALID FRESHNESS CHECK RESULTS */ + /* If a services goes stale, Nagios will initiate a forced check in order to freshen it. There is a race condition whereby a passive check + could arrive between the 1) initiation of the forced check and 2) the time when the forced check result is processed here. This would + make the service fresh again, so we do a quick check to make sure the service is still stale before we accept the check result. */ + if (is_service_result_fresh(svc, current_time, FALSE) == TRUE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding service freshness check result because the service is currently fresh (race condition avoided).\n"); + return; } - /* log passive checks - we need to do this here, as some my bypass external commands by getting dropped in checkresults dir */ - if(temp_service->check_type == CHECK_TYPE_PASSIVE) { - if(log_passive_checks == TRUE) - logit(NSLOG_PASSIVE_CHECK, FALSE, "PASSIVE SERVICE CHECK: %s;%s;%d;%s\n", temp_service->host_name, temp_service->description, temp_service->current_state, temp_service->plugin_output); + /* clear the freshening flag (it would have been set if this service was determined to be stale) */ + svc->is_being_freshened = FALSE; + } +} +/*****************************************************************************/ +static inline void host_fresh_check(host *hst, check_result *cr, time_t current_time) +{ + /* check freshness */ + if (cr->check_options & CHECK_OPTION_FRESHNESS_CHECK) { + + /* DISCARD INVALID FRESHNESS CHECK RESULTS */ + /* If a host goes stale, Nagios will initiate a forced check in order to freshen it. There is a race condition whereby a passive check + could arrive between the 1) initiation of the forced check and 2) the time when the forced check result is processed here. This would + make the host fresh again, so we do a quick check to make sure the host is still stale before we accept the check result. */ + if (is_host_result_fresh(hst, current_time, FALSE) == TRUE) { + log_debug_info(DEBUGL_CHECKS, 0, "Discarding host freshness check result because the host is currently fresh (race condition avoided).\n"); + return; } - /* get the host that this service runs on */ - temp_host = (host *)temp_service->host_ptr; + /* clear the freshening flag (it would have been set if this host was determined to be stale) */ + hst->is_being_freshened = FALSE; + } +} - /* if the service check was okay... */ - if(temp_service->current_state == STATE_OK) { +/****************************************************************************** + ******* Logic chunks for setting some of the initial flags, etc. + *****************************************************************************/ +static inline void service_initial_handling(service *svc, check_result *cr, char **old_plugin_output) +{ + char * temp_ptr = NULL; - /* if the host has never been checked before, verify its status */ - /* only do this if 1) the initial state was set to non-UP or 2) the host is not scheduled to be checked soon (next 5 minutes) */ - if(temp_host->has_been_checked == FALSE && (temp_host->initial_state != HOST_UP || (unsigned long)temp_host->next_check == 0L || (unsigned long)(temp_host->next_check - current_time) > 300)) { + /* save old plugin output */ + if (svc->plugin_output) { + * old_plugin_output = (char *)strdup(svc->plugin_output); + } - /* set a flag to remember that we launched a check */ - first_host_check_initiated = TRUE; - schedule_host_check(temp_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - } + my_free(svc->plugin_output); + my_free(svc->long_plugin_output); + my_free(svc->perf_data); + /* parse check output to get: (1) short output, (2) long output, (3) perf data */ + parse_check_output(cr->output, &svc->plugin_output, &svc->long_plugin_output, &svc->perf_data, TRUE, FALSE); - /* increment the current attempt number if this is a soft state (service was rechecked) */ - if(temp_service->state_type == SOFT_STATE && (temp_service->current_attempt < temp_service->max_attempts)) - temp_service->current_attempt = temp_service->current_attempt + 1; + /* make sure the plugin output isn't null */ + if (svc->plugin_output == NULL) { + svc->plugin_output = (char *)strdup("(No output returned from plugin)"); + } + /* otherwise replace the semicolons with colons */ + else { + replace_semicolons(svc->plugin_output, temp_ptr); + } + log_debug_info(DEBUGL_CHECKS, 2, + "Parsing check output...\n" + "Short Output: %s\n" + "Long Output: %s\n" + "Perf Data: %s\n", + svc->plugin_output, + (svc->long_plugin_output == NULL) ? "NULL" : svc->long_plugin_output, + (svc->perf_data == NULL) ? "NULL" : svc->perf_data); - log_debug_info(DEBUGL_CHECKS, 2, "ST: %s CA: %d MA: %d CS: %d LS: %d LHS: %d\n", (temp_service->state_type == SOFT_STATE) ? "SOFT" : "HARD", temp_service->current_attempt, temp_service->max_attempts, temp_service->current_state, temp_service->last_state, temp_service->last_hard_state); + svc->latency = cr->latency; + svc->execution_time = calculate_check_result_execution_time(cr); + svc->last_check = cr->start_time.tv_sec; + svc->should_be_scheduled = cr->reschedule_check; - /* check for a state change (either soft or hard) */ - if(temp_service->current_state != temp_service->last_state) { - log_debug_info(DEBUGL_CHECKS, 2, "Service has changed state since last check!\n"); - state_change = TRUE; - } + svc->last_state = svc->current_state; + svc->current_state = get_service_check_return_code(svc, cr); +} +/*****************************************************************************/ +static inline void host_initial_handling(host *hst, check_result *cr, char **old_plugin_output) +{ + char * temp_ptr = NULL; - /* checks for a hard state change where host was down at last service check */ - /* this occurs in the case where host goes down and service current attempt gets reset to 1 */ - /* if this check is not made, the service recovery looks like a soft recovery instead of a hard one */ - if(temp_service->host_problem_at_last_check == TRUE && temp_service->current_state == STATE_OK) { - log_debug_info(DEBUGL_CHECKS, 2, "Service had a HARD STATE CHANGE!!\n"); - hard_state_change = TRUE; - } + /* save old plugin output */ + if (hst->plugin_output) { + * old_plugin_output = (char *)strdup(hst->plugin_output); + } - /* check for a "normal" hard state change where max check attempts is reached */ - if(temp_service->current_attempt >= temp_service->max_attempts && temp_service->current_state != temp_service->last_hard_state) { - log_debug_info(DEBUGL_CHECKS, 2, "Service had a HARD STATE CHANGE!!\n"); - hard_state_change = TRUE; - } + my_free(hst->plugin_output); + my_free(hst->long_plugin_output); + my_free(hst->perf_data); - /* a state change occurred... */ - /* reset last and next notification times and acknowledgement flag if necessary, misc other stuff */ - if(state_change == TRUE || hard_state_change == TRUE) { + /* parse check output to get: (1) short output, (2) long output, (3) perf data */ + parse_check_output(cr->output, &hst->plugin_output, &hst->long_plugin_output, &hst->perf_data, TRUE, FALSE); - /* reschedule the service check */ - reschedule_check = TRUE; + /* make sure the plugin output isn't null */ + if (hst->plugin_output == NULL) { + hst->plugin_output = (char *)strdup("(No output returned from host check)"); + } + /* otherwise replace the semicolons with colons */ + else { + replace_semicolons(hst->plugin_output, temp_ptr); + } - /* reset notification times */ - temp_service->last_notification = (time_t)0; - temp_service->next_notification = (time_t)0; + log_debug_info(DEBUGL_CHECKS, 2, + "Parsing check output...\n" + "Short Output: %s\n" + "Long Output: %s\n" + "Perf Data: %s\n", + hst->plugin_output, + (hst->long_plugin_output == NULL) ? "NULL" : hst->long_plugin_output, + (hst->perf_data == NULL) ? "NULL" : hst->perf_data); - /* reset notification suppression option */ - temp_service->no_more_notifications = FALSE; + hst->latency = cr->latency; + hst->execution_time = calculate_check_result_execution_time(cr); + hst->last_check = cr->start_time.tv_sec; + hst->should_be_scheduled = cr->reschedule_check; - if(temp_service->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL && (state_change == TRUE || hard_state_change == FALSE)) { + hst->last_state = hst->current_state; + hst->current_state = get_host_check_return_code(hst, cr); +} - temp_service->problem_has_been_acknowledged = FALSE; - temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; - - /* remove any non-persistant comments associated with the ack */ - delete_service_acknowledgement_comments(temp_service); - } - else if(temp_service->acknowledgement_type == ACKNOWLEDGEMENT_STICKY && temp_service->current_state == STATE_OK) { - - temp_service->problem_has_been_acknowledged = FALSE; - temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; - - /* remove any non-persistant comments associated with the ack */ - delete_service_acknowledgement_comments(temp_service); - } - - /* - * hard changes between non-OK states should continue - * to be escalated, so don't reset current notification number - */ - } - - /* initialize the last host and service state change times if necessary */ - if(temp_service->last_state_change == (time_t)0) - temp_service->last_state_change = temp_service->last_check; - if(temp_service->last_hard_state_change == (time_t)0) - temp_service->last_hard_state_change = temp_service->last_check; - if(temp_host->last_state_change == (time_t)0) - temp_host->last_state_change = temp_service->last_check; - if(temp_host->last_hard_state_change == (time_t)0) - temp_host->last_hard_state_change = temp_service->last_check; - - /* update last service state change times */ - if(state_change == TRUE) - temp_service->last_state_change = temp_service->last_check; - if(hard_state_change == TRUE) - temp_service->last_hard_state_change = temp_service->last_check; +/****************************************************************************** + ******* Logic for when an object has a notable change + ******* Removes acknowledgement, advances event_id, etc. + *****************************************************************************/ +static inline void service_state_or_hard_state_type_change(service * svc, int state_change, int hard_state_change, int * log_event, int * handle_event) +{ + int state_or_type_change = FALSE; /* update the event and problem ids */ - if(state_change == TRUE) { + if (state_change == TRUE) { + + svc->last_state_change = svc->last_check; /* always update the event id on a state change */ - temp_service->last_event_id = temp_service->current_event_id; - temp_service->current_event_id = next_event_id; + svc->last_event_id = svc->current_event_id; + svc->current_event_id = next_event_id; next_event_id++; /* update the problem id when transitioning to a problem state */ - if(temp_service->last_state == STATE_OK) { + if (svc->last_state == STATE_OK) { /* don't reset last problem id, or it will be zero the next time a problem is encountered */ - temp_service->current_problem_id = next_problem_id; + svc->current_problem_id = next_problem_id; next_problem_id++; - } + } + + svc->state_type = SOFT_STATE; + + state_or_type_change = TRUE; + } + + if (hard_state_change == TRUE) { + + svc->last_hard_state_change = svc->last_check; + svc->last_state_change = svc->last_check; + svc->last_hard_state = svc->current_state; + svc->state_type = HARD_STATE; + + state_or_type_change = TRUE; + } + + if (state_or_type_change) { + + /* check if service should go into downtime from flexible downtime */ + if (svc->pending_flex_downtime > 0) { + check_pending_flex_service_downtime(svc); + } + + /* reset notification times and suppression option */ + svc->last_notification = (time_t)0; + svc->next_notification = (time_t)0; + svc->no_more_notifications = FALSE; + + if ((svc->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL && (state_change == TRUE || hard_state_change == FALSE)) + || (svc->acknowledgement_type == ACKNOWLEDGEMENT_STICKY && svc->current_state == STATE_OK)) { + + /* remove any non-persistant comments associated with the ack */ + svc->problem_has_been_acknowledged = FALSE; + svc->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + delete_service_acknowledgement_comments(svc); + } + + svc->should_be_scheduled = TRUE; + + *log_event = TRUE; + *handle_event = TRUE; + } +} +/*****************************************************************************/ +static inline void host_state_or_hard_state_type_change(host * hst, int state_change, int hard_state_change, int * log_event, int * handle_event, int * send_notification) +{ + int state_or_type_change = FALSE; + + /* check if we simulate a hard state change */ + if (hst->check_type == CHECK_TYPE_PASSIVE && passive_host_checks_are_soft == FALSE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Check type passive and passive host checks aren't false\n"); + + if (state_change == TRUE) { + hst->current_attempt = 1; + hard_state_change = TRUE; + } + + hst->state_type = HARD_STATE; + } + + /* update event and problem ids */ + if (state_change == TRUE) { + + hst->last_state_change = hst->last_check; + + /* always update the event id on a state change */ + hst->last_event_id = hst->current_event_id; + hst->current_event_id = next_event_id; + next_event_id++; + + /* update the problem id when transitioning to a problem state */ + if (hst->last_state == HOST_UP) { + /* don't reset last problem id, or it will be zero the next time a problem is encountered */ + hst->current_problem_id = next_problem_id; + next_problem_id++; + } /* clear the problem id when transitioning from a problem state to an OK state */ - if(temp_service->current_state == STATE_OK) { - temp_service->last_problem_id = temp_service->current_problem_id; - temp_service->current_problem_id = 0L; + else { + hst->last_problem_id = hst->current_problem_id; + hst->current_problem_id = 0L; + } + + hst->state_type = SOFT_STATE; + + state_or_type_change = TRUE; + } + + if (hard_state_change == TRUE) { + + hst->last_hard_state_change = hst->last_check; + hst->last_hard_state = hst->current_state; + hst->state_type = HARD_STATE; + + state_or_type_change = TRUE; + + /* this is in the host func, but not the service + because it can easily be missed if a passive check + comes in and passive_host_checks_are_soft == FALSE */ + *send_notification = TRUE; + } + + if (state_or_type_change) { + + /* check if host should go into downtime from flexible downtime */ + check_pending_flex_host_downtime(hst); + + /* reset notification times and suppression option */ + hst->last_notification = (time_t)0; + hst->next_notification = (time_t)0; + hst->no_more_notifications = FALSE; + + if ((hst->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL && (state_change == TRUE || hard_state_change == FALSE)) + || (hst->acknowledgement_type == ACKNOWLEDGEMENT_STICKY && hst->current_state == STATE_OK)) { + + /* remove any non-persistant comments associated with the ack */ + hst->problem_has_been_acknowledged = FALSE; + hst->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + delete_host_acknowledgement_comments(hst); + } + + hst->should_be_scheduled = TRUE; + + *log_event = TRUE; + *handle_event = TRUE; + } +} + +/****************************************************************************** + ******* Logic for setting default state change times, etc. + *****************************************************************************/ +static inline void initialize_last_service_state_change_times(service * svc, host * hst) +{ + /* initialize the last host and service state change times if necessary */ + if (svc->last_state_change == (time_t)0) { + svc->last_state_change = svc->last_check; + } + if (svc->last_hard_state_change == (time_t)0) { + svc->last_hard_state_change = svc->last_check; + } + if (hst->last_state_change == (time_t)0) { + hst->last_state_change = svc->last_check; + } + if (hst->last_hard_state_change == (time_t)0) { + hst->last_hard_state_change = svc->last_check; + } +} +/*****************************************************************************/ +static inline void initialize_last_host_state_change_times(host * hst) +{ + /* initialize last host state change times if necessary */ + if (hst->last_state_change == (time_t)0) { + hst->last_state_change = hst->last_check; + } + if (hst->last_hard_state_change == (time_t)0) { + hst->last_hard_state_change = hst->last_check; + } +} + + +/****************************************************************************** + ******* Logic chunks propagating checks to host parents/children + *****************************************************************************/ +static inline void host_propagate_checks_to_immediate_parents(host * hst, int parent_host_up, time_t current_time) +{ + hostsmember *temp_hostsmember = NULL; + host *parent_host = NULL; + + log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to parent host(s)...\n"); + for(temp_hostsmember = hst->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { + parent_host = temp_hostsmember->host_ptr; + if ((parent_host_up == TRUE && parent_host->current_state == HOST_UP) + || ((parent_host_up == FALSE && parent_host->current_state != HOST_UP))) { + + log_debug_info(DEBUGL_CHECKS, 1, "Check of parent host '%s' queued.\n", parent_host->name); + schedule_host_check(parent_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); + } + } +} +static inline void host_propagate_checks_to_immediate_children(host * hst, int children_none_up, int children_none_unreachable, time_t current_time) +{ + hostsmember *temp_hostsmember = NULL; + host *child_host = NULL; + + log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to child host(s)...\n"); + for(temp_hostsmember = hst->child_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { + child_host = temp_hostsmember->host_ptr; + if ( (children_none_up == TRUE && child_host->current_state != HOST_UP) + || (children_none_unreachable == TRUE && child_host->current_state != HOST_UNREACHABLE)) { + + log_debug_info(DEBUGL_CHECKS, 1, "Check of child host '%s' queued.\n", child_host->name); + schedule_host_check(child_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); + } + } +} + +/****************************************************************************** + ******* Logic chunks propagating dependency checks + *****************************************************************************/ +static inline void service_propagate_dependency_checks(service * svc, time_t current_time) +{ + if (svc->current_attempt == (svc->max_attempts - 1) + && execute_service_checks == TRUE + && enable_predictive_service_dependency_checks == TRUE) { + + servicedependency *temp_dependency = NULL; + service *master_service = NULL; + objectlist *list; + + log_debug_info(DEBUGL_CHECKS, 1, "Propagating predictive dependency checks to services this one depends on...\n"); + + /* check services that THIS ONE depends on for notification AND execution */ + /* we do this because we might be sending out a notification soon and we want the dependency logic to be accurate */ + for(list = svc->exec_deps; list; list = list->next) { + temp_dependency = (servicedependency *)list->object_ptr; + if (temp_dependency->dependent_service_ptr == svc && temp_dependency->master_service_ptr != NULL) { + + master_service = (service *)temp_dependency->master_service_ptr; + + log_debug_info(DEBUGL_CHECKS, 2, "Predictive check of service '%s' on host '%s' queued.\n", master_service->description, master_service->host_name); + schedule_service_check(master_service, current_time, CHECK_OPTION_DEPENDENCY_CHECK); } } + for(list = svc->notify_deps; list; list = list->next) { + temp_dependency = (servicedependency *)list->object_ptr; + if (temp_dependency->dependent_service_ptr == svc && temp_dependency->master_service_ptr != NULL) { - /**************************************/ - /******* SERVICE CHECK OK LOGIC *******/ - /**************************************/ + master_service = (service *)temp_dependency->master_service_ptr; - /* if the service is up and running OK... */ - if(temp_service->current_state == STATE_OK) { + log_debug_info(DEBUGL_CHECKS, 2, "Predictive check of service '%s' on host '%s' queued.\n", master_service->description, master_service->host_name); + schedule_service_check(master_service, current_time, CHECK_OPTION_DEPENDENCY_CHECK); + } + } + } +} +/*****************************************************************************/ +static inline void host_propagate_dependency_checks(host * hst, time_t current_time) +{ + /* we do to help ensure that the dependency checks are accurate before it comes time to notify */ + if (hst->current_attempt == (hst->max_attempts - 1) + && execute_host_checks == TRUE + && enable_predictive_host_dependency_checks == TRUE) { - log_debug_info(DEBUGL_CHECKS, 1, "Service is OK.\n"); + objectlist *list; + hostdependency *dep = NULL; + host *master_host = NULL; + + log_debug_info(DEBUGL_CHECKS, 1, "Propagating predictive dependency checks to hosts this one depends on...\n"); - /* reset the acknowledgement flag (this should already have been done, but just in case...) */ - temp_service->problem_has_been_acknowledged = FALSE; - temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; + for(list = hst->notify_deps; list; list = list->next) { + dep = (hostdependency *)list->object_ptr; + if (dep->dependent_host_ptr == hst && dep->master_host_ptr != NULL) { - /* verify the route to the host and send out host recovery notifications */ - if(temp_host->current_state != HOST_UP) { + master_host = (host *)dep->master_host_ptr; + + log_debug_info(DEBUGL_CHECKS, 1, "Check of host '%s' queued.\n", master_host->name); + schedule_host_check(master_host, current_time, CHECK_OPTION_NONE); + } + } + + for(list = hst->exec_deps; list; list = list->next) { + dep = (hostdependency *)list->object_ptr; + if (dep->dependent_host_ptr == hst && dep->master_host_ptr != NULL) { + + master_host = (host *)dep->master_host_ptr; + + log_debug_info(DEBUGL_CHECKS, 1, "Check of host '%s' queued.\n", master_host->name); + schedule_host_check(master_host, current_time, CHECK_OPTION_NONE); + } + } + } +} + +/****************************************************************************** + ******* One stop shop for determining if check_result data is valid + *****************************************************************************/ +static inline int is_valid_check_result_data(host * hst, check_result * cr) +{ + if (hst == NULL) { + log_debug_info(DEBUGL_CHECKS, 2, "No host associated with service, bailing!\n"); + return FALSE; + } + + if (cr == NULL) { + log_debug_info(DEBUGL_CHECKS, 2, "No check result specified, bailing!\n"); + return FALSE; + } + + return TRUE; +} +/****************************************************************************** + ********** Fin. ************************************************************ + *****************************************************************************/ + +/* handles asynchronous service check results */ +int handle_async_service_check_result(service *svc, check_result *cr) +{ + time_t current_time = 0L; + time_t next_check = 0L; + time_t preferred_time = 0L; + time_t next_valid_time = 0L; + + int state_change = FALSE; + int hard_state_change = FALSE; + int send_notification = FALSE; + int handle_event = FALSE; + int log_event = FALSE; + int check_host = FALSE; + int update_host_stats = FALSE; + + char * old_plugin_output = NULL; + + host * hst = NULL; + + log_debug_info(DEBUGL_FUNCTIONS, 0, "handle_async_service_check_result()\n"); + + if (svc == NULL) { + log_debug_info(DEBUGL_CHECKS, 2, "No service specified, bailing!\n"); + return ERROR; + } + hst = svc->host_ptr; + if (is_valid_check_result_data(hst, cr) == FALSE) { + return ERROR; + } + + if (cr->check_type == CHECK_TYPE_PASSIVE) { + if (service_is_passive(svc, cr) == FALSE) { + return ERROR; + } + } + else { + service_is_active(svc); + } + + time(¤t_time); + initialize_last_service_state_change_times(svc, hst); + + debug_async_service(svc, cr); + service_fresh_check(svc, cr, current_time); + service_initial_handling(svc, cr, &old_plugin_output); + + /* reschedule the next check at the regular interval - may be overridden */ + next_check = (time_t)(svc->last_check + (svc->check_interval * interval_length)); + + /***********************************************/ + /********** SCHEDULE SERVICE CHECK LOGIC **********/ + /***********************************************/ + if (svc->current_state == STATE_OK) { + + log_debug_info(DEBUGL_CHECKS, 1, "Service is OK\n"); + + if (hst->has_been_checked == FALSE) { + + log_debug_info(DEBUGL_CHECKS, 1, "Host has not been checked yet\n"); + + if (hst->next_check == 0L + || hst->initial_state != HOST_UP + || hst->next_check < hst->check_interval * interval_length + current_time) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service ok, but host hasn't been checked recently, scheduling host check\n"); + + check_host = TRUE; + } + } + + else if (hst->current_state != HOST_UP) { log_debug_info(DEBUGL_CHECKS, 1, "Host is NOT UP, so we'll check it to see if it recovered...\n"); + + if (svc->last_state == STATE_OK + && hst->has_been_checked == TRUE + && current_time - hst->last_check < cached_host_check_horizon) { - if(first_host_check_initiated == TRUE) - log_debug_info(DEBUGL_CHECKS, 1, "First host check was already initiated, so we'll skip a new host check.\n"); - else { - /* can we use the last cached host state? */ - /* usually only use cached host state if no service state change has occurred */ - if(state_change == FALSE && temp_host->has_been_checked == TRUE && ((current_time - temp_host->last_check) <= cached_host_check_horizon)) { - log_debug_info(DEBUGL_CHECKS, 1, "* Using cached host state: %d\n", temp_host->current_state); - update_check_stats(ACTIVE_ONDEMAND_HOST_CHECK_STATS, current_time); - update_check_stats(ACTIVE_CACHED_HOST_CHECK_STATS, current_time); - } + log_debug_info(DEBUGL_CHECKS, 2, "Service ok, but host isn't up (and has been checked). Using cached host data.\n"); - /* else launch an async (parallel) check of the host */ - else - schedule_host_check(temp_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } + update_host_stats = TRUE; + + } else { + + log_debug_info(DEBUGL_CHECKS, 2, "Service ok, but host isn't up and cached data isn't valid here, scheduling host check\n"); + + check_host = TRUE; } - /* if a hard service recovery has occurred... */ - if(hard_state_change == TRUE) { - - log_debug_info(DEBUGL_CHECKS, 1, "Service experienced a HARD RECOVERY.\n"); - - /* set the state type macro */ - temp_service->state_type = HARD_STATE; - - /* log the service recovery */ - log_service_event(temp_service); - state_was_logged = TRUE; - - /* 10/04/07 check to see if the service and/or associate host is flapping */ - /* this should be done before a notification is sent out to ensure the host didn't just start flapping */ - check_for_service_flapping(temp_service, TRUE, TRUE); - check_for_host_flapping(temp_host, TRUE, FALSE, TRUE); - flapping_check_done = TRUE; - - /* notify contacts about the service recovery */ - service_notification(temp_service, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); - - /* run the service event handler to handle the hard state change */ - handle_service_event(temp_service); - } - - /* else if a soft service recovery has occurred... */ - else if(state_change == TRUE) { - - log_debug_info(DEBUGL_CHECKS, 1, "Service experienced a SOFT RECOVERY.\n"); - - /* this is a soft recovery */ - temp_service->state_type = SOFT_STATE; - - /* log the soft recovery */ - log_service_event(temp_service); - state_was_logged = TRUE; - - /* run the service event handler to handle the soft state change */ - handle_service_event(temp_service); - } - - /* else no service state change has occurred... */ - else { - log_debug_info(DEBUGL_CHECKS, 1, "Service did not change state.\n"); - } - - /* should we obsessive over service checks? */ - if(obsess_over_services == TRUE) - obsessive_compulsive_service_check_processor(temp_service); - - /* reset all service variables because its okay now... */ - temp_service->host_problem_at_last_check = FALSE; - temp_service->current_attempt = 1; - temp_service->state_type = HARD_STATE; - temp_service->last_hard_state = STATE_OK; - temp_service->last_notification = (time_t)0; - temp_service->next_notification = (time_t)0; - temp_service->current_notification_number = 0; - temp_service->problem_has_been_acknowledged = FALSE; - temp_service->acknowledgement_type = ACKNOWLEDGEMENT_NONE; - temp_service->notified_on = 0; - - if(reschedule_check == TRUE) - next_service_check = (time_t)(temp_service->last_check + (temp_service->check_interval * interval_length)); + svc->host_problem_at_last_check = TRUE; } - - - /*******************************************/ - /******* SERVICE CHECK PROBLEM LOGIC *******/ - /*******************************************/ - - /* hey, something's not working quite like it should... */ + + } else { log_debug_info(DEBUGL_CHECKS, 1, "Service is in a non-OK state!\n"); - /* check the route to the host if its up right now... */ - if(temp_host->current_state == HOST_UP) { + if (hst->current_state == HOST_UP) { log_debug_info(DEBUGL_CHECKS, 1, "Host is currently UP, so we'll recheck its state to make sure...\n"); - /* only run a new check if we can and have to */ - if(execute_host_checks && state_change == TRUE && temp_host->last_check + cached_host_check_horizon < current_time) { - schedule_host_check(temp_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - else { - log_debug_info(DEBUGL_CHECKS, 1, "* Using cached host state: %d\n", temp_host->current_state); - route_result = temp_host->current_state; - update_check_stats(ACTIVE_ONDEMAND_HOST_CHECK_STATS, current_time); - update_check_stats(ACTIVE_CACHED_HOST_CHECK_STATS, current_time); - } + if (execute_host_checks == TRUE + && svc->last_state != svc->current_state + && hst->last_check + cached_host_check_horizon < current_time) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service not ok, host is up but cached data isn't valid, scheduling host check\n"); + + check_host = TRUE; + + } else { + + log_debug_info(DEBUGL_CHECKS, 2, "Service not ok, host is up, using cached host data\n"); + + update_host_stats = TRUE; } - /* else the host is either down or unreachable, so recheck it if necessary */ + /* give the service a chance to recover */ + if (svc->host_problem_at_last_check == TRUE + && svc->state_type == SOFT_STATE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service had a host problem at last check and is SOFT, so we'll reset current_attempt to 1 to give it a chance\n"); + + svc->current_attempt = 1; + } + + svc->host_problem_at_last_check = FALSE; + } else { - log_debug_info(DEBUGL_CHECKS, 1, "Host is currently %s.\n", host_state_name(temp_host->current_state)); + log_debug_info(DEBUGL_CHECKS, 1, "Host is currently not UP...\n"); - if(execute_host_checks && state_change == TRUE) { - schedule_host_check(temp_host, current_time, CHECK_OPTION_NONE); + if (execute_host_checks == FALSE || svc->current_state == svc->last_state) { + + log_debug_info(DEBUGL_CHECKS, 2, "Host checks aren't enabled, so send a notification\n"); + + /* fake a host check */ + if (hst->has_been_checked == FALSE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Host has never been checked, fake a host check\n"); + + hst->has_been_checked = TRUE; + hst->last_check = svc->last_check; } - /* else fake the host check, but (possibly) resend host notifications to contacts... */ - else { - - log_debug_info(DEBUGL_CHECKS, 1, "Assuming host is in same state as before...\n"); - - /* if the host has never been checked before, set the checked flag and last check time */ - /* This probably never evaluates to FALSE, present for historical reasons only, can probably be removed in the future */ - if(temp_host->has_been_checked == FALSE) { - temp_host->has_been_checked = TRUE; - temp_host->last_check = temp_service->last_check; - } - - /* fake the route check result */ - route_result = temp_host->current_state; /* possibly re-send host notifications... */ - host_notification(temp_host, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); - } + host_notification(hst, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); } - /* if the host is down or unreachable ... */ - if(route_result != HOST_UP) { - if (temp_host->state_type == HARD_STATE) { - log_debug_info(DEBUGL_CHECKS, 2, "Host is not UP, so we mark state changes if appropriate\n"); + svc->host_problem_at_last_check = TRUE; + } + } - /* "fake" a hard state change for the service - well, its not really fake, but it didn't get caught earlier... */ - if(temp_service->last_hard_state != temp_service->current_state) - hard_state_change = TRUE; + /* service hard state change, because if host is down/unreachable + the docs say we have a hard state change (but no notification) */ + if (hst->current_state != HOST_UP && svc->last_hard_state != svc->current_state) { - /* update last state change times */ - if(state_change == TRUE || hard_state_change == TRUE) - temp_service->last_state_change = temp_service->last_check; - if(hard_state_change == TRUE) { - temp_service->last_hard_state_change = temp_service->last_check; - temp_service->state_type = HARD_STATE; - temp_service->last_hard_state = temp_service->current_state; - } + log_debug_info(DEBUGL_CHECKS, 2, "Host is down or unreachable, forcing service hard state change\n"); - /* put service into a hard state without attempting check retries and don't send out notifications about it */ - temp_service->host_problem_at_last_check = TRUE; - } - else if (temp_service->last_state == STATE_OK) - temp_service->state_type = SOFT_STATE; - } + hard_state_change = TRUE; + svc->state_type = HARD_STATE; + svc->last_hard_state = svc->current_state; + } - /* the host is up - it recovered since the last time the service was checked... */ - else if(temp_service->host_problem_at_last_check == TRUE) { + if (check_host == TRUE) { + schedule_host_check(hst, current_time, CHECK_OPTION_DEPENDENCY_CHECK); + } - /* next time the service is checked we shouldn't get into this same case... */ - temp_service->host_problem_at_last_check = FALSE; + if (update_host_stats == TRUE) { + update_check_stats(ACTIVE_ONDEMAND_HOST_CHECK_STATS, current_time); + update_check_stats(ACTIVE_CACHED_HOST_CHECK_STATS, current_time); + } - /* reset the current check counter, so we give the service a chance */ - /* this helps prevent the case where service has N max check attempts, N-1 of which have already occurred. */ - /* if we didn't do this, the next check might fail and result in a hard problem - we should really give it more time */ - /* ADDED IF STATEMENT 01-17-05 EG */ - /* 01-17-05: Services in hard problem states before hosts went down would sometimes come back as soft problem states after */ - /* the hosts recovered. This caused problems, so hopefully this will fix it */ - if(temp_service->state_type == SOFT_STATE) - temp_service->current_attempt = 1; - } + /**************************************/ + /******* SERVICE CHECK OK LOGIC *******/ + /**************************************/ + if (svc->last_state == STATE_OK) { - log_debug_info(DEBUGL_CHECKS, 1, "Current/Max Attempt(s): %d/%d\n", temp_service->current_attempt, temp_service->max_attempts); + log_debug_info(DEBUGL_CHECKS, 1, "Service was OK at last check.\n"); - /* if we should retry the service check, do so (except if the host is down or unreachable!) */ - if(temp_service->current_attempt < temp_service->max_attempts) { + /***** SERVICE IS STILL OK *****/ + if (svc->current_state == STATE_OK) { - /* the host is down or unreachable, so don't attempt to retry the service check */ - if(route_result != HOST_UP) { + log_debug_info(DEBUGL_CHECKS, 1, "Service is still OK.\n"); - log_debug_info(DEBUGL_CHECKS, 1, "Host isn't UP, so we won't retry the service check...\n"); + svc->state_type = HARD_STATE; + svc->current_attempt = 1; + } - /* the host is not up, so reschedule the next service check at regular interval */ - if(reschedule_check == TRUE) - next_service_check = (time_t)(temp_service->last_check + (temp_service->check_interval * interval_length)); - - /* log the problem as a hard state if the host just went down */ - if(hard_state_change == TRUE) { - log_service_event(temp_service); - state_was_logged = TRUE; - - /* run the service event handler to handle the hard state */ - handle_service_event(temp_service); - } - } - - /* the host is up, so continue to retry the service check */ - else { - - log_debug_info(DEBUGL_CHECKS, 1, "Host is UP, so we'll retry the service check...\n"); - - /* this is a soft state */ - temp_service->state_type = SOFT_STATE; - - /* log the service check retry */ - log_service_event(temp_service); - state_was_logged = TRUE; - - /* run the service event handler to handle the soft state */ - handle_service_event(temp_service); - - if(reschedule_check == TRUE) - next_service_check = (time_t)(temp_service->last_check + (temp_service->retry_interval * interval_length)); - } - - /* perform dependency checks on the second to last check of the service */ - if(execute_service_checks && enable_predictive_service_dependency_checks == TRUE && temp_service->current_attempt == (temp_service->max_attempts - 1)) { - objectlist *list; - - log_debug_info(DEBUGL_CHECKS, 1, "Looking for services to check for predictive dependency checks...\n"); - - /* check services that THIS ONE depends on for notification AND execution */ - /* we do this because we might be sending out a notification soon and we want the dependency logic to be accurate */ - for(list = temp_service->exec_deps; list; list = list->next) { - temp_dependency = (servicedependency *)list->object_ptr; - if(temp_dependency->dependent_service_ptr == temp_service && temp_dependency->master_service_ptr != NULL) { - master_service = (service *)temp_dependency->master_service_ptr; - log_debug_info(DEBUGL_CHECKS, 2, "Predictive check of service '%s' on host '%s' queued.\n", master_service->description, master_service->host_name); - schedule_service_check(master_service, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - } - for(list = temp_service->notify_deps; list; list = list->next) { - temp_dependency = (servicedependency *)list->object_ptr; - if(temp_dependency->dependent_service_ptr == temp_service && temp_dependency->master_service_ptr != NULL) { - master_service = (service *)temp_dependency->master_service_ptr; - log_debug_info(DEBUGL_CHECKS, 2, "Predictive check of service '%s' on host '%s' queued.\n", master_service->description, master_service->host_name); - schedule_service_check(master_service, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - } - } - } - - - /* we've reached the maximum number of service rechecks, so handle the error */ + /***** SERVICE IS NOW IN PROBLEM STATE *****/ else { - log_debug_info(DEBUGL_CHECKS, 1, "Service has reached max number of rechecks, so we'll handle the error...\n"); + log_debug_info(DEBUGL_CHECKS, 1, "Service is a non-OK state (%s)!\n", service_state_name(svc->current_state)); - /* this is a hard state */ - temp_service->state_type = HARD_STATE; - - /* check for start of flexible (non-fixed) scheduled downtime if we just had a hard error */ - /* we need to check for both, state_change (SOFT) and hard_state_change (HARD) values */ - if((hard_state_change == TRUE || state_change == TRUE) && temp_service->pending_flex_downtime > 0) - check_pending_flex_service_downtime(temp_service); - - /* if we've hard a hard state change... */ - if(hard_state_change == TRUE) { - - /* log the service problem (even if host is not up, which is new in 0.0.5) */ - log_service_event(temp_service); - state_was_logged = TRUE; - } - - /* else log the problem (again) if this service is flagged as being volatile */ - else if(temp_service->is_volatile == TRUE) { - log_service_event(temp_service); - state_was_logged = TRUE; - } - - /* 10/04/07 check to see if the service and/or associate host is flapping */ - /* this should be done before a notification is sent out to ensure the host didn't just start flapping */ - check_for_service_flapping(temp_service, TRUE, TRUE); - check_for_host_flapping(temp_host, TRUE, FALSE, TRUE); - flapping_check_done = TRUE; - - /* (re)send notifications out about this service problem if the host is up (and was at last check also) and the dependencies were okay... */ - service_notification(temp_service, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); - - /* run the service event handler if we changed state from the last hard state or if this service is flagged as being volatile */ - if(hard_state_change == TRUE || temp_service->is_volatile == TRUE) - handle_service_event(temp_service); - - /* save the last hard state */ - temp_service->last_hard_state = temp_service->current_state; - - /* reschedule the next check at the regular interval */ - if(reschedule_check == TRUE) - next_service_check = (time_t)(temp_service->last_check + (temp_service->check_interval * interval_length)); + /* skip this service check if host is down/unreachable and state change happened */ + if (svc->host_problem_at_last_check == FALSE && hard_state_change == FALSE) { + svc->state_type = SOFT_STATE; } + svc->current_attempt = 1; - /* should we obsessive over service checks? */ - if(obsess_over_services == TRUE) - obsessive_compulsive_service_check_processor(temp_service); + handle_event = TRUE; + } + } + + /*******************************************/ + /******* SERVICE CHECK PROBLEM LOGIC *******/ + /*******************************************/ + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Service was NOT OK at last check (%s).\n", service_state_name(svc->last_state)); + + /***** SERVICE IS NOW OK *****/ + if (svc->current_state == STATE_OK) { + + handle_event = TRUE; + + if (svc->state_type == HARD_STATE) { + + log_debug_info(DEBUGL_CHECKS, 1, "Service experienced a HARD recovery.\n"); + + send_notification = TRUE; + } + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Service experienced a SOFT recovery.\n"); + } + + /* there was a state change, soft or hard */ + state_change = TRUE; } - /* reschedule the next service check ONLY for active, scheduled checks */ - if(reschedule_check == TRUE) { + /***** SERVICE IS STILL IN PROBLEM STATE *****/ + else { - log_debug_info(DEBUGL_CHECKS, 1, "Rescheduling next check of service at %s", ctime(&next_service_check)); + log_debug_info(DEBUGL_CHECKS, 1, "Service is still in a non-OK state (%s)!\n", service_state_name(svc->current_state)); - /* default is to reschedule service check unless a test below fails... */ - temp_service->should_be_scheduled = TRUE; + if (svc->state_type == SOFT_STATE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service state type is soft, using retry_interval\n"); + + handle_event = TRUE; + next_check = (unsigned long) (current_time + svc->retry_interval * interval_length); + } + + /* check if host is down/unreachable and don't send notifications */ + else if (svc->host_problem_at_last_check == TRUE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service state type is hard, but host is down or unreachable, not sending notification\n"); + + } else { + + log_debug_info(DEBUGL_CHECKS, 2, "Service state type is hard, sending a notification\n"); + + send_notification = TRUE; + } + } + } + + /* soft states should be using retry_interval */ + if (svc->state_type == SOFT_STATE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service state type is soft, using retry_interval\n"); + + next_check = (unsigned long) (current_time + svc->retry_interval * interval_length); + } + + /* check for a state change */ + if (svc->current_state != svc->last_state || (svc->current_state == STATE_OK && svc->state_type == SOFT_STATE)) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service experienced a state change\n"); + + state_change = TRUE; + } + + /* adjust the current attempt */ + if (svc->state_type == SOFT_STATE) { + + /* this has to be first so we don't reset every time a new non-ok state comes + in (and triggers the state_change == TRUE) */ + if (svc->last_state != STATE_OK && svc->current_attempt < svc->max_attempts) { + + svc->current_attempt++; + } + + /* historically, a soft recovery would actually get up to 2 attempts + and then immediately reset once the next check result came in */ + else if (state_change == TRUE && svc->current_state != STATE_OK) { + + svc->current_attempt = 1; + } + + /* otherwise, just increase the attempt */ + else if (svc->current_attempt < svc->max_attempts) { + + svc->current_attempt++; + } + } + + if (svc->current_attempt >= svc->max_attempts && + (svc->current_state != svc->last_hard_state || svc->state_type == SOFT_STATE)) { + + log_debug_info(DEBUGL_CHECKS, 2, "Service had a HARD STATE CHANGE!!\n"); + + next_check = (unsigned long)(current_time + (svc->check_interval * interval_length)); + + /* set both states changed, this may have been missed... */ + hard_state_change = TRUE; + + /* this is missed earlier */ + send_notification = TRUE; + } + + /* handle some acknowledgement things and update last_state_change */ + service_state_or_hard_state_type_change(svc, state_change, hard_state_change, &log_event, &handle_event); + + /* fix edge cases where log_event wouldn't have been set or won't be */ + if (svc->current_state != STATE_OK && svc->state_type == SOFT_STATE) { + log_event = TRUE; + } + + record_last_service_state_ended(svc); + + check_for_service_flapping(svc, TRUE, TRUE); + check_for_host_flapping(hst, TRUE, FALSE, TRUE); + + /* service with active checks disabled do not get rescheduled */ + if (svc->checks_enabled == FALSE) { + svc->should_be_scheduled = FALSE; + } + + /* hosts with non-recurring intervals do not get rescheduled if we're in a HARD or OK state */ + else if (svc->check_interval == 0 && (svc->state_type == HARD_STATE || svc->current_state == STATE_OK)) { + svc->should_be_scheduled = FALSE; + } + + /* schedule a non-forced check if we can */ + else if (svc->should_be_scheduled == TRUE) { + + log_debug_info(DEBUGL_CHECKS, 1, "Rescheduling next check of service at %s", ctime(&next_check)); /* next check time was calculated above */ - temp_service->next_check = next_service_check; - /* make sure we don't get ourselves into too much trouble... */ - if(current_time > temp_service->next_check) - temp_service->next_check = current_time; + if (current_time > next_check) { + svc->next_check = current_time; + } else { + svc->next_check = next_check; + } /* make sure we rescheduled the next service check at a valid time */ - preferred_time = temp_service->next_check; - get_next_valid_time(preferred_time, &next_valid_time, temp_service->check_period_ptr); - temp_service->next_check = next_valid_time; - if(next_valid_time > preferred_time) { - /* Next valid time is further in the future because of timeperiod - * constraints. Add a random amount so we don't get all checks - * subject to that timeperiod constraint scheduled at the same time - */ - temp_service->next_check += - ranged_urand(0, check_window(temp_service)); + preferred_time = svc->next_check; + get_next_valid_time(preferred_time, &next_valid_time, svc->check_period_ptr); + svc->next_check = next_valid_time; + + /* Next valid time is further in the future because of timeperiod + constraints. Add a random amount so we don't get all checks + subject to that timeperiod constraint scheduled at the same time */ + if (next_valid_time > preferred_time) { + svc->next_check += ranged_urand(0, check_window(svc)); } - /* services with non-recurring intervals do not get rescheduled */ - if(temp_service->check_interval == 0) - temp_service->should_be_scheduled = FALSE; + schedule_service_check(svc, svc->next_check, CHECK_OPTION_NONE); + } - /* services with active checks disabled do not get rescheduled */ - if(temp_service->checks_enabled == FALSE) - temp_service->should_be_scheduled = FALSE; + /* volatile service gets everything in non-ok hard state */ + if ((svc->current_state != STATE_OK) + && (svc->state_type == HARD_STATE) + && (svc->is_volatile == TRUE)) { - /* schedule a non-forced check if we can */ - if(temp_service->should_be_scheduled == TRUE) - schedule_service_check(temp_service, temp_service->next_check, CHECK_OPTION_NONE); + log_debug_info(DEBUGL_CHECKS, 2, "Service is volatile, and we're in a non-ok hard state..\n"); + + send_notification = TRUE; + log_event = TRUE; + handle_event = TRUE; + } + + if (send_notification == TRUE) { + + /* send notification */ + if (service_notification(svc, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE) == OK) { + + /* log state due to notification event when stalking_options N is set */ + if (should_stalk_notifications(svc)) { + log_event = TRUE; + } + } + } + + /* the service recovered, so reset the current notification number and state flags (after the recovery notification has gone out) */ + if(svc->current_state == STATE_OK && svc->state_type == HARD_STATE && hard_state_change == TRUE) { + svc->current_notification_number = 0; + svc->notified_on = 0; } - /* if we're stalking this state type and state was not already logged AND the plugin output changed since last check, log it now.. */ - if(temp_service->state_type == HARD_STATE && state_change == FALSE && state_was_logged == FALSE && compare_strings(old_plugin_output, temp_service->plugin_output)) { + if (obsess_over_services == TRUE) { + obsessive_compulsive_service_check_processor(svc); + } - if(should_stalk(temp_service)) - log_service_event(temp_service); + /* if we're stalking this state type AND the plugin output changed since last check, log it now.. */ + if (should_stalk(svc) && compare_strings(old_plugin_output, svc->plugin_output)) { + log_debug_info(DEBUGL_CHECKS, 2, "Logging due to state stalking, old: [%s], new: [%s]\n", old_plugin_output, svc->plugin_output); + log_event = TRUE; + } + + if (log_event == TRUE) { + log_service_event(svc); + } + + if (handle_event == TRUE) { + handle_service_event(svc); + } + + /* Update OK states since they send out a soft alert but then they + switch into a HARD state and reset the attempts */ + if (svc->current_state == STATE_OK && state_change == TRUE) { + + /* Reset attempts and problem state */ + if (hard_state_change == TRUE) { + svc->last_problem_id = svc->current_problem_id; + svc->current_problem_id = 0L; + svc->current_notification_number = 0; + svc->host_problem_at_last_check = FALSE; } + /* Set OK to a hard state */ + svc->last_hard_state_change = svc->last_check; + svc->last_hard_state = svc->current_state; + svc->current_attempt = 1; + svc->state_type = HARD_STATE; + } + + log_debug_info(DEBUGL_CHECKS, 2, + "STATE: %d, TYPE: %s, CUR: %d, MAX: %d, LAST_STATE: %d, LAST_HARD: %d, NOTIFY: %d, LOGGED: %d, HANDLED: %d\n", + svc->current_state, + (svc->state_type == SOFT_STATE) ? "SOFT" : "HARD", + svc->current_attempt, + svc->max_attempts, + svc->last_state, + svc->last_hard_state, + send_notification, + log_event, + handle_event); + #ifdef USE_EVENT_BROKER - /* send data to event broker */ - broker_service_check(NEBTYPE_SERVICECHECK_PROCESSED, NEBFLAG_NONE, NEBATTR_NONE, temp_service, temp_service->check_type, queued_check_result->start_time, queued_check_result->finish_time, NULL, temp_service->latency, temp_service->execution_time, service_check_timeout, queued_check_result->early_timeout, queued_check_result->return_code, NULL, NULL, queued_check_result); + broker_service_check(NEBTYPE_SERVICECHECK_PROCESSED, NEBFLAG_NONE, NEBATTR_NONE, svc, svc->check_type, cr->start_time, cr->finish_time, NULL, svc->latency, svc->execution_time, service_check_timeout, cr->early_timeout, cr->return_code, NULL, NULL, cr); #endif - /* set the checked flag */ - temp_service->has_been_checked = TRUE; + svc->has_been_checked = TRUE; + update_service_status(svc, FALSE); + update_service_performance_data(svc); - /* update the current service status log */ - update_service_status(temp_service, FALSE); - - /* check to see if the service and/or associate host is flapping */ - if(flapping_check_done == FALSE) { - check_for_service_flapping(temp_service, TRUE, TRUE); - check_for_host_flapping(temp_host, TRUE, FALSE, TRUE); - } - - /* update service performance info */ - update_service_performance_data(temp_service); - - /* free allocated memory */ - my_free(temp_plugin_output); my_free(old_plugin_output); return OK; - } - - +} /* schedules an immediate or delayed service check */ -void schedule_service_check(service *svc, time_t check_time, int options) { +inline void schedule_service_check(service *svc, time_t check_time, int options) +{ timed_event *temp_event = NULL; int use_original_event = TRUE; log_debug_info(DEBUGL_FUNCTIONS, 0, "schedule_service_check()\n"); - if(svc == NULL) + if (svc == NULL) return; log_debug_info(DEBUGL_CHECKS, 0, "Scheduling a %s, active check of service '%s' on host '%s' @ %s", (options & CHECK_OPTION_FORCE_EXECUTION) ? "forced" : "non-forced", svc->description, svc->host_name, ctime(&check_time)); /* don't schedule a check if active checks of this service are disabled */ - if(svc->checks_enabled == FALSE && !(options & CHECK_OPTION_FORCE_EXECUTION)) { + if (svc->checks_enabled == FALSE && !(options & CHECK_OPTION_FORCE_EXECUTION)) { log_debug_info(DEBUGL_CHECKS, 0, "Active checks of this service are disabled.\n"); return; - } + } /* we may have to nudge this check a bit */ if (options == CHECK_OPTION_DEPENDENCY_CHECK) { if (svc->last_check + cached_service_check_horizon > check_time) { log_debug_info(DEBUGL_CHECKS, 0, "Last check result is recent enough (%s)", ctime(&svc->last_check)); return; - } } + } /* default is to use the new event */ use_original_event = FALSE; @@ -1087,7 +1677,7 @@ void schedule_service_check(service *svc, time_t check_time, int options) { * If the service already has a check scheduled, * we need to decide which of the events to use */ - if(temp_event != NULL) { + if (temp_event != NULL) { log_debug_info(DEBUGL_CHECKS, 2, "Found another service check event for this service @ %s", ctime(&temp_event->run_time)); @@ -1095,51 +1685,51 @@ void schedule_service_check(service *svc, time_t check_time, int options) { use_original_event = TRUE; /* the original event is a forced check... */ - if((temp_event->event_options & CHECK_OPTION_FORCE_EXECUTION)) { + if ((temp_event->event_options & CHECK_OPTION_FORCE_EXECUTION)) { /* the new event is also forced and its execution time is earlier than the original, so use it instead */ - if((options & CHECK_OPTION_FORCE_EXECUTION) && (check_time < temp_event->run_time)) { + if ((options & CHECK_OPTION_FORCE_EXECUTION) && (check_time < temp_event->run_time)) { use_original_event = FALSE; log_debug_info(DEBUGL_CHECKS, 2, "New service check event is forced and occurs before the existing event, so the new event will be used instead.\n"); - } } + } /* the original event is not a forced check... */ else { /* the new event is a forced check, so use it instead */ - if((options & CHECK_OPTION_FORCE_EXECUTION)) { + if ((options & CHECK_OPTION_FORCE_EXECUTION)) { use_original_event = FALSE; log_debug_info(DEBUGL_CHECKS, 2, "New service check event is forced, so it will be used instead of the existing event.\n"); - } + } /* the new event is not forced either and its execution time is earlier than the original, so use it instead */ - else if(check_time < temp_event->run_time) { + else if (check_time < temp_event->run_time) { use_original_event = FALSE; log_debug_info(DEBUGL_CHECKS, 2, "New service check event occurs before the existing (older) event, so it will be used instead.\n"); - } + } /* the new event is older, so override the existing one */ else { log_debug_info(DEBUGL_CHECKS, 2, "New service check event occurs after the existing event, so we'll ignore it.\n"); - } } } + } /* schedule a new event */ - if(use_original_event == FALSE) { + if (use_original_event == FALSE) { /* make sure we remove the old event from the queue */ - if(temp_event) { + if (temp_event) { remove_event(nagios_squeue, temp_event); - } + } else { /* allocate memory for a new event item */ temp_event = (timed_event *)calloc(1, sizeof(timed_event)); - if(temp_event == NULL) { + if (temp_event == NULL) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of service '%s' on host '%s'!\n", svc->description, svc->host_name); return; - } } + } log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new service check event.\n"); @@ -1161,28 +1751,27 @@ void schedule_service_check(service *svc, time_t check_time, int options) { temp_event->timing_func = NULL; temp_event->compensate_for_time_change = TRUE; add_event(nagios_squeue, temp_event); - } + } else { /* reset the next check time (it may be out of sync) */ - if(temp_event != NULL) + if (temp_event != NULL) { svc->next_check = temp_event->run_time; + } log_debug_info(DEBUGL_CHECKS, 2, "Keeping original service check event (ignoring the new one).\n"); - } + } /* update the status log */ update_service_status(svc, FALSE); - - return; - } +} /* checks viability of performing a service check */ -int check_service_check_viability(service *svc, int check_options, int *time_is_valid, time_t *new_time) { - int result = OK; +inline int check_service_check_viability(service *svc, int check_options, int *time_is_valid, time_t *new_time) +{ int perform_check = TRUE; time_t current_time = 0L; time_t preferred_time = 0L; @@ -1192,14 +1781,17 @@ int check_service_check_viability(service *svc, int check_options, int *time_is_ log_debug_info(DEBUGL_FUNCTIONS, 0, "check_service_check_viability()\n"); /* make sure we have a service */ - if(svc == NULL) + if (svc == NULL) { return ERROR; + } /* get the check interval to use if we need to reschedule the check */ - if(svc->state_type == SOFT_STATE && svc->current_state != STATE_OK) + if (svc->state_type == SOFT_STATE && svc->current_state != STATE_OK) { check_interval = (svc->retry_interval * interval_length); - else + } + else { check_interval = (svc->check_interval * interval_length); + } /* get the current time */ time(¤t_time); @@ -1208,64 +1800,76 @@ int check_service_check_viability(service *svc, int check_options, int *time_is_ preferred_time = current_time; /* can we check the host right now? */ - if(!(check_options & CHECK_OPTION_FORCE_EXECUTION)) { + if (!(check_options & CHECK_OPTION_FORCE_EXECUTION)) { /* if checks of the service are currently disabled... */ - if(svc->checks_enabled == FALSE) { + if (svc->checks_enabled == FALSE) { preferred_time = current_time + check_interval; perform_check = FALSE; log_debug_info(DEBUGL_CHECKS, 2, "Active checks of the service are currently disabled.\n"); - } + } /* make sure this is a valid time to check the service */ - if(check_time_against_period((unsigned long)current_time, svc->check_period_ptr) == ERROR) { + if (check_time_against_period((unsigned long)current_time, svc->check_period_ptr) == ERROR) { preferred_time = current_time; - if(time_is_valid) + if (time_is_valid) { *time_is_valid = FALSE; + } perform_check = FALSE; log_debug_info(DEBUGL_CHECKS, 2, "This is not a valid time for this service to be actively checked.\n"); - } + } /* check service dependencies for execution */ - if(check_service_dependencies(svc, EXECUTION_DEPENDENCY) == DEPENDENCIES_FAILED) { + if (check_service_dependencies(svc, EXECUTION_DEPENDENCY) == DEPENDENCIES_FAILED) { preferred_time = current_time + check_interval; perform_check = FALSE; - - log_debug_info(DEBUGL_CHECKS, 2, "Execution dependencies for this service failed, so it will not be actively checked.\n"); + if (service_skip_check_dependency_status >= 0) { + svc->current_state = service_skip_check_dependency_status; } + log_debug_info(DEBUGL_CHECKS, 2, "Execution dependencies for this service failed, so it will not be actively checked.\n"); } + } - /* check if parent service is OK */ - if(check_service_parents(svc) == DEPENDENCIES_FAILED) { - preferred_time = current_time + check_interval; - perform_check = FALSE; - log_debug_info(DEBUGL_CHECKS, 2, "Execution parents for this service failed, so it will not be actively checked.\n"); + /* check if parent service is OK */ + if (check_service_parents(svc) == DEPENDENCIES_FAILED) { + preferred_time = current_time + check_interval; + perform_check = FALSE; + if (service_skip_check_parent_status >= 0) { + svc->current_state = service_skip_check_parent_status; } + log_debug_info(DEBUGL_CHECKS, 2, "Execution parents for this service failed, so it will not be actively checked.\n"); + } - /* check if host is up - if not, do not perform check */ - if(host_down_disable_service_checks) { - if((temp_host = svc->host_ptr) == NULL) { - log_debug_info(DEBUGL_CHECKS, 2, "Host pointer NULL in check_service_check_viability().\n"); - return ERROR; - } else { - if(temp_host->current_state != HOST_UP) { - log_debug_info(DEBUGL_CHECKS, 2, "Host state not UP, so service check will not be performed - will be rescheduled as normal.\n"); - perform_check = FALSE; + /* check if host is up - if not, do not perform check */ + if (host_down_disable_service_checks) { + if ((temp_host = svc->host_ptr) == NULL) { + log_debug_info(DEBUGL_CHECKS, 2, "Host pointer NULL in check_service_check_viability().\n"); + return ERROR; + } + else { + if (temp_host->current_state != HOST_UP) { + log_debug_info(DEBUGL_CHECKS, 2, "Host state not UP, so service check will not be performed - will be rescheduled as normal.\n"); + perform_check = FALSE; + if (service_skip_check_host_down_status >= 0) { + svc->current_state = service_skip_check_host_down_status; } } } + } /* pass back the next viable check time */ - if(new_time) + if (new_time) { *new_time = preferred_time; - - result = (perform_check == TRUE) ? OK : ERROR; - - return result; } + if (perform_check == TRUE) { + return OK; + } + return ERROR; +} + /* checks service parents */ @@ -1281,7 +1885,7 @@ int check_service_parents(service *svc) service *parent_service; /* find the service we depend on... */ - if((parent_service = temp_servicesmember->service_ptr) == NULL) { + if ((parent_service = temp_servicesmember->service_ptr) == NULL) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: service '%s' on host '%s' is NULL ptr\n", temp_servicesmember->service_description, temp_servicesmember->host_name); continue; @@ -1290,10 +1894,10 @@ int check_service_parents(service *svc) state = parent_service->last_hard_state; /* is the service we depend on in a state that fails the dependency tests? */ - if((state == STATE_CRITICAL) || (state == STATE_UNKNOWN)) + if ((state == STATE_CRITICAL) || (state == STATE_UNKNOWN)) return DEPENDENCIES_FAILED; - if(check_service_parents(parent_service) != DEPENDENCIES_OK) + if (check_service_parents(parent_service) != DEPENDENCIES_OK) return DEPENDENCIES_FAILED; } @@ -1303,7 +1907,8 @@ int check_service_parents(service *svc) /* checks service dependencies */ -int check_service_dependencies(service *svc, int dependency_type) { +int check_service_dependencies(service *svc, int dependency_type) +{ objectlist *list; int state = STATE_OK; time_t current_time = 0L; @@ -1312,7 +1917,7 @@ int check_service_dependencies(service *svc, int dependency_type) { log_debug_info(DEBUGL_FUNCTIONS, 0, "check_service_dependencies()\n"); /* only check dependencies of the desired type */ - if(dependency_type == NOTIFICATION_DEPENDENCY) + if (dependency_type == NOTIFICATION_DEPENDENCY) list = svc->notify_deps; else list = svc->exec_deps; @@ -1323,38 +1928,47 @@ int check_service_dependencies(service *svc, int dependency_type) { servicedependency *temp_dependency = (servicedependency *)list->object_ptr; /* find the service we depend on... */ - if((temp_service = temp_dependency->master_service_ptr) == NULL) + if ((temp_service = temp_dependency->master_service_ptr) == NULL) { continue; + } /* skip this dependency if it has a timeperiod and the current time isn't valid */ time(¤t_time); - if(temp_dependency->dependency_period != NULL && check_time_against_period(current_time, temp_dependency->dependency_period_ptr) == ERROR) + if (temp_dependency->dependency_period != NULL + && (check_time_against_period(current_time, temp_dependency->dependency_period_ptr) == ERROR)) { + return FALSE; + } /* get the status to use (use last hard state if its currently in a soft state) */ - if(temp_service->state_type == SOFT_STATE && soft_state_dependencies == FALSE) + if (temp_service->state_type == SOFT_STATE && soft_state_dependencies == FALSE) { state = temp_service->last_hard_state; - else + } + else { state = temp_service->current_state; + } /* is the service we depend on in state that fails the dependency tests? */ - if(flag_isset(temp_dependency->failure_options, 1 << state)) + if (flag_isset(temp_dependency->failure_options, 1 << state)) { return DEPENDENCIES_FAILED; + } /* immediate dependencies ok at this point - check parent dependencies if necessary */ - if(temp_dependency->inherits_parent == TRUE) { - if(check_service_dependencies(temp_service, dependency_type) != DEPENDENCIES_OK) + if (temp_dependency->inherits_parent == TRUE) { + if (check_service_dependencies(temp_service, dependency_type) != DEPENDENCIES_OK) { return DEPENDENCIES_FAILED; } } + } return DEPENDENCIES_OK; - } +} /* check for services that never returned from a check... */ -void check_for_orphaned_services(void) { +void check_for_orphaned_services(void) +{ service *temp_service = NULL; time_t current_time = 0L; time_t expected_time = 0L; @@ -1369,14 +1983,15 @@ void check_for_orphaned_services(void) { for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) { /* skip services that are not currently executing */ - if(temp_service->is_executing == FALSE) + if (temp_service->is_executing == FALSE) { continue; + } /* determine the time at which the check results should have come in (allow 10 minutes slack time) */ expected_time = (time_t)(temp_service->next_check + temp_service->latency + service_check_timeout + check_reaper_interval + 600); /* this service was supposed to have executed a while ago, but for some reason the results haven't come back in... */ - if(expected_time < current_time) { + if (expected_time < current_time) { /* log a warning */ logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: The check of service '%s' on host '%s' looks like it was orphaned (results never came back; last_check=%lu; next_check=%lu). I'm scheduling an immediate check of the service...\n", temp_service->description, temp_service->host_name, temp_service->last_check, temp_service->next_check); @@ -1387,25 +2002,27 @@ void check_for_orphaned_services(void) { temp_service->last_check, ctime(&temp_service->last_check)); /* decrement the number of running service checks */ - if(currently_running_service_checks > 0) + if (currently_running_service_checks > 0) { currently_running_service_checks--; + } /* disable the executing flag */ temp_service->is_executing = FALSE; /* schedule an immediate check of the service */ schedule_service_check(temp_service, current_time, CHECK_OPTION_ORPHAN_CHECK); - } - } - return; } + return; +} + /* check freshness of service results */ -void check_service_result_freshness(void) { +void check_service_result_freshness(void) +{ service *temp_service = NULL; time_t current_time = 0L; @@ -1414,10 +2031,10 @@ void check_service_result_freshness(void) { log_debug_info(DEBUGL_CHECKS, 1, "Checking the freshness of service check results...\n"); /* bail out if we're not supposed to be checking freshness */ - if(check_service_freshness == FALSE) { + if (check_service_freshness == FALSE) { log_debug_info(DEBUGL_CHECKS, 1, "Service freshness checking is disabled.\n"); return; - } + } /* get the current time */ time(¤t_time); @@ -1426,49 +2043,56 @@ void check_service_result_freshness(void) { for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) { /* skip services we shouldn't be checking for freshness */ - if(temp_service->check_freshness == FALSE) + if (temp_service->check_freshness == FALSE) { continue; + } /* skip services that are currently executing (problems here will be caught by orphaned service check) */ - if(temp_service->is_executing == TRUE) + if (temp_service->is_executing == TRUE) { continue; + } /* skip services that have both active and passive checks disabled */ - if(temp_service->checks_enabled == FALSE && temp_service->accept_passive_checks == FALSE) + if (temp_service->checks_enabled == FALSE && temp_service->accept_passive_checks == FALSE) { continue; + } /* skip services that are already being freshened */ - if(temp_service->is_being_freshened == TRUE) + if (temp_service->is_being_freshened == TRUE) { continue; + } /* see if the time is right... */ - if(check_time_against_period(current_time, temp_service->check_period_ptr) == ERROR) + if (check_time_against_period(current_time, temp_service->check_period_ptr) == ERROR) { continue; + } /* EXCEPTION */ /* don't check freshness of services without regular check intervals if we're using auto-freshness threshold */ - if(temp_service->check_interval == 0 && temp_service->freshness_threshold == 0) + if ((temp_service->check_interval == 0) && (temp_service->freshness_threshold == 0)) { continue; + } /* the results for the last check of this service are stale! */ - if(is_service_result_fresh(temp_service, current_time, TRUE) == FALSE) { + if (is_service_result_fresh(temp_service, current_time, TRUE) == FALSE) { /* set the freshen flag */ temp_service->is_being_freshened = TRUE; /* schedule an immediate forced check of the service */ schedule_service_check(temp_service, current_time, CHECK_OPTION_FORCE_EXECUTION | CHECK_OPTION_FRESHNESS_CHECK); - } - } - return; } + return; +} + /* tests whether or not a service's check results are fresh */ -int is_service_result_fresh(service *temp_service, time_t current_time, int log_this) { +int is_service_result_fresh(service *temp_service, time_t current_time, int log_this) +{ int freshness_threshold = 0; time_t expiration_time = 0L; int days = 0; @@ -1483,14 +2107,17 @@ int is_service_result_fresh(service *temp_service, time_t current_time, int log_ log_debug_info(DEBUGL_CHECKS, 2, "Checking freshness of service '%s' on host '%s'...\n", temp_service->description, temp_service->host_name); /* use user-supplied freshness threshold or auto-calculate a freshness threshold to use? */ - if(temp_service->freshness_threshold == 0) { - if(temp_service->state_type == HARD_STATE || temp_service->current_state == STATE_OK) + if (temp_service->freshness_threshold == 0) { + if (temp_service->state_type == HARD_STATE || temp_service->current_state == STATE_OK) { freshness_threshold = (temp_service->check_interval * interval_length) + temp_service->latency + additional_freshness_latency; - else + } + else { freshness_threshold = (temp_service->retry_interval * interval_length) + temp_service->latency + additional_freshness_latency; } - else + } + else { freshness_threshold = temp_service->freshness_threshold; + } log_debug_info(DEBUGL_CHECKS, 2, "Freshness thresholds: service=%d, use=%d\n", temp_service->freshness_threshold, freshness_threshold); @@ -1506,8 +2133,9 @@ int is_service_result_fresh(service *temp_service, time_t current_time, int log_ * passive checks also become stale, so remove dependence on active * check logic */ - if(temp_service->has_been_checked == FALSE) + if (temp_service->has_been_checked == FALSE) { expiration_time = (time_t)(event_start + freshness_threshold); + } /* * CHANGED 06/19/07 EG - * Per Ton's suggestion (and user requests), only use program start @@ -1525,10 +2153,15 @@ int is_service_result_fresh(service *temp_service, time_t current_time, int log_ * Added max_service_check_spread to expiration time as suggested * by Altinity */ - else if(temp_service->checks_enabled == TRUE && event_start > temp_service->last_check && temp_service->freshness_threshold == 0) + else if ((temp_service->checks_enabled == TRUE) + && (event_start > temp_service->last_check) + && (temp_service->freshness_threshold == 0)) { + expiration_time = (time_t)(event_start + freshness_threshold + (max_service_check_spread * interval_length)); - else + } + else { expiration_time = (time_t)(temp_service->last_check + freshness_threshold); + } /* * If the check was last done passively, we assume it's going @@ -1540,130 +2173,431 @@ int is_service_result_fresh(service *temp_service, time_t current_time, int log_ * freshness threshold based on vast heuristical research (ie, "some * guy once told me the golden ratio is good for loads of stuff"). */ - if (temp_service->check_type == CHECK_TYPE_PASSIVE) { - if (temp_service->last_check < event_start && - event_start - last_program_stop > freshness_threshold * 0.618) - { - expiration_time = event_start + freshness_threshold; - } + if ((temp_service->check_type == CHECK_TYPE_PASSIVE) + && (temp_service->last_check < event_start) + && (event_start - last_program_stop > freshness_threshold * 0.618)) { + + expiration_time = event_start + freshness_threshold; } log_debug_info(DEBUGL_CHECKS, 2, "HBC: %d, PS: %lu, ES: %lu, LC: %lu, CT: %lu, ET: %lu\n", temp_service->has_been_checked, (unsigned long)program_start, (unsigned long)event_start, (unsigned long)temp_service->last_check, (unsigned long)current_time, (unsigned long)expiration_time); /* the results for the last check of this service are stale */ - if(expiration_time < current_time) { + if (expiration_time < current_time) { get_time_breakdown((current_time - expiration_time), &days, &hours, &minutes, &seconds); get_time_breakdown(freshness_threshold, &tdays, &thours, &tminutes, &tseconds); /* log a warning */ - if(log_this == TRUE) + if (log_this == TRUE) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: The results of service '%s' on host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). I'm forcing an immediate check of the service.\n", temp_service->description, temp_service->host_name, days, hours, minutes, seconds, tdays, thours, tminutes, tseconds); + } log_debug_info(DEBUGL_CHECKS, 1, "Check results for service '%s' on host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). Forcing an immediate check of the service...\n", temp_service->description, temp_service->host_name, days, hours, minutes, seconds, tdays, thours, tminutes, tseconds); return FALSE; - } + } log_debug_info(DEBUGL_CHECKS, 1, "Check results for service '%s' on host '%s' are fresh.\n", temp_service->description, temp_service->host_name); return TRUE; +} + + +int handle_async_host_check_result(host *hst, check_result *cr) +{ + time_t current_time = 0L; + time_t next_check = 0L; + time_t preferred_time = 0L; + time_t next_valid_time = 0L; + + int state_change = FALSE; + int hard_state_change = FALSE; + int send_notification = FALSE; + int handle_event = FALSE; + int log_event = FALSE; + + char * old_plugin_output = NULL; + + log_debug_info(DEBUGL_FUNCTIONS, 0, "handle_async_host_check_result()\n"); + + if (is_valid_check_result_data(hst, cr) == FALSE) { + return ERROR; } + if (cr->check_type == CHECK_TYPE_PASSIVE) { + if (host_is_passive(hst, cr) == FALSE) { + return ERROR; + } + } + else { + host_is_active(hst); + } + time(¤t_time); + initialize_last_host_state_change_times(hst); + debug_async_host(hst, cr); + host_fresh_check(hst, cr, current_time); + host_initial_handling(hst, cr, &old_plugin_output); + /* reschedule the next check at the regular interval - may be overridden */ + next_check = (time_t)(hst->last_check + (hst->check_interval * interval_length)); + + /**************************************/ + /********* HOST CHECK OK LOGIC ********/ + /**************************************/ + if (hst->last_state == HOST_UP) { + + log_debug_info(DEBUGL_CHECKS, 1, "Host was UP.\n"); + + /***** HOST IS STILL UP *****/ + if (hst->current_state == HOST_UP) { + + log_debug_info(DEBUGL_CHECKS, 1, "Host is still UP.\n"); + + hst->state_type = HARD_STATE; + hst->current_attempt = 1; + } + + /***** HOST IS NOW DOWN/UNREACHABLE *****/ + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Host is no longer UP (%s)!\n", host_state_name(hst->current_state)); + + hst->state_type = SOFT_STATE; + hst->current_attempt = 1; + + /* propagate checks to immediate parents if they are UP */ + host_propagate_checks_to_immediate_parents(hst, FALSE, current_time); + + /* propagate checks to immediate children if they are not UNREACHABLE */ + host_propagate_checks_to_immediate_children(hst, FALSE, TRUE, current_time); + + /* propagate checks to hosts that THIS ONE depends on for notifications AND execution */ + host_propagate_dependency_checks(hst, current_time); + + /* we need to handle this event */ + handle_event = TRUE; + } + } + + /**************************************/ + /****** HOST CHECK PROBLEM LOGIC ******/ + /**************************************/ + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Host was not UP last time.\n"); + + /***** HOST IS NOW UP *****/ + if (hst->current_state == HOST_UP) { + + log_debug_info(DEBUGL_CHECKS, 1, "Host is UP now.\n"); + + /* propagate checks to immediate parents if they are not UP */ + host_propagate_checks_to_immediate_parents(hst, TRUE, current_time); + + /* propagate checks to immediate children if they are not UP */ + host_propagate_checks_to_immediate_children(hst, TRUE, FALSE, current_time); + + /* we need to handle this event */ + handle_event = TRUE; + + /* but a soft recovery is not something we notify for */ + if (hst->state_type == HARD_STATE) { + + log_debug_info(DEBUGL_CHECKS, 1, "Host experienced a HARD recovery.\n"); + + send_notification = TRUE; + hard_state_change = TRUE; + + hst->current_attempt = 1; + } + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Host experienced a SOFT recovery.\n"); + } + } + + /***** HOST IS STILL DOWN/UNREACHABLE *****/ + else { + + log_debug_info(DEBUGL_CHECKS, 1, "Host is still not UP (%s)!\n", host_state_name(hst->current_state)); + + if (hst->state_type == SOFT_STATE) { + + log_debug_info(DEBUGL_CHECKS, 2, "Host state type is soft, using retry_interval\n"); + + handle_event = TRUE; + next_check = (unsigned long) (current_time + hst->retry_interval * interval_length); + } + + /* if the state_type is hard, then send a notification */ + else { + + log_debug_info(DEBUGL_CHECKS, 2, "Host state type is hard, sending a notification\n"); + + send_notification = TRUE; + } + } + } + + /* translate host state between DOWN/UNREACHABLE (only for passive checks if enabled) */ + if (hst->current_state != HOST_UP && (hst->check_type == CHECK_TYPE_ACTIVE || translate_passive_host_checks == TRUE)) { + + hst->current_state = determine_host_reachability(hst); + if (hst->state_type == SOFT_STATE) + next_check = (unsigned long)(current_time + (hst->retry_interval * interval_length)); + + } + + /* check for state change */ + if (hst->current_state != hst->last_state || (hst->current_state == HOST_UP && hst->state_type == SOFT_STATE)) { + + log_debug_info(DEBUGL_CHECKS, 2, "Host experienced a state change\n"); + + state_change = TRUE; + } + + /* adjust the current attempt */ + if (hst->state_type == SOFT_STATE) { + + /* this is an edge case for non-up states, it needs to be checked first */ + if (hst->last_state != HOST_UP && hst->current_state != HOST_UP && hst->current_attempt < hst->max_attempts) { + hst->current_attempt++; + } + + /* reset it to 1 */ + else if (state_change == TRUE || hst->current_state == HOST_UP) { + hst->current_attempt = 1; + } + + /* or increment if we can */ + else if (hst->current_attempt < hst->max_attempts) { + hst->current_attempt++; + } + } + + if (hst->current_attempt >= hst->max_attempts && hst->current_state != hst->last_hard_state) { + + log_debug_info(DEBUGL_CHECKS, 2, "Host had a HARD STATE CHANGE!!\n"); + + next_check = (unsigned long)(current_time + (hst->check_interval * interval_length)); + + hard_state_change = TRUE; + send_notification = TRUE; + } + + /* handle some acknowledgement things and update last_state_change */ + host_state_or_hard_state_type_change(hst, state_change, hard_state_change, &log_event, &handle_event, &send_notification); + + record_last_host_state_ended(hst); + + check_for_host_flapping(hst, TRUE, TRUE, TRUE); + + /* host with active checks disabled do not get rescheduled */ + if (hst->checks_enabled == FALSE) { + hst->should_be_scheduled = FALSE; + } + + /* hosts with non-recurring intervals do not get rescheduled if we're in a HARD or UP state */ + else if (hst->check_interval == 0 && (hst->state_type == HARD_STATE || hst->current_state == HOST_UP)) { + hst->should_be_scheduled = FALSE; + } + + /* schedule a non-forced check if we can */ + else if (hst->should_be_scheduled == TRUE) { + + log_debug_info(DEBUGL_CHECKS, 1, "Rescheduling next check of host at %s", ctime(&next_check)); + + /* next check time was calculated above */ + /* make sure we don't get ourselves into too much trouble... */ + if (current_time > next_check) { + hst->next_check = current_time; + } else { + hst->next_check = next_check; + } + + /* make sure we rescheduled the next service check at a valid time */ + preferred_time = hst->next_check; + get_next_valid_time(preferred_time, &next_valid_time, hst->check_period_ptr); + hst->next_check = next_valid_time; + + /* Next valid time is further in the future because of timeperiod + constraints. Add a random amount so we don't get all checks + subject to that timeperiod constraint scheduled at the same time */ + if (next_valid_time > preferred_time) { + hst->next_check += ranged_urand(0, check_window(hst)); + } + + schedule_host_check(hst, hst->next_check, CHECK_OPTION_NONE); + } + + if (hst->current_attempt == HOST_UP) { + hst->current_attempt = 1; + } + + if (send_notification == TRUE) { + + /* send notifications */ + if (host_notification(hst, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE) == OK) { + + /* log state due to notification event when stalking_options N is set */ + if (should_stalk_notifications(hst)) { + log_event = TRUE; + } + } + } + + /* the host recovered, so reset the current notification number and state flags (after the recovery notification has gone out) */ + if(hst->current_state == HOST_UP && hst->state_type == HARD_STATE && hard_state_change == TRUE) { + hst->current_notification_number = 0; + hst->notified_on = 0; + } + + if (obsess_over_hosts == TRUE) { + obsessive_compulsive_host_check_processor(hst); + } + + /* if we're stalking this state type AND the plugin output changed since last check, log it now.. */ + if (should_stalk(hst) && compare_strings(old_plugin_output, hst->plugin_output)) { + log_event = TRUE; + } + + /* if log_host_retries is set to true, we have to log soft states too */ + if (hst->state_type == SOFT_STATE && log_host_retries == TRUE) { + log_event = TRUE; + } + + if (log_event == TRUE) { + log_host_event(hst); + } + + if (handle_event == TRUE) { + handle_host_event(hst); + } + + log_debug_info(DEBUGL_CHECKS, 2, + "STATE: %d, TYPE: %s, CUR: %d, MAX: %d, LAST_STATE: %d, LAST_HARD: %d, NOTIFY: %d, LOGGED: %d, HANDLED: %d\n", + hst->current_state, + (hst->state_type == SOFT_STATE) ? "SOFT" : "HARD", + hst->current_attempt, + hst->max_attempts, + hst->last_state, + hst->last_hard_state, + send_notification, + log_event, + handle_event); + +#ifdef USE_EVENT_BROKER + broker_host_check(NEBTYPE_HOSTCHECK_PROCESSED, NEBFLAG_NONE, NEBATTR_NONE, hst, hst->check_type, hst->current_state, hst->state_type, cr->start_time, cr->finish_time, hst->check_command, hst->latency, hst->execution_time, host_check_timeout, cr->early_timeout, cr->return_code, NULL, hst->plugin_output, hst->long_plugin_output, hst->perf_data, NULL, cr); +#endif + + hst->has_been_checked = TRUE; + update_host_status(hst, FALSE); + update_host_performance_data(hst); + + /* free memory */ + my_free(old_plugin_output); + + return OK; +} /******************************************************************/ /*************** COMMON ROUTE/HOST CHECK FUNCTIONS ****************/ /******************************************************************/ /* schedules an immediate or delayed host check */ -void schedule_host_check(host *hst, time_t check_time, int options) { +inline void schedule_host_check(host *hst, time_t check_time, int options) +{ timed_event *temp_event = NULL; + + /* use the originally scheduled check unless we decide otherwise */ int use_original_event = TRUE; log_debug_info(DEBUGL_FUNCTIONS, 0, "schedule_host_check()\n"); - if(hst == NULL) + + if (hst == NULL) { return; - - log_debug_info(DEBUGL_CHECKS, 0, "Scheduling a %s, active check of host '%s' @ %s", (options & CHECK_OPTION_FORCE_EXECUTION) ? "forced" : "non-forced", hst->name, ctime(&check_time)); - - /* don't schedule a check if active checks of this host are disabled */ - if(hst->checks_enabled == FALSE && !(options & CHECK_OPTION_FORCE_EXECUTION)) { - log_debug_info(DEBUGL_CHECKS, 0, "Active checks are disabled for this host.\n"); - return; - } - - if (options == CHECK_OPTION_DEPENDENCY_CHECK) { - if (hst->last_check + cached_host_check_horizon > check_time) { - log_debug_info(DEBUGL_CHECKS, 0, "Last check result is recent enough (%s)\n", ctime(&hst->last_check)); - return; - } } - /* default is to use the new event */ - use_original_event = FALSE; + log_debug_info(DEBUGL_CHECKS, 0, "Scheduling a %s, active check of host '%s' @ %s", + (options & CHECK_OPTION_FORCE_EXECUTION) ? "forced" : "non-forced", + hst->name, + ctime(&check_time)); + + /* don't schedule a check if active checks of this host are disabled */ + if (hst->checks_enabled == FALSE && !(options & CHECK_OPTION_FORCE_EXECUTION)) { + log_debug_info(DEBUGL_CHECKS, 0, "Active checks are disabled for this host.\n"); + return; + } + + if ((options == CHECK_OPTION_DEPENDENCY_CHECK) + && (hst->last_check + cached_host_check_horizon > check_time)) { + + log_debug_info(DEBUGL_CHECKS, 0, "Last check result is recent enough (%s)\n", ctime(&hst->last_check)); + return; + } temp_event = (timed_event *)hst->next_check_event; + if (temp_event == NULL) { + use_original_event = FALSE; + } + /* * If the host already had a check scheduled we need * to decide which check event to use */ - if(temp_event != NULL) { + else { log_debug_info(DEBUGL_CHECKS, 2, "Found another host check event for this host @ %s", ctime(&temp_event->run_time)); - /* use the originally scheduled check unless we decide otherwise */ - use_original_event = TRUE; - /* the original event is a forced check... */ - if((temp_event->event_options & CHECK_OPTION_FORCE_EXECUTION)) { + if ((temp_event->event_options & CHECK_OPTION_FORCE_EXECUTION)) { /* the new event is also forced and its execution time is earlier than the original, so use it instead */ - if((options & CHECK_OPTION_FORCE_EXECUTION) && (check_time < temp_event->run_time)) { + if ((options & CHECK_OPTION_FORCE_EXECUTION) && (check_time < temp_event->run_time)) { log_debug_info(DEBUGL_CHECKS, 2, "New host check event is forced and occurs before the existing event, so the new event be used instead.\n"); use_original_event = FALSE; - } } + } /* the original event is not a forced check... */ else { /* the new event is a forced check, so use it instead */ - if((options & CHECK_OPTION_FORCE_EXECUTION)) { - use_original_event = FALSE; + if ((options & CHECK_OPTION_FORCE_EXECUTION)) { log_debug_info(DEBUGL_CHECKS, 2, "New host check event is forced, so it will be used instead of the existing event.\n"); - } + use_original_event = FALSE; + } /* the new event is not forced either and its execution time is earlier than the original, so use it instead */ - else if(check_time < temp_event->run_time) { - use_original_event = FALSE; + else if (check_time < temp_event->run_time) { log_debug_info(DEBUGL_CHECKS, 2, "New host check event occurs before the existing (older) event, so it will be used instead.\n"); - } + use_original_event = FALSE; + } /* the new event is older, so override the existing one */ else { log_debug_info(DEBUGL_CHECKS, 2, "New host check event occurs after the existing event, so we'll ignore it.\n"); - } } } + } /* use the new event */ - if(use_original_event == FALSE) { + if (use_original_event == FALSE) { log_debug_info(DEBUGL_CHECKS, 2, "Scheduling new host check event.\n"); /* possibly allocate memory for a new event item */ if (temp_event) { remove_event(nagios_squeue, temp_event); - } - else if((temp_event = (timed_event *)calloc(1, sizeof(timed_event))) == NULL) { + } + else if ((temp_event = (timed_event *)calloc(1, sizeof(timed_event))) == NULL) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Could not reschedule check of host '%s'!\n", hst->name); return; - } - + } /* set the next host check event and time */ hst->next_check_event = temp_event; @@ -1683,26 +2617,26 @@ void schedule_host_check(host *hst, time_t check_time, int options) { temp_event->timing_func = NULL; temp_event->compensate_for_time_change = TRUE; add_event(nagios_squeue, temp_event); - } + } else { /* reset the next check time (it may be out of sync) */ - if(temp_event != NULL) + if (temp_event != NULL) { hst->next_check = temp_event->run_time; + } log_debug_info(DEBUGL_CHECKS, 2, "Keeping original host check event (ignoring the new one).\n"); - } + } /* update the status log */ update_host_status(hst, FALSE); - - return; - } +} /* checks host dependencies */ -int check_host_dependencies(host *hst, int dependency_type) { +int check_host_dependencies(host *hst, int dependency_type) +{ hostdependency *temp_dependency = NULL; objectlist *list; host *temp_host = NULL; @@ -1714,7 +2648,8 @@ int check_host_dependencies(host *hst, int dependency_type) { if (dependency_type == NOTIFICATION_DEPENDENCY) { list = hst->notify_deps; - } else { + } + else { list = hst->exec_deps; } @@ -1723,38 +2658,47 @@ int check_host_dependencies(host *hst, int dependency_type) { temp_dependency = (hostdependency *)list->object_ptr; /* find the host we depend on... */ - if((temp_host = temp_dependency->master_host_ptr) == NULL) + if ((temp_host = temp_dependency->master_host_ptr) == NULL) { continue; + } /* skip this dependency if it has a timeperiod and the current time isn't valid */ time(¤t_time); - if(temp_dependency->dependency_period != NULL && check_time_against_period(current_time, temp_dependency->dependency_period_ptr) == ERROR) + if ((temp_dependency->dependency_period != NULL) + && (check_time_against_period(current_time, temp_dependency->dependency_period_ptr) == ERROR)) { + return FALSE; - - /* get the status to use (use last hard state if its currently in a soft state) */ - if(temp_host->state_type == SOFT_STATE && soft_state_dependencies == FALSE) - state = temp_host->last_hard_state; - else - state = temp_host->current_state; - - /* is the host we depend on in state that fails the dependency tests? */ - if(flag_isset(temp_dependency->failure_options, 1 << state)) - return DEPENDENCIES_FAILED; - - /* immediate dependencies ok at this point - check parent dependencies if necessary */ - if(temp_dependency->inherits_parent == TRUE) { - if(check_host_dependencies(temp_host, dependency_type) != DEPENDENCIES_OK) - return DEPENDENCIES_FAILED; - } } - return DEPENDENCIES_OK; + /* get the status to use (use last hard state if its currently in a soft state) */ + if (temp_host->state_type == SOFT_STATE && soft_state_dependencies == FALSE) { + state = temp_host->last_hard_state; + } + else { + state = temp_host->current_state; + } + + /* is the host we depend on in state that fails the dependency tests? */ + if (flag_isset(temp_dependency->failure_options, 1 << state)) { + return DEPENDENCIES_FAILED; + } + + /* immediate dependencies ok at this point - check parent dependencies if necessary */ + if ((temp_dependency->inherits_parent == TRUE) + && (check_host_dependencies(temp_host, dependency_type) != DEPENDENCIES_OK)) { + + return DEPENDENCIES_FAILED; + } } + return DEPENDENCIES_OK; +} + /* check for hosts that never returned from a check... */ -void check_for_orphaned_hosts(void) { +void check_for_orphaned_hosts(void) +{ host *temp_host = NULL; time_t current_time = 0L; time_t expected_time = 0L; @@ -1769,56 +2713,60 @@ void check_for_orphaned_hosts(void) { for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { /* skip hosts that don't have a set check interval (on-demand checks are missed by the orphan logic) */ - if(temp_host->next_check == (time_t)0L) + if (temp_host->next_check == (time_t)0L) { continue; + } /* skip hosts that are not currently executing */ - if(temp_host->is_executing == FALSE) + if (temp_host->is_executing == FALSE) { continue; + } /* determine the time at which the check results should have come in (allow 10 minutes slack time) */ expected_time = (time_t)(temp_host->next_check + temp_host->latency + host_check_timeout + check_reaper_interval + 600); /* this host was supposed to have executed a while ago, but for some reason the results haven't come back in... */ - if(expected_time < current_time) { + if (expected_time < current_time) { /* log a warning */ - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: The check of host '%s' looks like it was orphaned (results never came back). I'm scheduling an immediate check of the host...\n", temp_host->name); + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: The check of host '%s' looks like it was orphaned (results never came back). I'm scheduling an immediate check of the host...\n", + temp_host->name); - log_debug_info(DEBUGL_CHECKS, 1, "Host '%s' was orphaned, so we're scheduling an immediate check...\n", temp_host->name); + log_debug_info(DEBUGL_CHECKS, 1, + "Host '%s' was orphaned, so we're scheduling an immediate check...\n", + temp_host->name); /* decrement the number of running host checks */ - if(currently_running_host_checks > 0) + if (currently_running_host_checks > 0) { currently_running_host_checks--; + } /* disable the executing flag */ temp_host->is_executing = FALSE; /* schedule an immediate check of the host */ schedule_host_check(temp_host, current_time, CHECK_OPTION_ORPHAN_CHECK); - } - } - - return; } +} /* check freshness of host results */ -void check_host_result_freshness(void) { +void check_host_result_freshness(void) +{ host *temp_host = NULL; time_t current_time = 0L; - log_debug_info(DEBUGL_FUNCTIONS, 0, "check_host_result_freshness()\n"); log_debug_info(DEBUGL_CHECKS, 2, "Attempting to check the freshness of host check results...\n"); /* bail out if we're not supposed to be checking freshness */ - if(check_host_freshness == FALSE) { + if (check_host_freshness == FALSE) { log_debug_info(DEBUGL_CHECKS, 2, "Host freshness checking is disabled.\n"); return; - } + } /* get the current time */ time(¤t_time); @@ -1827,43 +2775,47 @@ void check_host_result_freshness(void) { for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { /* skip hosts we shouldn't be checking for freshness */ - if(temp_host->check_freshness == FALSE) + if (temp_host->check_freshness == FALSE) { continue; + } /* skip hosts that have both active and passive checks disabled */ - if(temp_host->checks_enabled == FALSE && temp_host->accept_passive_checks == FALSE) + if (temp_host->checks_enabled == FALSE && temp_host->accept_passive_checks == FALSE) { continue; + } /* skip hosts that are currently executing (problems here will be caught by orphaned host check) */ - if(temp_host->is_executing == TRUE) + if (temp_host->is_executing == TRUE) { continue; + } /* skip hosts that are already being freshened */ - if(temp_host->is_being_freshened == TRUE) + if (temp_host->is_being_freshened == TRUE) { continue; + } /* see if the time is right... */ - if(check_time_against_period(current_time, temp_host->check_period_ptr) == ERROR) + if (check_time_against_period(current_time, temp_host->check_period_ptr) == ERROR) { continue; + } /* the results for the last check of this host are stale */ - if(is_host_result_fresh(temp_host, current_time, TRUE) == FALSE) { + if (is_host_result_fresh(temp_host, current_time, TRUE) == FALSE) { /* set the freshen flag */ temp_host->is_being_freshened = TRUE; /* schedule an immediate forced check of the host */ schedule_host_check(temp_host, current_time, CHECK_OPTION_FORCE_EXECUTION | CHECK_OPTION_FRESHNESS_CHECK); - } } - - return; } +} /* checks to see if a hosts's check results are fresh */ -int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) { +int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) +{ time_t expiration_time = 0L; int freshness_threshold = 0; int days = 0; @@ -1879,17 +2831,20 @@ int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) { log_debug_info(DEBUGL_CHECKS, 2, "Checking freshness of host '%s'...\n", temp_host->name); /* use user-supplied freshness threshold or auto-calculate a freshness threshold to use? */ - if(temp_host->freshness_threshold == 0) { - if(temp_host->state_type == HARD_STATE || temp_host->current_state == STATE_OK) { + if (temp_host->freshness_threshold == 0) { + + if (temp_host->state_type == HARD_STATE || temp_host->current_state == STATE_OK) { interval = temp_host->check_interval; - } + } else { interval = temp_host->retry_interval; - } - freshness_threshold = (interval * interval_length) + temp_host->latency + additional_freshness_latency; } - else + + freshness_threshold = (interval * interval_length) + temp_host->latency + additional_freshness_latency; + } + else { freshness_threshold = temp_host->freshness_threshold; + } log_debug_info(DEBUGL_CHECKS, 2, "Freshness thresholds: host=%d, use=%d\n", temp_host->freshness_threshold, freshness_threshold); @@ -1900,8 +2855,9 @@ int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) { * if > last check AND active checks are enabled, so active checks * can become stale immediately upon program startup */ - if(temp_host->has_been_checked == FALSE) + if (temp_host->has_been_checked == FALSE) { expiration_time = (time_t)(event_start + freshness_threshold); + } /* * CHANGED 06/19/07 EG: * Per Ton's suggestion (and user requests), only use program start @@ -1914,10 +2870,15 @@ int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) { * Added max_host_check_spread to expiration time as suggested by * Altinity */ - else if(temp_host->checks_enabled == TRUE && event_start > temp_host->last_check && temp_host->freshness_threshold == 0) + else if ((temp_host->checks_enabled == TRUE) + && (event_start > temp_host->last_check) + && (temp_host->freshness_threshold == 0)) { + expiration_time = (time_t)(event_start + freshness_threshold + (max_host_check_spread * interval_length)); - else + } + else { expiration_time = (time_t)(temp_host->last_check + freshness_threshold); + } /* * If the check was last done passively, we assume it's going @@ -1929,50 +2890,77 @@ int is_host_result_fresh(host *temp_host, time_t current_time, int log_this) { * freshness threshold based on vast heuristical research (ie, "some * guy once told me the golden ratio is good for loads of stuff"). */ - if (temp_host->check_type == CHECK_TYPE_PASSIVE) { - if (temp_host->last_check < event_start && - event_start - last_program_stop > freshness_threshold * 0.618) - { - expiration_time = event_start + freshness_threshold; - } + if ((temp_host->check_type == CHECK_TYPE_PASSIVE) + && (temp_host->last_check < event_start) + && (event_start - last_program_stop > freshness_threshold * 0.618)) { + + expiration_time = event_start + freshness_threshold; } - log_debug_info(DEBUGL_CHECKS, 2, "HBC: %d, PS: %lu, ES: %lu, LC: %lu, CT: %lu, ET: %lu\n", temp_host->has_been_checked, (unsigned long)program_start, (unsigned long)event_start, (unsigned long)temp_host->last_check, (unsigned long)current_time, (unsigned long)expiration_time); + log_debug_info(DEBUGL_CHECKS, 2, + "HBC: %d, PS: %lu, ES: %lu, LC: %lu, CT: %lu, ET: %lu\n", + temp_host->has_been_checked, + (unsigned long)program_start, + (unsigned long)event_start, + (unsigned long)temp_host->last_check, + (unsigned long)current_time, + (unsigned long)expiration_time); /* the results for the last check of this host are stale */ - if(expiration_time < current_time) { + if (expiration_time < current_time) { get_time_breakdown((current_time - expiration_time), &days, &hours, &minutes, &seconds); get_time_breakdown(freshness_threshold, &tdays, &thours, &tminutes, &tseconds); /* log a warning */ - if(log_this == TRUE) - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: The results of host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). I'm forcing an immediate check of the host.\n", temp_host->name, days, hours, minutes, seconds, tdays, thours, tminutes, tseconds); + if (log_this == TRUE) { + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: The results of host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). I'm forcing an immediate check of the host.\n", + temp_host->name, + days, + hours, + minutes, + seconds, + tdays, + thours, + tminutes, + tseconds); + } - log_debug_info(DEBUGL_CHECKS, 1, "Check results for host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). Forcing an immediate check of the host...\n", temp_host->name, days, hours, minutes, seconds, tdays, thours, tminutes, tseconds); + log_debug_info(DEBUGL_CHECKS, 1, + "Check results for host '%s' are stale by %dd %dh %dm %ds (threshold=%dd %dh %dm %ds). Forcing an immediate check of the host...\n", + temp_host->name, + days, + hours, + minutes, + seconds, + tdays, + thours, + tminutes, + tseconds); return FALSE; - } - else - log_debug_info(DEBUGL_CHECKS, 1, "Check results for host '%s' are fresh.\n", temp_host->name); - - return TRUE; } + log_debug_info(DEBUGL_CHECKS, 1, "Check results for host '%s' are fresh.\n", temp_host->name); + return TRUE; +} + /* run a scheduled host check asynchronously */ -int run_scheduled_host_check(host *hst, int check_options, double latency) { +int run_scheduled_host_check(host *hst, int check_options, double latency) +{ int result = OK; time_t current_time = 0L; time_t preferred_time = 0L; time_t next_valid_time = 0L; int time_is_valid = TRUE; - log_debug_info(DEBUGL_FUNCTIONS, 0, "run_scheduled_host_check()\n"); - if(hst == NULL) + if (hst == NULL) { return ERROR; + } log_debug_info(DEBUGL_CHECKS, 0, "Attempting to run scheduled check of host '%s': check options=%d, latency=%lf\n", hst->name, check_options, latency); @@ -1986,20 +2974,21 @@ int run_scheduled_host_check(host *hst, int check_options, double latency) { result = run_async_host_check(hst, check_options, latency, TRUE, TRUE, &time_is_valid, &preferred_time); /* an error occurred, so reschedule the check */ - if(result == ERROR) { + if (result == ERROR) { log_debug_info(DEBUGL_CHECKS, 1, "Unable to run scheduled host check at this time\n"); /* only attempt to (re)schedule checks that should get checked... */ - if(hst->should_be_scheduled == TRUE) { + if (hst->should_be_scheduled == TRUE) { /* get current time */ time(¤t_time); /* determine next time we should check the host if needed */ /* if host has no check interval, schedule it again for 5 minutes from now */ - if(current_time >= preferred_time) + if (current_time >= preferred_time) { preferred_time = current_time + ((hst->check_interval <= 0) ? 300 : (hst->check_interval * interval_length)); + } /* make sure we rescheduled the next host check at a valid time */ get_next_valid_time(preferred_time, &next_valid_time, hst->check_period_ptr); @@ -2008,52 +2997,54 @@ int run_scheduled_host_check(host *hst, int check_options, double latency) { * If the host really can't be rescheduled properly we * set next check time to preferred_time and try again then */ - if(time_is_valid == FALSE && check_time_against_period(next_valid_time, hst->check_period_ptr) == ERROR) { + if ((time_is_valid == FALSE) + && (check_time_against_period(next_valid_time, hst->check_period_ptr) == ERROR)) { - hst->next_check = preferred_time + - ranged_urand(0, check_window(hst)); + hst->next_check = preferred_time + ranged_urand(0, check_window(hst)); logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' could not be rescheduled properly. Scheduling check for %s...\n", hst->name, ctime(&preferred_time)); log_debug_info(DEBUGL_CHECKS, 1, "Unable to find any valid times to reschedule the next host check!\n"); - } + } /* this service could be rescheduled... */ else { hst->next_check = next_valid_time; - if(next_valid_time > preferred_time) { + if (next_valid_time > preferred_time) { /* Next valid time is further in the future because of * timeperiod constraints. Add a random amount so we * don't get all checks subject to that timeperiod * constraint scheduled at the same time */ hst->next_check += ranged_urand(0, check_window(hst)); - } + } hst->should_be_scheduled = TRUE; log_debug_info(DEBUGL_CHECKS, 1, "Rescheduled next host check for %s", ctime(&next_valid_time)); - } } + } /* update the status log */ update_host_status(hst, FALSE); /* reschedule the next host check - unless we couldn't find a valid next check time */ /* 10/19/07 EG - keep original check options */ - if(hst->should_be_scheduled == TRUE) + if (hst->should_be_scheduled == TRUE) { schedule_host_check(hst, hst->next_check, check_options); - - return ERROR; } - return OK; + return ERROR; } + return OK; +} + /* perform an asynchronous check of a host */ /* scheduled host checks will use this, as will some checks that result from on-demand checks... */ -int run_async_host_check(host *hst, int check_options, double latency, int scheduled_check, int reschedule_check, int *time_is_valid, time_t *preferred_time) { +int run_async_host_check(host *hst, int check_options, double latency, int scheduled_check, int reschedule_check, int *time_is_valid, time_t *preferred_time) +{ nagios_macros mac; char *raw_command = NULL; char *processed_command = NULL; @@ -2069,30 +3060,30 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched log_debug_info(DEBUGL_FUNCTIONS, 0, "run_async_host_check(%s ...)\n", hst ? hst->name : "(NULL host!)"); /* make sure we have a host */ - if(hst == NULL) + if (hst == NULL) return ERROR; log_debug_info(DEBUGL_CHECKS, 0, "** Running async check of host '%s'...\n", hst->name); /* abort if check is already running or was recently completed */ if (!(check_options & CHECK_OPTION_FORCE_EXECUTION)) { - if(hst->is_executing == TRUE) { + if (hst->is_executing == TRUE) { log_debug_info(DEBUGL_CHECKS, 1, "A check of this host is already being executed, so we'll pass for the moment...\n"); return ERROR; - } + } if (hst->last_check + cached_host_check_horizon > time(NULL)) { log_debug_info(DEBUGL_CHECKS, 0, "Host '%s' was last checked within its cache horizon. Aborting check\n", hst->name); return ERROR; - } } + } log_debug_info(DEBUGL_CHECKS, 0, "Host '%s' passed first hurdle (caching/execution)\n", hst->name); /* is the host check viable at this time? */ - if(check_host_check_viability(hst, check_options, time_is_valid, preferred_time) == ERROR) { + if (check_host_check_viability(hst, check_options, time_is_valid, preferred_time) == ERROR) { log_debug_info(DEBUGL_CHECKS, 0, "Host check isn't viable at this point.\n"); return ERROR; - } + } /******** GOOD TO GO FOR A REAL HOST CHECK AT THIS POINT ********/ @@ -2106,34 +3097,34 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched /* send data to event broker */ neb_result = broker_host_check(NEBTYPE_HOSTCHECK_ASYNC_PRECHECK, NEBFLAG_NONE, NEBATTR_NONE, hst, CHECK_TYPE_ACTIVE, hst->current_state, hst->state_type, start_time, end_time, hst->check_command, hst->latency, 0.0, host_check_timeout, FALSE, 0, NULL, NULL, NULL, NULL, NULL, NULL); - if(neb_result == NEBERROR_CALLBACKCANCEL || neb_result == NEBERROR_CALLBACKOVERRIDE) { - log_debug_info(DEBUGL_CHECKS, 0, "Check of host '%s' (id=%u) was %s by a module\n", - hst->name, hst->id, - neb_result == NEBERROR_CALLBACKCANCEL ? "cancelled" : "overridden"); - } /* neb module wants to cancel the host check - the check will be rescheduled for a later time by the scheduling logic */ - if(neb_result == NEBERROR_CALLBACKCANCEL) { - if(preferred_time) + if (neb_result == NEBERROR_CALLBACKCANCEL) { + + log_debug_info(DEBUGL_CHECKS, 0, "Check of host '%s' (id=%u) was cancelled by a module\n", hst->name, hst->id); + + if (preferred_time) { *preferred_time += check_window(hst); - return ERROR; } + return ERROR; + } /* neb module wants to override the host check - perhaps it will check the host itself */ /* NOTE: if a module does this, it has to do a lot of the stuff found below to make sure things don't get whacked out of shape! */ /* NOTE: if would be easier for modules to override checks when the NEBTYPE_SERVICECHECK_INITIATE event is called (later) */ - if(neb_result == NEBERROR_CALLBACKOVERRIDE) + if (neb_result == NEBERROR_CALLBACKOVERRIDE) { + + log_debug_info(DEBUGL_CHECKS, 0, "Check of host '%s' (id=%u) was overridden by a module\n", hst->name, hst->id); return OK; + } #endif log_debug_info(DEBUGL_CHECKS, 0, "Checking host '%s'...\n", hst->name); /* clear check options - we don't want old check options retained */ /* only clear options if this was a scheduled check - on demand check options shouldn't affect retained info */ - if(scheduled_check == TRUE) + if (scheduled_check == TRUE) { hst->check_options = CHECK_OPTION_NONE; - - /* adjust host check attempt */ - adjust_host_check_attempt(hst, TRUE); + } /* set latency (temporarily) for macros and event broker */ old_latency = hst->latency; @@ -2145,20 +3136,20 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched /* get the raw command line */ get_raw_command_line_r(&mac, hst->check_command_ptr, hst->check_command, &raw_command, macro_options); - if(raw_command == NULL) { + if (raw_command == NULL) { clear_volatile_macros_r(&mac); log_debug_info(DEBUGL_CHECKS, 0, "Raw check command for host '%s' was NULL - aborting.\n", hst->name); return ERROR; - } + } /* process any macros contained in the argument */ process_macros_r(&mac, raw_command, &processed_command, macro_options); my_free(raw_command); - if(processed_command == NULL) { + if (processed_command == NULL) { clear_volatile_macros_r(&mac); log_debug_info(DEBUGL_CHECKS, 0, "Processed check command for host '%s' was NULL - aborting.\n", hst->name); return ERROR; - } + } /* get the command start time */ gettimeofday(&start_time, NULL); @@ -2208,7 +3199,8 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched runchk_result = wproc_run_check(cr, processed_command, &mac); if (runchk_result == ERROR) { logit(NSLOG_RUNTIME_ERROR, TRUE, "Unable to send check for host '%s' to worker (ret=%d)\n", hst->name, runchk_result); - } else { + } + else { /* do the book-keeping */ currently_running_host_checks++; hst->is_executing = TRUE; @@ -2222,568 +3214,14 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched my_free(processed_command); return runchk_result; - } - - - -static int get_host_check_return_code(host *temp_host, - check_result *queued_check_result) { - - int rc; - char *temp_plugin_output = NULL; - - log_debug_info(DEBUGL_FUNCTIONS, 0, "get_host_check_return_code()\n"); - - /* get the unprocessed return code */ - /* NOTE: for passive checks, this is the final/processed state */ - rc = queued_check_result->return_code; - - /* adjust return code (active checks only) */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE) { - if(queued_check_result->early_timeout) { - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' timed out after %.2lf seconds\n", temp_host->name, temp_host->execution_time); - my_free(temp_host->plugin_output); - my_free(temp_host->long_plugin_output); - my_free(temp_host->perf_data); - asprintf(&temp_host->plugin_output, "(Host check timed out after %.2lf seconds)", temp_host->execution_time); - rc = STATE_UNKNOWN; - } - - /* if there was some error running the command, just skip it (this shouldn't be happening) */ - else if(queued_check_result->exited_ok == FALSE) { - - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' did not exit properly!\n", temp_host->name); - - my_free(temp_host->plugin_output); - my_free(temp_host->long_plugin_output); - my_free(temp_host->perf_data); - - temp_host->plugin_output = (char *)strdup("(Host check did not exit properly)"); - - rc = STATE_CRITICAL; - } - - /* make sure the return code is within bounds */ - else if(queued_check_result->return_code < 0 || queued_check_result->return_code > 3) { - - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Return code of %d for check of host '%s' was out of bounds.%s\n", queued_check_result->return_code, temp_host->name, (queued_check_result->return_code == 126 || queued_check_result->return_code == 127) ? " Make sure the plugin you're trying to run actually exists." : ""); - - asprintf(&temp_plugin_output, "(Return code of %d is out of bounds%s : %s)", queued_check_result->return_code, (queued_check_result->return_code == 126 || queued_check_result->return_code == 127) ? " - plugin may be missing" : "", temp_host->plugin_output); - my_free(temp_host->plugin_output); - - asprintf(&temp_host->plugin_output, "%s)", temp_plugin_output); - my_free(temp_plugin_output); - my_free(temp_host->long_plugin_output); - my_free(temp_host->perf_data); - - rc = STATE_CRITICAL; - } - - /* a NULL host check command means we should assume the host is UP */ - if(temp_host->check_command == NULL) { - my_free(temp_host->plugin_output); - temp_host->plugin_output = (char *)strdup("(Host assumed to be UP)"); - rc = STATE_OK; - } - } - return rc; - } +} /* process results of an asynchronous host check */ -int handle_async_host_check_result(host *temp_host, check_result *queued_check_result) { - time_t current_time; - int result = STATE_OK; - int reschedule_check = FALSE; - char *old_plugin_output = NULL; - char *temp_ptr = NULL; - struct timeval start_time_hires; - struct timeval end_time_hires; - - log_debug_info(DEBUGL_FUNCTIONS, 0, "handle_async_host_check_result(%s ...)\n", temp_host ? temp_host->name : "(NULL host!)"); - - /* make sure we have what we need */ - if(temp_host == NULL || queued_check_result == NULL) - return ERROR; - - time(¤t_time); - - log_debug_info(DEBUGL_CHECKS, 1, "** Handling async check result for host '%s' from '%s'...\n", temp_host->name, check_result_source(queued_check_result)); - - log_debug_info(DEBUGL_CHECKS, 2, "\tCheck Type: %s\n", (queued_check_result->check_type == CHECK_TYPE_ACTIVE) ? "Active" : "Passive"); - log_debug_info(DEBUGL_CHECKS, 2, "\tCheck Options: %d\n", queued_check_result->check_options); - log_debug_info(DEBUGL_CHECKS, 2, "\tScheduled Check?: %s\n", (queued_check_result->scheduled_check == TRUE) ? "Yes" : "No"); - log_debug_info(DEBUGL_CHECKS, 2, "\tReschedule Check?: %s\n", (queued_check_result->reschedule_check == TRUE) ? "Yes" : "No"); - log_debug_info(DEBUGL_CHECKS, 2, "\tExited OK?: %s\n", (queued_check_result->exited_ok == TRUE) ? "Yes" : "No"); - log_debug_info(DEBUGL_CHECKS, 2, "\tExec Time: %.3f\n", temp_host->execution_time); - log_debug_info(DEBUGL_CHECKS, 2, "\tLatency: %.3f\n", temp_host->latency); - log_debug_info(DEBUGL_CHECKS, 2, "\tReturn Status: %d\n", queued_check_result->return_code); - log_debug_info(DEBUGL_CHECKS, 2, "\tOutput: %s\n", (queued_check_result == NULL) ? "NULL" : queued_check_result->output); - - /* decrement the number of host checks still out there... */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE && currently_running_host_checks > 0) - currently_running_host_checks--; - - /* skip this host check results if its passive and we aren't accepting passive check results */ - if(queued_check_result->check_type == CHECK_TYPE_PASSIVE) { - if(accept_passive_host_checks == FALSE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive host check result because passive host checks are disabled globally.\n"); - return ERROR; - } - if(temp_host->accept_passive_checks == FALSE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding passive host check result because passive checks are disabled for this host.\n"); - return ERROR; - } - } - - /* clear the freshening flag (it would have been set if this host was determined to be stale) */ - if(queued_check_result->check_options & CHECK_OPTION_FRESHNESS_CHECK) - temp_host->is_being_freshened = FALSE; - - /* DISCARD INVALID FRESHNESS CHECK RESULTS */ - /* If a host goes stale, Nagios will initiate a forced check in order to freshen it. There is a race condition whereby a passive check - could arrive between the 1) initiation of the forced check and 2) the time when the forced check result is processed here. This would - make the host fresh again, so we do a quick check to make sure the host is still stale before we accept the check result. */ - if((queued_check_result->check_options & CHECK_OPTION_FRESHNESS_CHECK) && is_host_result_fresh(temp_host, current_time, FALSE) == TRUE) { - log_debug_info(DEBUGL_CHECKS, 0, "Discarding host freshness check result because the host is currently fresh (race condition avoided).\n"); - return OK; - } - - /* was this check passive or active? */ - temp_host->check_type = (queued_check_result->check_type == CHECK_TYPE_ACTIVE) ? CHECK_TYPE_ACTIVE : CHECK_TYPE_PASSIVE; - - /* update check statistics for passive results */ - if(queued_check_result->check_type == CHECK_TYPE_PASSIVE) - update_check_stats(PASSIVE_HOST_CHECK_STATS, queued_check_result->start_time.tv_sec); - - /* should we reschedule the next check of the host? NOTE: this might be overridden later... */ - reschedule_check = queued_check_result->reschedule_check; - - /* check latency is passed to us for both active and passive checks */ - temp_host->latency = queued_check_result->latency; - - /* update the execution time for this check (millisecond resolution) */ - temp_host->execution_time = (double)((double)(queued_check_result->finish_time.tv_sec - queued_check_result->start_time.tv_sec) + (double)((queued_check_result->finish_time.tv_usec - queued_check_result->start_time.tv_usec) / 1000.0) / 1000.0); - if(temp_host->execution_time < 0.0) - temp_host->execution_time = 0.0; - - /* set the checked flag */ - temp_host->has_been_checked = TRUE; - - /* clear the execution flag if this was an active check */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE) - temp_host->is_executing = FALSE; - - /* get the last check time */ - temp_host->last_check = queued_check_result->start_time.tv_sec; - - /* was this check passive or active? */ - temp_host->check_type = (queued_check_result->check_type == CHECK_TYPE_ACTIVE) ? CHECK_TYPE_ACTIVE : CHECK_TYPE_PASSIVE; - - /* save the old host state */ - temp_host->last_state = temp_host->current_state; - if(temp_host->state_type == HARD_STATE) - temp_host->last_hard_state = temp_host->current_state; - - /* save old plugin output */ - if(temp_host->plugin_output) - old_plugin_output = (char *)strdup(temp_host->plugin_output); - - /* clear the old plugin output and perf data buffers */ - my_free(temp_host->plugin_output); - my_free(temp_host->long_plugin_output); - my_free(temp_host->perf_data); - - /* parse check output to get: (1) short output, (2) long output, (3) perf data */ - parse_check_output(queued_check_result->output, &temp_host->plugin_output, &temp_host->long_plugin_output, &temp_host->perf_data, TRUE, FALSE); - - /* make sure we have some data */ - if(temp_host->plugin_output == NULL || !strcmp(temp_host->plugin_output, "")) { - my_free(temp_host->plugin_output); - temp_host->plugin_output = (char *)strdup("(No output returned from host check)"); - } - - /* replace semicolons in plugin output (but not performance data) with colons */ - if((temp_ptr = temp_host->plugin_output)) { - while((temp_ptr = strchr(temp_ptr, ';'))) - * temp_ptr = ':'; - } - - log_debug_info(DEBUGL_CHECKS, 2, "Parsing check output...\n"); - log_debug_info(DEBUGL_CHECKS, 2, "Short Output: %s\n", (temp_host->plugin_output == NULL) ? "NULL" : temp_host->plugin_output); - log_debug_info(DEBUGL_CHECKS, 2, "Long Output: %s\n", (temp_host->long_plugin_output == NULL) ? "NULL" : temp_host->long_plugin_output); - log_debug_info(DEBUGL_CHECKS, 2, "Perf Data: %s\n", (temp_host->perf_data == NULL) ? "NULL" : temp_host->perf_data); - - /* get the check return code */ - result = get_host_check_return_code(temp_host, queued_check_result); - - /* translate return code to basic UP/DOWN state - the DOWN/UNREACHABLE state determination is made later */ - /* NOTE: only do this for active checks - passive check results already have the final state */ - if(queued_check_result->check_type == CHECK_TYPE_ACTIVE) { - - /* if we're not doing aggressive host checking, let WARNING states indicate the host is up (fake the result to be STATE_OK) */ - if(use_aggressive_host_checking == FALSE && result == STATE_WARNING) - result = STATE_OK; - - /* OK states means the host is UP */ - if(result == STATE_OK) - result = HOST_UP; - - /* any problem state indicates the host is not UP */ - else - result = HOST_DOWN; - } - - - /******************* PROCESS THE CHECK RESULTS ******************/ - - /* process the host check result */ - process_host_check_result(temp_host, result, old_plugin_output, CHECK_OPTION_NONE, reschedule_check, TRUE, cached_host_check_horizon); - - /* free memory */ - my_free(old_plugin_output); - - log_debug_info(DEBUGL_CHECKS, 1, "** Async check result for host '%s' handled: new state=%d\n", temp_host->name, temp_host->current_state); - - /* high resolution start time for event broker */ - start_time_hires = queued_check_result->start_time; - - /* high resolution end time for event broker */ - gettimeofday(&end_time_hires, NULL); - -#ifdef USE_EVENT_BROKER - /* send data to event broker */ - broker_host_check(NEBTYPE_HOSTCHECK_PROCESSED, NEBFLAG_NONE, NEBATTR_NONE, temp_host, temp_host->check_type, temp_host->current_state, temp_host->state_type, start_time_hires, end_time_hires, temp_host->check_command, temp_host->latency, temp_host->execution_time, host_check_timeout, queued_check_result->early_timeout, queued_check_result->return_code, NULL, temp_host->plugin_output, temp_host->long_plugin_output, temp_host->perf_data, NULL, queued_check_result); -#endif - - return OK; - } - - - -/* processes the result of a synchronous or asynchronous host check */ -int process_host_check_result(host *hst, int new_state, char *old_plugin_output, int check_options, int reschedule_check, int use_cached_result, unsigned long check_timestamp_horizon) { - hostsmember *temp_hostsmember = NULL; - host *child_host = NULL; - host *parent_host = NULL; - host *master_host = NULL; - time_t current_time = 0L; - time_t next_check = 0L; - time_t preferred_time = 0L; - time_t next_valid_time = 0L; - - - log_debug_info(DEBUGL_FUNCTIONS, 0, "process_host_check_result()\n"); - - log_debug_info(DEBUGL_CHECKS, 1, "HOST: %s, ATTEMPT=%d/%d, CHECK TYPE=%s, STATE TYPE=%s, OLD STATE=%d, NEW STATE=%d\n", hst->name, hst->current_attempt, hst->max_attempts, (hst->check_type == CHECK_TYPE_ACTIVE) ? "ACTIVE" : "PASSIVE", (hst->state_type == HARD_STATE) ? "HARD" : "SOFT", hst->current_state, new_state); - - /* get the current time */ - time(¤t_time); - - /* default next check time */ - next_check = current_time + normal_check_window(hst); - - /* we have to adjust current attempt # for passive checks, as it isn't done elsewhere */ - if(hst->check_type == CHECK_TYPE_PASSIVE && passive_host_checks_are_soft == TRUE) - adjust_host_check_attempt(hst, FALSE); - - /* log passive checks - we need to do this here, as some my bypass external commands by getting dropped in checkresults dir */ - if(hst->check_type == CHECK_TYPE_PASSIVE) { - if(log_passive_checks == TRUE) - logit(NSLOG_PASSIVE_CHECK, FALSE, "PASSIVE HOST CHECK: %s;%d;%s\n", hst->name, new_state, hst->plugin_output); - } - - - /******* HOST WAS DOWN/UNREACHABLE INITIALLY *******/ - if(hst->current_state != HOST_UP) { - - log_debug_info(DEBUGL_CHECKS, 1, "Host was %s.\n", host_state_name(hst->current_state)); - - /***** HOST IS NOW UP *****/ - /* the host just recovered! */ - if(new_state == HOST_UP) { - - /* set the current state */ - hst->current_state = HOST_UP; - - /* set the state type */ - /* set state type to HARD for passive checks and active checks that were previously in a HARD STATE */ - if(hst->state_type == HARD_STATE || (hst->check_type == CHECK_TYPE_PASSIVE && passive_host_checks_are_soft == FALSE)) - hst->state_type = HARD_STATE; - else - hst->state_type = SOFT_STATE; - - log_debug_info(DEBUGL_CHECKS, 1, "Host experienced a %s recovery (it's now UP).\n", (hst->state_type == HARD_STATE) ? "HARD" : "SOFT"); - - /* reschedule the next check of the host at the normal interval */ - reschedule_check = TRUE; - next_check = (unsigned long)(current_time + (hst->check_interval * interval_length)); - - /* propagate checks to immediate parents if they are not already UP */ - /* we do this because a parent host (or grandparent) may have recovered somewhere and we should catch the recovery as soon as possible */ - log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to parent host(s)...\n"); - for(temp_hostsmember = hst->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { - parent_host = temp_hostsmember->host_ptr; - if(parent_host->current_state != HOST_UP) { - log_debug_info(DEBUGL_CHECKS, 1, "Check of parent host '%s' queued.\n", parent_host->name); - schedule_host_check(parent_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - } - - /* propagate checks to immediate children if they are not already UP */ - /* we do this because children may currently be UNREACHABLE, but may (as a result of this recovery) switch to UP or DOWN states */ - log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to child host(s)...\n"); - for(temp_hostsmember = hst->child_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { - child_host = temp_hostsmember->host_ptr; - if(child_host->current_state != HOST_UP) { - log_debug_info(DEBUGL_CHECKS, 1, "Check of child host '%s' queued.\n", child_host->name); - schedule_host_check(child_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - } - } - - } - - /***** HOST IS STILL DOWN/UNREACHABLE *****/ - /* we're still in a problem state... */ - else { - - log_debug_info(DEBUGL_CHECKS, 1, "Host is still %s.\n", host_state_name(hst->current_state)); - - /* passive checks are treated as HARD states by default... */ - if(hst->check_type == CHECK_TYPE_PASSIVE && passive_host_checks_are_soft == FALSE) { - - /* set the state type */ - hst->state_type = HARD_STATE; - - /* reset the current attempt */ - hst->current_attempt = 1; - } - - /* active checks and passive checks (treated as SOFT states) */ - else { - - /* set the state type */ - /* we've maxed out on the retries */ - if(hst->current_attempt == hst->max_attempts) - hst->state_type = HARD_STATE; - /* the host was in a hard problem state before, so it still is now */ - /* 2015-07-23 with the change adjust_host_check_attempt, this can no longer happen - else if(hst->current_attempt == 1) - hst->state_type = HARD_STATE; - */ - /* the host is in a soft state and the check will be retried */ - else - hst->state_type = SOFT_STATE; - } - - /* make a determination of the host's state */ - /* translate host state between DOWN/UNREACHABLE (only for passive checks if enabled) */ - hst->current_state = new_state; - if(hst->check_type == CHECK_TYPE_ACTIVE || translate_passive_host_checks == TRUE) - hst->current_state = determine_host_reachability(hst); - - /* reschedule the next check if the host state changed */ - if(hst->last_state != hst->current_state || hst->last_hard_state != hst->current_state) { - - reschedule_check = TRUE; - - /* schedule a re-check of the host at the retry interval because we can't determine its final state yet... */ - if(hst->state_type == SOFT_STATE) - next_check = (unsigned long)(current_time + (hst->retry_interval * interval_length)); - - /* host has maxed out on retries (or was previously in a hard problem state), so reschedule the next check at the normal interval */ - else - next_check = (unsigned long)(current_time + (hst->check_interval * interval_length)); - } - - } - - } - - /******* HOST WAS UP INITIALLY *******/ - else { - - log_debug_info(DEBUGL_CHECKS, 1, "Host was UP.\n"); - - /***** HOST IS STILL UP *****/ - /* either the host never went down since last check */ - if(new_state == HOST_UP) { - - log_debug_info(DEBUGL_CHECKS, 1, "Host is still UP.\n"); - - /* set the current state */ - hst->current_state = HOST_UP; - - /* set the state type */ - hst->state_type = HARD_STATE; - - /* reschedule the next check at the normal interval */ - if(reschedule_check == TRUE) - next_check = (unsigned long)(current_time + (hst->check_interval * interval_length)); - } - - /***** HOST IS NOW DOWN/UNREACHABLE *****/ - else { - - log_debug_info(DEBUGL_CHECKS, 1, "Host is now %s.\n", host_state_name(hst->current_state)); - - /* active and (in some cases) passive check results are treated as SOFT states */ - if(hst->check_type == CHECK_TYPE_ACTIVE || passive_host_checks_are_soft == TRUE) { - - /* set the state type */ - hst->state_type = SOFT_STATE; - } - - /* by default, passive check results are treated as HARD states */ - else { - - /* set the state type */ - hst->state_type = HARD_STATE; - - /* reset the current attempt */ - hst->current_attempt = 1; - } - - /* make a (in some cases) preliminary determination of the host's state */ - /* translate host state between DOWN/UNREACHABLE (for passive checks only if enabled) */ - hst->current_state = new_state; - if(hst->check_type == CHECK_TYPE_ACTIVE || translate_passive_host_checks == TRUE) - hst->current_state = determine_host_reachability(hst); - - /* reschedule a check of the host */ - reschedule_check = TRUE; - - /* schedule a re-check of the host at the retry interval because we can't determine its final state yet... */ - if(hst->check_type == CHECK_TYPE_ACTIVE || passive_host_checks_are_soft == TRUE) - next_check = (unsigned long)(current_time + (hst->retry_interval * interval_length)); - - /* schedule a re-check of the host at the normal interval */ - else - next_check = (unsigned long)(current_time + (hst->check_interval * interval_length)); - - /* propagate checks to immediate parents if they are UP */ - /* we do this because a parent host (or grandparent) may have gone down and blocked our route */ - /* checking the parents ASAP will allow us to better determine the final state (DOWN/UNREACHABLE) of this host later */ - log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to immediate parent hosts that are UP...\n"); - - for(temp_hostsmember = hst->parent_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { - parent_host = temp_hostsmember->host_ptr; - if(parent_host->current_state == HOST_UP) { - schedule_host_check(parent_host, current_time, CHECK_OPTION_DEPENDENCY_CHECK); - log_debug_info(DEBUGL_CHECKS, 1, "Check of host '%s' queued.\n", parent_host->name); - } - } - - /* propagate checks to immediate children if they are not UNREACHABLE */ - /* we do this because we may now be blocking the route to child hosts */ - log_debug_info(DEBUGL_CHECKS, 1, "Propagating checks to immediate non-UNREACHABLE child hosts...\n"); - for(temp_hostsmember = hst->child_hosts; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) { - child_host = temp_hostsmember->host_ptr; - if(child_host->current_state != HOST_UNREACHABLE) { - log_debug_info(DEBUGL_CHECKS, 1, "Check of child host '%s' queued.\n", child_host->name); - schedule_host_check(child_host, current_time, CHECK_OPTION_NONE); - } - } - - /* check dependencies on second to last host check */ - if(enable_predictive_host_dependency_checks == TRUE && hst->current_attempt == (hst->max_attempts - 1)) { - objectlist *list; - - /* propagate checks to hosts that THIS ONE depends on for notifications AND execution */ - /* we do to help ensure that the dependency checks are accurate before it comes time to notify */ - log_debug_info(DEBUGL_CHECKS, 1, "Propagating predictive dependency checks to hosts this one depends on...\n"); - - for(list = hst->notify_deps; list; list = list->next) { - hostdependency *dep = (hostdependency *)list->object_ptr; - if(dep->dependent_host_ptr == hst && dep->master_host_ptr != NULL) { - master_host = (host *)dep->master_host_ptr; - log_debug_info(DEBUGL_CHECKS, 1, "Check of host '%s' queued.\n", master_host->name); - schedule_host_check(master_host, current_time, CHECK_OPTION_NONE); - } - } - for(list = hst->exec_deps; list; list = list->next) { - hostdependency *dep = (hostdependency *)list->object_ptr; - if(dep->dependent_host_ptr == hst && dep->master_host_ptr != NULL) { - master_host = (host *)dep->master_host_ptr; - log_debug_info(DEBUGL_CHECKS, 1, "Check of host '%s' queued.\n", master_host->name); - schedule_host_check(master_host, current_time, CHECK_OPTION_NONE); - } - } - } - } - } - - log_debug_info(DEBUGL_CHECKS, 1, "Pre-handle_host_state() Host: %s, Attempt=%d/%d, Type=%s, Final State=%d (%s)\n", hst->name, hst->current_attempt, hst->max_attempts, (hst->state_type == HARD_STATE) ? "HARD" : "SOFT", hst->current_state, host_state_name(hst->current_state)); - - /* handle the host state */ - handle_host_state(hst); - - log_debug_info(DEBUGL_CHECKS, 1, "Post-handle_host_state() Host: %s, Attempt=%d/%d, Type=%s, Final State=%d (%s)\n", hst->name, hst->current_attempt, hst->max_attempts, (hst->state_type == HARD_STATE) ? "HARD" : "SOFT", hst->current_state, host_state_name(hst->current_state)); - - - /******************** POST-PROCESSING STUFF *********************/ - - /* if the plugin output differs from previous check and no state change, log the current state/output if state stalking is enabled */ - if(hst->last_state == hst->current_state && should_stalk(hst) && compare_strings(old_plugin_output, hst->plugin_output)) { - log_host_event(hst); - } - - /* check to see if the associated host is flapping */ - check_for_host_flapping(hst, TRUE, TRUE, TRUE); - - /* reschedule the next check of the host (usually ONLY for scheduled, active checks, unless overridden above) */ - if(reschedule_check == TRUE) { - - log_debug_info(DEBUGL_CHECKS, 1, "Rescheduling next check of host at %s", ctime(&next_check)); - - /* default is to reschedule host check unless a test below fails... */ - hst->should_be_scheduled = TRUE; - - /* get the new current time */ - time(¤t_time); - - /* make sure we don't get ourselves into too much trouble... */ - if(current_time > next_check) - hst->next_check = current_time; - else - hst->next_check = next_check; - - /* make sure we rescheduled the next service check at a valid time */ - preferred_time = hst->next_check; - get_next_valid_time(preferred_time, &next_valid_time, hst->check_period_ptr); - hst->next_check = next_valid_time; - if(next_valid_time > preferred_time) { - /* Next valid time is further in the future because of timeperiod - * constraints. Add a random amount so we don't get all checks - * subject to that timeperiod constraint scheduled at the same time - */ - hst->next_check += ranged_urand(0, check_window(hst)); - } - - /* hosts with non-recurring intervals do not get rescheduled if we're in a HARD or UP state */ - if(hst->check_interval == 0 && (hst->state_type == HARD_STATE || hst->current_state == HOST_UP)) - hst->should_be_scheduled = FALSE; - - /* host with active checks disabled do not get rescheduled */ - if(hst->checks_enabled == FALSE) - hst->should_be_scheduled = FALSE; - - /* schedule a non-forced check if we can */ - if(hst->should_be_scheduled == TRUE) { - schedule_host_check(hst, hst->next_check, CHECK_OPTION_NONE); - } - } - - /* update host status - for both active (scheduled) and passive (non-scheduled) hosts */ - update_host_status(hst, FALSE); - - return OK; - } - /* checks viability of performing a host check */ -int check_host_check_viability(host *hst, int check_options, int *time_is_valid, time_t *new_time) { - int result = OK; +int check_host_check_viability(host *hst, int check_options, int *time_is_valid, time_t *new_time) +{ int perform_check = TRUE; time_t current_time = 0L; time_t preferred_time = 0L; @@ -2792,18 +3230,22 @@ int check_host_check_viability(host *hst, int check_options, int *time_is_valid, log_debug_info(DEBUGL_FUNCTIONS, 0, "check_host_check_viability()\n"); /* make sure we have a host */ - if(hst == NULL) + if (hst == NULL) { return ERROR; + } /* get the check interval to use if we need to reschedule the check */ - if(hst->state_type == SOFT_STATE && hst->current_state != HOST_UP) + if (hst->state_type == SOFT_STATE && hst->current_state != HOST_UP) { check_interval = (hst->retry_interval * interval_length); - else + } + else { check_interval = (hst->check_interval * interval_length); + } /* make sure check interval is positive - otherwise use 5 minutes out for next check */ - if(check_interval <= 0) + if (check_interval <= 0) { check_interval = 300; + } /* get the current time */ time(¤t_time); @@ -2812,100 +3254,78 @@ int check_host_check_viability(host *hst, int check_options, int *time_is_valid, preferred_time = current_time; /* can we check the host right now? */ - if(!(check_options & CHECK_OPTION_FORCE_EXECUTION)) { + if (!(check_options & CHECK_OPTION_FORCE_EXECUTION)) { /* if checks of the host are currently disabled... */ - if(hst->checks_enabled == FALSE) { + if (hst->checks_enabled == FALSE) { preferred_time = current_time + check_interval; perform_check = FALSE; - } + } /* make sure this is a valid time to check the host */ - if(check_time_against_period((unsigned long)current_time, hst->check_period_ptr) == ERROR) { + if (check_time_against_period((unsigned long)current_time, hst->check_period_ptr) == ERROR) { log_debug_info(DEBUGL_CHECKS, 0, "Timeperiod check failed\n"); preferred_time = current_time; - if(time_is_valid) + if (time_is_valid) { *time_is_valid = FALSE; - perform_check = FALSE; } + perform_check = FALSE; + } /* check host dependencies for execution */ - if(check_host_dependencies(hst, EXECUTION_DEPENDENCY) == DEPENDENCIES_FAILED) { + if (check_host_dependencies(hst, EXECUTION_DEPENDENCY) == DEPENDENCIES_FAILED) { log_debug_info(DEBUGL_CHECKS, 0, "Host check dependencies failed\n"); preferred_time = current_time + check_interval; perform_check = FALSE; + if (host_skip_check_dependency_status >= 0) { + hst->current_state = host_skip_check_dependency_status; } } + } /* pass back the next viable check time */ - if(new_time) + if (new_time) { *new_time = preferred_time; - - result = (perform_check == TRUE) ? OK : ERROR; - - return result; } - - -/* adjusts current host check attempt before a new check is performed */ -int adjust_host_check_attempt(host *hst, int is_active) { - - log_debug_info(DEBUGL_FUNCTIONS, 0, "adjust_host_check_attempt()\n"); - - if(hst == NULL) - return ERROR; - - log_debug_info(DEBUGL_CHECKS, 2, "Adjusting check attempt number for host '%s': current attempt=%d/%d, state=%d, state type=%d\n", hst->name, hst->current_attempt, hst->max_attempts, hst->current_state, hst->state_type); - - /* if host is in a hard state, reset current attempt number */ - /* 2015-07-23 only reset current_attempt if host is up */ - if(hst->state_type == HARD_STATE && hst->current_state == HOST_UP) - hst->current_attempt = 1; - - /* if host is in a soft UP state, reset current attempt number (active checks only) */ - else if(is_active == TRUE && hst->state_type == SOFT_STATE && hst->current_state == HOST_UP) - hst->current_attempt = 1; - - /* increment current attempt number */ - else if(hst->current_attempt < hst->max_attempts) - hst->current_attempt++; - - log_debug_info(DEBUGL_CHECKS, 2, "New check attempt number = %d\n", hst->current_attempt); - - return OK; + if (perform_check == TRUE) { + return OK; } + return ERROR; +} + /* determination of the host's state based on route availability*/ /* used only to determine difference between DOWN and UNREACHABLE states */ -int determine_host_reachability(host *hst) { +inline int determine_host_reachability(host *hst) +{ host *parent_host = NULL; hostsmember *temp_hostsmember = NULL; log_debug_info(DEBUGL_FUNCTIONS, 0, "determine_host_reachability(host=%s)\n", hst ? hst->name : "(NULL host!)"); - if(hst == NULL) + if (hst == NULL) return HOST_DOWN; log_debug_info(DEBUGL_CHECKS, 2, "Determining state of host '%s': current state=%d (%s)\n", hst->name, hst->current_state, host_state_name(hst->current_state)); /* host is UP - no translation needed */ - if(hst->current_state == HOST_UP) { + if (hst->current_state == HOST_UP) { log_debug_info(DEBUGL_CHECKS, 2, "Host is UP, no state translation needed.\n"); return HOST_UP; - } + } /* host has no parents, so it is DOWN */ - if(hst->check_type == CHECK_TYPE_PASSIVE && hst->current_state == HOST_UNREACHABLE) { + if (hst->check_type == CHECK_TYPE_PASSIVE && hst->current_state == HOST_UNREACHABLE) { log_debug_info(DEBUGL_CHECKS, 2, "Passive check so keep it UNREACHABLE.\n"); return HOST_UNREACHABLE; - } - else if(hst->parent_hosts == NULL) { + } + else if (hst->parent_hosts == NULL) { log_debug_info(DEBUGL_CHECKS, 2, "Host has no parents, so it is DOWN.\n"); return HOST_DOWN; - } + } /* check all parent hosts to see if we're DOWN or UNREACHABLE */ else { @@ -2913,17 +3333,17 @@ int determine_host_reachability(host *hst) { parent_host = temp_hostsmember->host_ptr; log_debug_info(DEBUGL_CHECKS, 2, " Parent '%s' is %s\n", parent_host->name, host_state_name(parent_host->current_state)); /* bail out as soon as we find one parent host that is UP */ - if(parent_host->current_state == HOST_UP) { + if (parent_host->current_state == HOST_UP) { /* set the current state */ log_debug_info(DEBUGL_CHECKS, 2, "At least one parent (%s) is up, so host is DOWN.\n", parent_host->name); return HOST_DOWN; - } } } + } log_debug_info(DEBUGL_CHECKS, 2, "No parents were up, so host is UNREACHABLE.\n"); return HOST_UNREACHABLE; - } +} @@ -2932,149 +3352,10 @@ int determine_host_reachability(host *hst) { /******************************************************************/ -/* top level host state handler - occurs after every host check (soft/hard and active/passive) */ -int handle_host_state(host *hst) { - int state_change = FALSE; - int hard_state_change = FALSE; - time_t current_time = 0L; - - - log_debug_info(DEBUGL_FUNCTIONS, 0, "handle_host_state()\n"); - - /* get current time */ - time(¤t_time); - - /* obsess over this host check */ - obsessive_compulsive_host_check_processor(hst); - - /* update performance data */ - update_host_performance_data(hst); - - /* record the time the last state ended */ - switch(hst->last_state) { - case HOST_UP: - hst->last_time_up = current_time; - break; - case HOST_DOWN: - hst->last_time_down = current_time; - break; - case HOST_UNREACHABLE: - hst->last_time_unreachable = current_time; - break; - default: - break; - } - - /* has the host state changed? */ - if(hst->last_state != hst->current_state || (hst->current_state == HOST_UP && hst->state_type == SOFT_STATE)) - state_change = TRUE; - - if(hst->current_attempt >= hst->max_attempts && hst->last_hard_state != hst->current_state) - hard_state_change = TRUE; - - /* if the host state has changed... */ - if(state_change == TRUE || hard_state_change == TRUE) { - - /* reset the next and last notification times */ - hst->last_notification = (time_t)0; - hst->next_notification = (time_t)0; - - /* reset notification suppression option */ - hst->no_more_notifications = FALSE; - - /* reset the acknowledgement flag if necessary */ - if(hst->acknowledgement_type == ACKNOWLEDGEMENT_NORMAL && (state_change == TRUE || hard_state_change == FALSE)) { - - hst->problem_has_been_acknowledged = FALSE; - hst->acknowledgement_type = ACKNOWLEDGEMENT_NONE; - - /* remove any non-persistant comments associated with the ack */ - delete_host_acknowledgement_comments(hst); - } - else if(hst->acknowledgement_type == ACKNOWLEDGEMENT_STICKY && hst->current_state == HOST_UP) { - - hst->problem_has_been_acknowledged = FALSE; - hst->acknowledgement_type = ACKNOWLEDGEMENT_NONE; - - /* remove any non-persistant comments associated with the ack */ - delete_host_acknowledgement_comments(hst); - } - - } - - /* Not sure about this, but is old behaviour */ - if(hst->last_hard_state != hst->current_state) - hard_state_change = TRUE; - - if(state_change == TRUE || hard_state_change == TRUE) { - - /* update last state change times */ - hst->last_state_change = current_time; - if(hst->state_type == HARD_STATE) - hst->last_hard_state_change = current_time; - - /* update the event id */ - hst->last_event_id = hst->current_event_id; - hst->current_event_id = next_event_id; - next_event_id++; - - /* update the problem id when transitioning to a problem state */ - if(hst->last_state == HOST_UP) { - /* don't reset last problem id, or it will be zero the next time a problem is encountered */ - hst->current_problem_id = next_problem_id; - next_problem_id++; - } - - /* clear the problem id when transitioning from a problem state to an UP state */ - if(hst->current_state == HOST_UP) { - hst->last_problem_id = hst->current_problem_id; - hst->current_problem_id = 0L; - } - - /* write the host state change to the main log file */ - if(hst->state_type == HARD_STATE || (hst->state_type == SOFT_STATE && log_host_retries == TRUE)) - log_host_event(hst); - - /* check for start of flexible (non-fixed) scheduled downtime */ - /* It can start on soft states */ - check_pending_flex_host_downtime(hst); - - /* notify contacts about the recovery or problem if its a "hard" state */ - if(hst->state_type == HARD_STATE) - host_notification(hst, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); - - /* handle the host state change */ - handle_host_event(hst); - - /* the host just recovered, so reset the current host attempt */ - if(hst->current_state == HOST_UP) - hst->current_attempt = 1; - - /* the host recovered, so reset the current notification number and state flags (after the recovery notification has gone out) */ - if(hst->current_state == HOST_UP) { - hst->current_notification_number = 0; - hst->notified_on = 0; - } - } - - /* else the host state has not changed */ - else { - - /* notify contacts if host is still down or unreachable */ - if(hst->current_state != HOST_UP && hst->state_type == HARD_STATE) - host_notification(hst, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); - - /* if we're in a soft state and we should log host retries, do so now... */ - if(hst->state_type == SOFT_STATE && log_host_retries == TRUE) - log_host_event(hst); - } - - return OK; - } - /* Parses raw plugin output and returns: short and long output, perf data. */ -int parse_check_output(char *buf, char **short_output, char **long_output, char **perf_data, int escape_newlines_please, int newlines_are_escaped) { +int parse_check_output(char *buf, char **short_output, char **long_output, char **perf_data, int escape_newlines_please, int newlines_are_escaped) +{ int current_line = 0; int eof = FALSE; int in_perf_data = FALSE; @@ -3086,17 +3367,23 @@ int parse_check_output(char *buf, char **short_output, char **long_output, char int y = 0; /* Initialize output values. */ - if (short_output) + if (short_output) { *short_output = NULL; - if (long_output) + } + if (long_output) { *long_output = NULL; - if (perf_data) + } + if (perf_data) { *perf_data = NULL; + } /* No input provided or no output requested, nothing to do. */ - if (!buf || !*buf || (!short_output && !long_output && !perf_data)) - return OK; + if (!buf + || !*buf + || (!short_output && !long_output && !perf_data)) { + return OK; + } /* Initialize dynamic buffers (1KB chunk size). */ dbuf_init(&long_text, dbuf_chunk); @@ -3109,27 +3396,31 @@ int parse_check_output(char *buf, char **short_output, char **long_output, char if (buf[x] == '\\' && buf[x + 1] == '\\') { x++; buf[y++] = buf[x]; - } + } else if (buf[x] == '\\' && buf[x + 1] == 'n') { x++; buf[y++] = '\n'; - } - else + } + else { buf[y++] = buf[x]; } - buf[y] = '\0'; } + buf[y] = '\0'; + } /* Process each line of input. */ for (x = 0; !eof && buf[0]; x++) { /* Continue on until we reach the end of a line (or input). */ - if (buf[x] == '\n') + if (buf[x] == '\n') { buf[x] = '\0'; - else if (buf[x] == '\0') + } + else if (buf[x] == '\0') { eof = TRUE; - else + } + else { continue; + } /* Handle this line of input. */ current_line++; @@ -3138,80 +3429,105 @@ int parse_check_output(char *buf, char **short_output, char **long_output, char if (current_line == 1) { /* Get the short plugin output. If buf[0] is '|', strtok() will - * return buf+1 or NULL if buf[1] is '\0'. We use my_strtok() + * return buf+1 or NULL if buf[1] is '\0'. We use my_strtok_with_free() * instead which returns a pointer to '\0' in this case. */ - if ((ptr = my_strtok(buf, "|"))) { + ptr = my_strtok_with_free(buf, "|", FALSE); + if (ptr != NULL) { + if (short_output) { - strip(ptr); /* Remove leading and trailing whitespace. */ + + /* Remove leading and trailing whitespace. */ + strip(ptr); *short_output = strdup(ptr); - } + } /* Get the optional perf data. */ - if ((ptr = my_strtok(NULL, "\n"))) + ptr = my_strtok_with_free(NULL, "\n", FALSE); + if (ptr != NULL) { dbuf_strcat(&perf_text, ptr); } + /* free anything we've allocated */ + my_strtok_with_free(NULL, NULL, TRUE); } + } + /* Additional lines contain long plugin output and optional perf data. * Once we've hit perf data, the rest of the output is perf data. */ else if (in_perf_data) { - if (perf_text.buf && *perf_text.buf) + if (perf_text.buf && *perf_text.buf) { dbuf_strcat(&perf_text, " "); - dbuf_strcat(&perf_text, buf); - } + dbuf_strcat(&perf_text, buf); + } + /* Look for the perf data separator. */ else if (strchr(buf, '|')) { in_perf_data = TRUE; - if ((ptr = my_strtok(buf, "|"))) { + ptr = my_strtok_with_free(buf, "|", FALSE); + if (ptr != NULL) { /* Get the remaining long plugin output. */ - if (current_line > 2) + if (current_line > 2) { dbuf_strcat(&long_text, "\n"); + } dbuf_strcat(&long_text, ptr); /* Get the perf data. */ - if ((ptr = my_strtok(NULL, "\n"))) { - if (perf_text.buf && *perf_text.buf) + ptr = my_strtok_with_free(NULL, "\n", FALSE); + if (ptr != NULL) { + if (perf_text.buf && *perf_text.buf) { dbuf_strcat(&perf_text, " "); - dbuf_strcat(&perf_text, ptr); } + dbuf_strcat(&perf_text, ptr); } + /* free anything we've allocated */ + my_strtok_with_free(NULL, NULL, TRUE); } + } + /* Otherwise it's still just long output. */ else { - if (current_line > 2) + if (current_line > 2) { dbuf_strcat(&long_text, "\n"); - dbuf_strcat(&long_text, buf); } + dbuf_strcat(&long_text, buf); + } /* Point buf to the start of the next line. *(buf+x+1) will be a valid * memory reference on our next iteration or we are at the end of input * (eof == TRUE) and *(buf+x+1) will never be referenced. */ buf += x + 1; - x = -1; /* x will be incremented to 0 by the loop update. */ - } + + /* x will be incremented to 0 by the loop update. */ + x = -1; + } /* Save long output. */ if (long_output && long_text.buf && *long_text.buf) { + /* Escape newlines (and backslashes) in long output if requested. */ - if (escape_newlines_please) + if (escape_newlines_please) { *long_output = escape_newlines(long_text.buf); - else + } + else { *long_output = strdup(long_text.buf); } + } /* Save perf data. */ if (perf_data && perf_text.buf && *perf_text.buf) { - strip(perf_text.buf); /* Remove leading and trailing whitespace. */ + + /* Remove leading and trailing whitespace. */ + strip(perf_text.buf); *perf_data = strdup(perf_text.buf); - } + } /* free dynamic buffers */ dbuf_free(&long_text); dbuf_free(&perf_text); return OK; - } +} diff --git a/base/commands.c b/base/commands.c index 1381317..1bfc048 100644 --- a/base/commands.c +++ b/base/commands.c @@ -55,58 +55,63 @@ static struct { /* creates external command file as a named pipe (FIFO) and opens it for reading (non-blocked mode) */ -int open_command_file(void) { +int open_command_file(void) +{ struct stat st; int result = 0; - /* if we're not checking external commands, don't do anything */ - if(check_external_commands == FALSE) - return OK; - - /* the command file was already created */ - if(command_file_created == TRUE) + /* if the command file was created or + we're not checking external commands, don't do anything */ + if (command_file_created == TRUE || check_external_commands == FALSE) { return OK; + } /* reset umask (group needs write permissions) */ umask(S_IWOTH); /* use existing FIFO if possible */ - if(!(stat(command_file, &st) != -1 && (st.st_mode & S_IFIFO))) { + result = stat(command_file, &st); + if(!(result != -1 && (st.st_mode & S_IFIFO))) { /* create the external command file as a named pipe (FIFO) */ - if((result = mkfifo(command_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) != 0) { + result = mkfifo(command_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (result != 0) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Error: Could not create external command file '%s' as named pipe: (%d) -> %s. " + "If this file already exists and you are sure that another copy of Nagios is not running, you should delete this file.\n", + command_file, errno, strerror(errno)); - logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Could not create external command file '%s' as named pipe: (%d) -> %s. If this file already exists and you are sure that another copy of Nagios is not running, you should delete this file.\n", command_file, errno, strerror(errno)); return ERROR; - } } + } /* open the command file for reading (non-blocked) - O_TRUNC flag cannot be used due to errors on some systems */ /* NOTE: file must be opened read-write for poll() to work */ - if((command_file_fd = open(command_file, O_RDWR | O_NONBLOCK)) < 0) { + command_file_fd = open(command_file, O_RDWR | O_NONBLOCK); + if (command_file_fd < 0) { - logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Could not open external command file for reading via open(): (%d) -> %s\n", errno, strerror(errno)); + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Error: Could not open external command file for reading via open(): (%d) -> %s\n", errno, strerror(errno)); return ERROR; - } + } /* set a flag to remember we already created the file */ command_file_created = TRUE; return OK; - } +} /* closes the external command file FIFO and deletes it */ -int close_command_file(void) { - - /* if we're not checking external commands, don't do anything */ - if(check_external_commands == FALSE) - return OK; - - /* the command file wasn't created or was already cleaned up */ - if(command_file_created == FALSE) +int close_command_file(void) +{ + /* if the command file wasn't created or was already cleaned up + or we're not checking external commands, don't do anything */ + if (command_file_created == FALSE || check_external_commands == FALSE) { return OK; + } /* reset our flag */ command_file_created = FALSE; @@ -114,8 +119,11 @@ int close_command_file(void) { /* close the command file */ fclose(command_file_fp); + /* unlink the pipe */ + unlink(command_file); + return OK; - } +} /* shutdown command file worker thread */ @@ -393,23 +401,31 @@ int process_external_command1(char *cmd) { log_debug_info(DEBUGL_EXTERNALCOMMANDS, 2, "Raw command entry: %s\n", cmd); /* get the command entry time */ - if((temp_ptr = my_strtok(cmd, "[")) == NULL) + if((temp_ptr = my_strtok_with_free(cmd, "[", FALSE)) == NULL) return CMD_ERROR_MALFORMED_COMMAND; - if((temp_ptr = my_strtok(NULL, "]")) == NULL) + if((temp_ptr = my_strtok_with_free(NULL, "]", FALSE)) == NULL) { + temp_ptr = my_strtok_with_free(NULL, NULL, TRUE); return CMD_ERROR_MALFORMED_COMMAND; + } entry_time = (time_t)strtoul(temp_ptr, NULL, 10); /* get the command identifier */ - if((temp_ptr = my_strtok(NULL, ";")) == NULL) + if((temp_ptr = my_strtok_with_free(NULL, ";", FALSE)) == NULL) { + temp_ptr = my_strtok_with_free(NULL, NULL, TRUE); return CMD_ERROR_MALFORMED_COMMAND; - if((command_id = (char *)strdup(temp_ptr + 1)) == NULL) + } + else if((command_id = (char *)strdup(temp_ptr + 1)) == NULL) { + temp_ptr = my_strtok_with_free(NULL, NULL, TRUE); return CMD_ERROR_INTERNAL_ERROR; + } /* get the command arguments */ - if((temp_ptr = my_strtok(NULL, "\n")) == NULL) + if((temp_ptr = my_strtok_with_free(NULL, "\n", FALSE)) == NULL) args = (char *)strdup(""); else args = (char *)strdup(temp_ptr); + + temp_ptr = my_strtok_with_free(NULL, NULL, TRUE); if(args == NULL) { my_free(command_id); return CMD_ERROR_INTERNAL_ERROR; @@ -421,79 +437,79 @@ int process_external_command1(char *cmd) { /**** PROCESS COMMANDS ****/ /**************************/ - if(!strcmp(command_id, "ENTER_STANDBY_MODE") || !strcmp(command_id, "DISABLE_NOTIFICATIONS")) + if(!strcasecmp(command_id, "ENTER_STANDBY_MODE") || !strcasecmp(command_id, "DISABLE_NOTIFICATIONS")) command_type = CMD_DISABLE_NOTIFICATIONS; - else if(!strcmp(command_id, "ENTER_ACTIVE_MODE") || !strcmp(command_id, "ENABLE_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENTER_ACTIVE_MODE") || !strcasecmp(command_id, "ENABLE_NOTIFICATIONS")) command_type = CMD_ENABLE_NOTIFICATIONS; - else if(!strcmp(command_id, "SHUTDOWN_PROGRAM") || !strcmp(command_id, "SHUTDOWN_PROCESS")) + else if(!strcasecmp(command_id, "SHUTDOWN_PROGRAM") || !strcasecmp(command_id, "SHUTDOWN_PROCESS")) command_type = CMD_SHUTDOWN_PROCESS; - else if(!strcmp(command_id, "RESTART_PROGRAM") || !strcmp(command_id, "RESTART_PROCESS")) + else if(!strcasecmp(command_id, "RESTART_PROGRAM") || !strcasecmp(command_id, "RESTART_PROCESS")) command_type = CMD_RESTART_PROCESS; - else if(!strcmp(command_id, "SAVE_STATE_INFORMATION")) + else if(!strcasecmp(command_id, "SAVE_STATE_INFORMATION")) command_type = CMD_SAVE_STATE_INFORMATION; - else if(!strcmp(command_id, "READ_STATE_INFORMATION")) + else if(!strcasecmp(command_id, "READ_STATE_INFORMATION")) command_type = CMD_READ_STATE_INFORMATION; - else if(!strcmp(command_id, "ENABLE_EVENT_HANDLERS")) + else if(!strcasecmp(command_id, "ENABLE_EVENT_HANDLERS")) command_type = CMD_ENABLE_EVENT_HANDLERS; - else if(!strcmp(command_id, "DISABLE_EVENT_HANDLERS")) + else if(!strcasecmp(command_id, "DISABLE_EVENT_HANDLERS")) command_type = CMD_DISABLE_EVENT_HANDLERS; - else if(!strcmp(command_id, "ENABLE_PERFORMANCE_DATA")) + else if(!strcasecmp(command_id, "ENABLE_PERFORMANCE_DATA")) command_type = CMD_ENABLE_PERFORMANCE_DATA; - else if(!strcmp(command_id, "DISABLE_PERFORMANCE_DATA")) + else if(!strcasecmp(command_id, "DISABLE_PERFORMANCE_DATA")) command_type = CMD_DISABLE_PERFORMANCE_DATA; - else if(!strcmp(command_id, "START_EXECUTING_HOST_CHECKS")) + else if(!strcasecmp(command_id, "START_EXECUTING_HOST_CHECKS")) command_type = CMD_START_EXECUTING_HOST_CHECKS; - else if(!strcmp(command_id, "STOP_EXECUTING_HOST_CHECKS")) + else if(!strcasecmp(command_id, "STOP_EXECUTING_HOST_CHECKS")) command_type = CMD_STOP_EXECUTING_HOST_CHECKS; - else if(!strcmp(command_id, "START_EXECUTING_SVC_CHECKS")) + else if(!strcasecmp(command_id, "START_EXECUTING_SVC_CHECKS")) command_type = CMD_START_EXECUTING_SVC_CHECKS; - else if(!strcmp(command_id, "STOP_EXECUTING_SVC_CHECKS")) + else if(!strcasecmp(command_id, "STOP_EXECUTING_SVC_CHECKS")) command_type = CMD_STOP_EXECUTING_SVC_CHECKS; - else if(!strcmp(command_id, "START_ACCEPTING_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "START_ACCEPTING_PASSIVE_HOST_CHECKS")) command_type = CMD_START_ACCEPTING_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "STOP_ACCEPTING_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "STOP_ACCEPTING_PASSIVE_HOST_CHECKS")) command_type = CMD_STOP_ACCEPTING_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "START_ACCEPTING_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "START_ACCEPTING_PASSIVE_SVC_CHECKS")) command_type = CMD_START_ACCEPTING_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "STOP_ACCEPTING_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "STOP_ACCEPTING_PASSIVE_SVC_CHECKS")) command_type = CMD_STOP_ACCEPTING_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "START_OBSESSING_OVER_HOST_CHECKS")) + else if(!strcasecmp(command_id, "START_OBSESSING_OVER_HOST_CHECKS")) command_type = CMD_START_OBSESSING_OVER_HOST_CHECKS; - else if(!strcmp(command_id, "STOP_OBSESSING_OVER_HOST_CHECKS")) + else if(!strcasecmp(command_id, "STOP_OBSESSING_OVER_HOST_CHECKS")) command_type = CMD_STOP_OBSESSING_OVER_HOST_CHECKS; - else if(!strcmp(command_id, "START_OBSESSING_OVER_SVC_CHECKS")) + else if(!strcasecmp(command_id, "START_OBSESSING_OVER_SVC_CHECKS")) command_type = CMD_START_OBSESSING_OVER_SVC_CHECKS; - else if(!strcmp(command_id, "STOP_OBSESSING_OVER_SVC_CHECKS")) + else if(!strcasecmp(command_id, "STOP_OBSESSING_OVER_SVC_CHECKS")) command_type = CMD_STOP_OBSESSING_OVER_SVC_CHECKS; - else if(!strcmp(command_id, "ENABLE_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "ENABLE_FLAP_DETECTION")) command_type = CMD_ENABLE_FLAP_DETECTION; - else if(!strcmp(command_id, "DISABLE_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "DISABLE_FLAP_DETECTION")) command_type = CMD_DISABLE_FLAP_DETECTION; - else if(!strcmp(command_id, "CHANGE_GLOBAL_HOST_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "CHANGE_GLOBAL_HOST_EVENT_HANDLER")) command_type = CMD_CHANGE_GLOBAL_HOST_EVENT_HANDLER; - else if(!strcmp(command_id, "CHANGE_GLOBAL_SVC_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "CHANGE_GLOBAL_SVC_EVENT_HANDLER")) command_type = CMD_CHANGE_GLOBAL_SVC_EVENT_HANDLER; - else if(!strcmp(command_id, "ENABLE_SERVICE_FRESHNESS_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICE_FRESHNESS_CHECKS")) command_type = CMD_ENABLE_SERVICE_FRESHNESS_CHECKS; - else if(!strcmp(command_id, "DISABLE_SERVICE_FRESHNESS_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICE_FRESHNESS_CHECKS")) command_type = CMD_DISABLE_SERVICE_FRESHNESS_CHECKS; - else if(!strcmp(command_id, "ENABLE_HOST_FRESHNESS_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOST_FRESHNESS_CHECKS")) command_type = CMD_ENABLE_HOST_FRESHNESS_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOST_FRESHNESS_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOST_FRESHNESS_CHECKS")) command_type = CMD_DISABLE_HOST_FRESHNESS_CHECKS; @@ -501,171 +517,171 @@ int process_external_command1(char *cmd) { /**** HOST-RELATED COMMANDS ****/ /*******************************/ - else if(!strcmp(command_id, "ADD_HOST_COMMENT")) + else if(!strcasecmp(command_id, "ADD_HOST_COMMENT")) command_type = CMD_ADD_HOST_COMMENT; - else if(!strcmp(command_id, "DEL_HOST_COMMENT")) + else if(!strcasecmp(command_id, "DEL_HOST_COMMENT")) command_type = CMD_DEL_HOST_COMMENT; - else if(!strcmp(command_id, "DEL_ALL_HOST_COMMENTS")) + else if(!strcasecmp(command_id, "DEL_ALL_HOST_COMMENTS")) command_type = CMD_DEL_ALL_HOST_COMMENTS; - else if(!strcmp(command_id, "DELAY_HOST_NOTIFICATION")) + else if(!strcasecmp(command_id, "DELAY_HOST_NOTIFICATION")) command_type = CMD_DELAY_HOST_NOTIFICATION; - else if(!strcmp(command_id, "ENABLE_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_HOST_NOTIFICATIONS")) command_type = CMD_ENABLE_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_HOST_NOTIFICATIONS")) command_type = CMD_DISABLE_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST")) + else if(!strcasecmp(command_id, "ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST")) command_type = CMD_ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST; - else if(!strcmp(command_id, "DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST")) + else if(!strcasecmp(command_id, "DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST")) command_type = CMD_DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST; - else if(!strcmp(command_id, "ENABLE_HOST_AND_CHILD_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_HOST_AND_CHILD_NOTIFICATIONS")) command_type = CMD_ENABLE_HOST_AND_CHILD_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_HOST_AND_CHILD_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_HOST_AND_CHILD_NOTIFICATIONS")) command_type = CMD_DISABLE_HOST_AND_CHILD_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_HOST_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_HOST_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_HOST_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_HOST_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_HOST_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_HOST_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_HOST_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOST_SVC_CHECKS")) command_type = CMD_ENABLE_HOST_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOST_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOST_SVC_CHECKS")) command_type = CMD_DISABLE_HOST_SVC_CHECKS; - else if(!strcmp(command_id, "ENABLE_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_PASSIVE_HOST_CHECKS")) command_type = CMD_ENABLE_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "DISABLE_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_PASSIVE_HOST_CHECKS")) command_type = CMD_DISABLE_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "SCHEDULE_HOST_SVC_CHECKS")) + else if(!strcasecmp(command_id, "SCHEDULE_HOST_SVC_CHECKS")) command_type = CMD_SCHEDULE_HOST_SVC_CHECKS; - else if(!strcmp(command_id, "SCHEDULE_FORCED_HOST_SVC_CHECKS")) + else if(!strcasecmp(command_id, "SCHEDULE_FORCED_HOST_SVC_CHECKS")) command_type = CMD_SCHEDULE_FORCED_HOST_SVC_CHECKS; - else if(!strcmp(command_id, "ACKNOWLEDGE_HOST_PROBLEM")) + else if(!strcasecmp(command_id, "ACKNOWLEDGE_HOST_PROBLEM")) command_type = CMD_ACKNOWLEDGE_HOST_PROBLEM; - else if(!strcmp(command_id, "REMOVE_HOST_ACKNOWLEDGEMENT")) + else if(!strcasecmp(command_id, "REMOVE_HOST_ACKNOWLEDGEMENT")) command_type = CMD_REMOVE_HOST_ACKNOWLEDGEMENT; - else if(!strcmp(command_id, "ENABLE_HOST_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "ENABLE_HOST_EVENT_HANDLER")) command_type = CMD_ENABLE_HOST_EVENT_HANDLER; - else if(!strcmp(command_id, "DISABLE_HOST_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "DISABLE_HOST_EVENT_HANDLER")) command_type = CMD_DISABLE_HOST_EVENT_HANDLER; - else if(!strcmp(command_id, "ENABLE_HOST_CHECK")) + else if(!strcasecmp(command_id, "ENABLE_HOST_CHECK")) command_type = CMD_ENABLE_HOST_CHECK; - else if(!strcmp(command_id, "DISABLE_HOST_CHECK")) + else if(!strcasecmp(command_id, "DISABLE_HOST_CHECK")) command_type = CMD_DISABLE_HOST_CHECK; - else if(!strcmp(command_id, "SCHEDULE_HOST_CHECK")) + else if(!strcasecmp(command_id, "SCHEDULE_HOST_CHECK")) command_type = CMD_SCHEDULE_HOST_CHECK; - else if(!strcmp(command_id, "SCHEDULE_FORCED_HOST_CHECK")) + else if(!strcasecmp(command_id, "SCHEDULE_FORCED_HOST_CHECK")) command_type = CMD_SCHEDULE_FORCED_HOST_CHECK; - else if(!strcmp(command_id, "SCHEDULE_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_HOST_DOWNTIME")) command_type = CMD_SCHEDULE_HOST_DOWNTIME; - else if(!strcmp(command_id, "SCHEDULE_HOST_SVC_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_HOST_SVC_DOWNTIME")) command_type = CMD_SCHEDULE_HOST_SVC_DOWNTIME; - else if(!strcmp(command_id, "DEL_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "DEL_HOST_DOWNTIME")) command_type = CMD_DEL_HOST_DOWNTIME; - else if(!strcmp(command_id, "DEL_DOWNTIME_BY_HOST_NAME")) + else if(!strcasecmp(command_id, "DEL_DOWNTIME_BY_HOST_NAME")) command_type = CMD_DEL_DOWNTIME_BY_HOST_NAME; - else if(!strcmp(command_id, "DEL_DOWNTIME_BY_HOSTGROUP_NAME")) + else if(!strcasecmp(command_id, "DEL_DOWNTIME_BY_HOSTGROUP_NAME")) command_type = CMD_DEL_DOWNTIME_BY_HOSTGROUP_NAME; - else if(!strcmp(command_id, "DEL_DOWNTIME_BY_START_TIME_COMMENT")) + else if(!strcasecmp(command_id, "DEL_DOWNTIME_BY_START_TIME_COMMENT")) command_type = CMD_DEL_DOWNTIME_BY_START_TIME_COMMENT; - else if(!strcmp(command_id, "ENABLE_HOST_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "ENABLE_HOST_FLAP_DETECTION")) command_type = CMD_ENABLE_HOST_FLAP_DETECTION; - else if(!strcmp(command_id, "DISABLE_HOST_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "DISABLE_HOST_FLAP_DETECTION")) command_type = CMD_DISABLE_HOST_FLAP_DETECTION; - else if(!strcmp(command_id, "START_OBSESSING_OVER_HOST")) + else if(!strcasecmp(command_id, "START_OBSESSING_OVER_HOST")) command_type = CMD_START_OBSESSING_OVER_HOST; - else if(!strcmp(command_id, "STOP_OBSESSING_OVER_HOST")) + else if(!strcasecmp(command_id, "STOP_OBSESSING_OVER_HOST")) command_type = CMD_STOP_OBSESSING_OVER_HOST; - else if(!strcmp(command_id, "CHANGE_HOST_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "CHANGE_HOST_EVENT_HANDLER")) command_type = CMD_CHANGE_HOST_EVENT_HANDLER; - else if(!strcmp(command_id, "CHANGE_HOST_CHECK_COMMAND")) + else if(!strcasecmp(command_id, "CHANGE_HOST_CHECK_COMMAND")) command_type = CMD_CHANGE_HOST_CHECK_COMMAND; - else if(!strcmp(command_id, "CHANGE_NORMAL_HOST_CHECK_INTERVAL")) + else if(!strcasecmp(command_id, "CHANGE_NORMAL_HOST_CHECK_INTERVAL")) command_type = CMD_CHANGE_NORMAL_HOST_CHECK_INTERVAL; - else if(!strcmp(command_id, "CHANGE_RETRY_HOST_CHECK_INTERVAL")) + else if(!strcasecmp(command_id, "CHANGE_RETRY_HOST_CHECK_INTERVAL")) command_type = CMD_CHANGE_RETRY_HOST_CHECK_INTERVAL; - else if(!strcmp(command_id, "CHANGE_MAX_HOST_CHECK_ATTEMPTS")) + else if(!strcasecmp(command_id, "CHANGE_MAX_HOST_CHECK_ATTEMPTS")) command_type = CMD_CHANGE_MAX_HOST_CHECK_ATTEMPTS; - else if(!strcmp(command_id, "SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME")) command_type = CMD_SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME; - else if(!strcmp(command_id, "SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME")) command_type = CMD_SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME; - else if(!strcmp(command_id, "SET_HOST_NOTIFICATION_NUMBER")) + else if(!strcasecmp(command_id, "SET_HOST_NOTIFICATION_NUMBER")) command_type = CMD_SET_HOST_NOTIFICATION_NUMBER; - else if(!strcmp(command_id, "CHANGE_HOST_CHECK_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_HOST_CHECK_TIMEPERIOD")) command_type = CMD_CHANGE_HOST_CHECK_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_CUSTOM_HOST_VAR")) + else if(!strcasecmp(command_id, "CHANGE_CUSTOM_HOST_VAR")) command_type = CMD_CHANGE_CUSTOM_HOST_VAR; - else if(!strcmp(command_id, "SEND_CUSTOM_HOST_NOTIFICATION")) + else if(!strcasecmp(command_id, "SEND_CUSTOM_HOST_NOTIFICATION")) command_type = CMD_SEND_CUSTOM_HOST_NOTIFICATION; - else if(!strcmp(command_id, "CHANGE_HOST_NOTIFICATION_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_HOST_NOTIFICATION_TIMEPERIOD")) command_type = CMD_CHANGE_HOST_NOTIFICATION_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_HOST_MODATTR")) + else if(!strcasecmp(command_id, "CHANGE_HOST_MODATTR")) command_type = CMD_CHANGE_HOST_MODATTR; - else if (!strcmp(command_id,"CLEAR_HOST_FLAPPING_STATE")) + else if (!strcasecmp(command_id,"CLEAR_HOST_FLAPPING_STATE")) command_type = CMD_CLEAR_HOST_FLAPPING_STATE; /************************************/ /**** HOSTGROUP-RELATED COMMANDS ****/ /************************************/ - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_HOST_NOTIFICATIONS")) command_type = CMD_ENABLE_HOSTGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_HOST_NOTIFICATIONS")) command_type = CMD_DISABLE_HOSTGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_HOSTGROUP_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_HOSTGROUP_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_HOST_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_HOST_CHECKS")) command_type = CMD_ENABLE_HOSTGROUP_HOST_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_HOST_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_HOST_CHECKS")) command_type = CMD_DISABLE_HOSTGROUP_HOST_CHECKS; - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS")) command_type = CMD_ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS")) command_type = CMD_DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_SVC_CHECKS")) command_type = CMD_ENABLE_HOSTGROUP_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_SVC_CHECKS")) command_type = CMD_DISABLE_HOSTGROUP_SVC_CHECKS; - else if(!strcmp(command_id, "ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS")) command_type = CMD_ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS")) command_type = CMD_DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "SCHEDULE_HOSTGROUP_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_HOSTGROUP_HOST_DOWNTIME")) command_type = CMD_SCHEDULE_HOSTGROUP_HOST_DOWNTIME; - else if(!strcmp(command_id, "SCHEDULE_HOSTGROUP_SVC_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_HOSTGROUP_SVC_DOWNTIME")) command_type = CMD_SCHEDULE_HOSTGROUP_SVC_DOWNTIME; @@ -673,139 +689,139 @@ int process_external_command1(char *cmd) { /**** SERVICE-RELATED COMMANDS ****/ /**********************************/ - else if(!strcmp(command_id, "ADD_SVC_COMMENT")) + else if(!strcasecmp(command_id, "ADD_SVC_COMMENT")) command_type = CMD_ADD_SVC_COMMENT; - else if(!strcmp(command_id, "DEL_SVC_COMMENT")) + else if(!strcasecmp(command_id, "DEL_SVC_COMMENT")) command_type = CMD_DEL_SVC_COMMENT; - else if(!strcmp(command_id, "DEL_ALL_SVC_COMMENTS")) + else if(!strcasecmp(command_id, "DEL_ALL_SVC_COMMENTS")) command_type = CMD_DEL_ALL_SVC_COMMENTS; - else if(!strcmp(command_id, "SCHEDULE_SVC_CHECK")) + else if(!strcasecmp(command_id, "SCHEDULE_SVC_CHECK")) command_type = CMD_SCHEDULE_SVC_CHECK; - else if(!strcmp(command_id, "SCHEDULE_FORCED_SVC_CHECK")) + else if(!strcasecmp(command_id, "SCHEDULE_FORCED_SVC_CHECK")) command_type = CMD_SCHEDULE_FORCED_SVC_CHECK; - else if(!strcmp(command_id, "ENABLE_SVC_CHECK")) + else if(!strcasecmp(command_id, "ENABLE_SVC_CHECK")) command_type = CMD_ENABLE_SVC_CHECK; - else if(!strcmp(command_id, "DISABLE_SVC_CHECK")) + else if(!strcasecmp(command_id, "DISABLE_SVC_CHECK")) command_type = CMD_DISABLE_SVC_CHECK; - else if(!strcmp(command_id, "ENABLE_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_PASSIVE_SVC_CHECKS")) command_type = CMD_ENABLE_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_PASSIVE_SVC_CHECKS")) command_type = CMD_DISABLE_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "DELAY_SVC_NOTIFICATION")) + else if(!strcasecmp(command_id, "DELAY_SVC_NOTIFICATION")) command_type = CMD_DELAY_SVC_NOTIFICATION; - else if(!strcmp(command_id, "ENABLE_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "PROCESS_SERVICE_CHECK_RESULT")) + else if(!strcasecmp(command_id, "PROCESS_SERVICE_CHECK_RESULT")) command_type = CMD_PROCESS_SERVICE_CHECK_RESULT; - else if(!strcmp(command_id, "PROCESS_HOST_CHECK_RESULT")) + else if(!strcasecmp(command_id, "PROCESS_HOST_CHECK_RESULT")) command_type = CMD_PROCESS_HOST_CHECK_RESULT; - else if(!strcmp(command_id, "ENABLE_SVC_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "ENABLE_SVC_EVENT_HANDLER")) command_type = CMD_ENABLE_SVC_EVENT_HANDLER; - else if(!strcmp(command_id, "DISABLE_SVC_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "DISABLE_SVC_EVENT_HANDLER")) command_type = CMD_DISABLE_SVC_EVENT_HANDLER; - else if(!strcmp(command_id, "ENABLE_SVC_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "ENABLE_SVC_FLAP_DETECTION")) command_type = CMD_ENABLE_SVC_FLAP_DETECTION; - else if(!strcmp(command_id, "DISABLE_SVC_FLAP_DETECTION")) + else if(!strcasecmp(command_id, "DISABLE_SVC_FLAP_DETECTION")) command_type = CMD_DISABLE_SVC_FLAP_DETECTION; - else if(!strcmp(command_id, "SCHEDULE_SVC_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_SVC_DOWNTIME")) command_type = CMD_SCHEDULE_SVC_DOWNTIME; - else if(!strcmp(command_id, "DEL_SVC_DOWNTIME")) + else if(!strcasecmp(command_id, "DEL_SVC_DOWNTIME")) command_type = CMD_DEL_SVC_DOWNTIME; - else if(!strcmp(command_id, "ACKNOWLEDGE_SVC_PROBLEM")) + else if(!strcasecmp(command_id, "ACKNOWLEDGE_SVC_PROBLEM")) command_type = CMD_ACKNOWLEDGE_SVC_PROBLEM; - else if(!strcmp(command_id, "REMOVE_SVC_ACKNOWLEDGEMENT")) + else if(!strcasecmp(command_id, "REMOVE_SVC_ACKNOWLEDGEMENT")) command_type = CMD_REMOVE_SVC_ACKNOWLEDGEMENT; - else if(!strcmp(command_id, "START_OBSESSING_OVER_SVC")) + else if(!strcasecmp(command_id, "START_OBSESSING_OVER_SVC")) command_type = CMD_START_OBSESSING_OVER_SVC; - else if(!strcmp(command_id, "STOP_OBSESSING_OVER_SVC")) + else if(!strcasecmp(command_id, "STOP_OBSESSING_OVER_SVC")) command_type = CMD_STOP_OBSESSING_OVER_SVC; - else if(!strcmp(command_id, "CHANGE_SVC_EVENT_HANDLER")) + else if(!strcasecmp(command_id, "CHANGE_SVC_EVENT_HANDLER")) command_type = CMD_CHANGE_SVC_EVENT_HANDLER; - else if(!strcmp(command_id, "CHANGE_SVC_CHECK_COMMAND")) + else if(!strcasecmp(command_id, "CHANGE_SVC_CHECK_COMMAND")) command_type = CMD_CHANGE_SVC_CHECK_COMMAND; - else if(!strcmp(command_id, "CHANGE_NORMAL_SVC_CHECK_INTERVAL")) + else if(!strcasecmp(command_id, "CHANGE_NORMAL_SVC_CHECK_INTERVAL")) command_type = CMD_CHANGE_NORMAL_SVC_CHECK_INTERVAL; - else if(!strcmp(command_id, "CHANGE_RETRY_SVC_CHECK_INTERVAL")) + else if(!strcasecmp(command_id, "CHANGE_RETRY_SVC_CHECK_INTERVAL")) command_type = CMD_CHANGE_RETRY_SVC_CHECK_INTERVAL; - else if(!strcmp(command_id, "CHANGE_MAX_SVC_CHECK_ATTEMPTS")) + else if(!strcasecmp(command_id, "CHANGE_MAX_SVC_CHECK_ATTEMPTS")) command_type = CMD_CHANGE_MAX_SVC_CHECK_ATTEMPTS; - else if(!strcmp(command_id, "SET_SVC_NOTIFICATION_NUMBER")) + else if(!strcasecmp(command_id, "SET_SVC_NOTIFICATION_NUMBER")) command_type = CMD_SET_SVC_NOTIFICATION_NUMBER; - else if(!strcmp(command_id, "CHANGE_SVC_CHECK_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_SVC_CHECK_TIMEPERIOD")) command_type = CMD_CHANGE_SVC_CHECK_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_CUSTOM_SVC_VAR")) + else if(!strcasecmp(command_id, "CHANGE_CUSTOM_SVC_VAR")) command_type = CMD_CHANGE_CUSTOM_SVC_VAR; - else if(!strcmp(command_id, "CHANGE_CUSTOM_CONTACT_VAR")) + else if(!strcasecmp(command_id, "CHANGE_CUSTOM_CONTACT_VAR")) command_type = CMD_CHANGE_CUSTOM_CONTACT_VAR; - else if(!strcmp(command_id, "SEND_CUSTOM_SVC_NOTIFICATION")) + else if(!strcasecmp(command_id, "SEND_CUSTOM_SVC_NOTIFICATION")) command_type = CMD_SEND_CUSTOM_SVC_NOTIFICATION; - else if(!strcmp(command_id, "CHANGE_SVC_NOTIFICATION_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_SVC_NOTIFICATION_TIMEPERIOD")) command_type = CMD_CHANGE_SVC_NOTIFICATION_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_SVC_MODATTR")) + else if(!strcasecmp(command_id, "CHANGE_SVC_MODATTR")) command_type = CMD_CHANGE_SVC_MODATTR; - else if (!strcmp(command_id,"CLEAR_SVC_FLAPPING_STATE")) + else if (!strcasecmp(command_id,"CLEAR_SVC_FLAPPING_STATE")) command_type = CMD_CLEAR_SVC_FLAPPING_STATE; /***************************************/ /**** SERVICEGROUP-RELATED COMMANDS ****/ /***************************************/ - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS")) command_type = CMD_ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS")) command_type = CMD_DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_HOST_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_HOST_CHECKS")) command_type = CMD_ENABLE_SERVICEGROUP_HOST_CHECKS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_HOST_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_HOST_CHECKS")) command_type = CMD_DISABLE_SERVICEGROUP_HOST_CHECKS; - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS")) command_type = CMD_ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS")) command_type = CMD_DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS; - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_SVC_CHECKS")) command_type = CMD_ENABLE_SERVICEGROUP_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_SVC_CHECKS")) command_type = CMD_DISABLE_SERVICEGROUP_SVC_CHECKS; - else if(!strcmp(command_id, "ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS")) command_type = CMD_ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS")) + else if(!strcasecmp(command_id, "DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS")) command_type = CMD_DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS; - else if(!strcmp(command_id, "SCHEDULE_SERVICEGROUP_HOST_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_SERVICEGROUP_HOST_DOWNTIME")) command_type = CMD_SCHEDULE_SERVICEGROUP_HOST_DOWNTIME; - else if(!strcmp(command_id, "SCHEDULE_SERVICEGROUP_SVC_DOWNTIME")) + else if(!strcasecmp(command_id, "SCHEDULE_SERVICEGROUP_SVC_DOWNTIME")) command_type = CMD_SCHEDULE_SERVICEGROUP_SVC_DOWNTIME; @@ -813,41 +829,41 @@ int process_external_command1(char *cmd) { /**** CONTACT-RELATED COMMANDS ****/ /**********************************/ - else if(!strcmp(command_id, "ENABLE_CONTACT_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_CONTACT_HOST_NOTIFICATIONS")) command_type = CMD_ENABLE_CONTACT_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_CONTACT_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_CONTACT_HOST_NOTIFICATIONS")) command_type = CMD_DISABLE_CONTACT_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_CONTACT_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_CONTACT_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_CONTACT_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_CONTACT_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_CONTACT_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_CONTACT_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD")) command_type = CMD_CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD")) + else if(!strcasecmp(command_id, "CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD")) command_type = CMD_CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD; - else if(!strcmp(command_id, "CHANGE_CONTACT_MODATTR")) + else if(!strcasecmp(command_id, "CHANGE_CONTACT_MODATTR")) command_type = CMD_CHANGE_CONTACT_MODATTR; - else if(!strcmp(command_id, "CHANGE_CONTACT_MODHATTR")) + else if(!strcasecmp(command_id, "CHANGE_CONTACT_MODHATTR")) command_type = CMD_CHANGE_CONTACT_MODHATTR; - else if(!strcmp(command_id, "CHANGE_CONTACT_MODSATTR")) + else if(!strcasecmp(command_id, "CHANGE_CONTACT_MODSATTR")) command_type = CMD_CHANGE_CONTACT_MODSATTR; /***************************************/ /**** CONTACTGROUP-RELATED COMMANDS ****/ /***************************************/ - else if(!strcmp(command_id, "ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS")) command_type = CMD_ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS")) command_type = CMD_DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS; - else if(!strcmp(command_id, "ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS")) command_type = CMD_ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS; - else if(!strcmp(command_id, "DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS")) + else if(!strcasecmp(command_id, "DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS")) command_type = CMD_DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS; @@ -855,7 +871,7 @@ int process_external_command1(char *cmd) { /****** MISC COMMANDS *****/ /**************************/ - else if(!strcmp(command_id, "PROCESS_FILE")) + else if(!strcasecmp(command_id, "PROCESS_FILE")) command_type = CMD_PROCESS_FILE; @@ -1341,6 +1357,7 @@ int process_host_command(int cmd, time_t entry_time, char *args) { servicesmember *temp_servicesmember = NULL; char *str = NULL; char *buf[2] = {NULL, NULL}; + char *author, *comment; int intval = 0; printf("ARGS: %s\n", args); @@ -1471,6 +1488,13 @@ int process_host_command(int cmd, time_t entry_time, char *args) { break; } + if ((author = my_strtok(NULL, ";")) != NULL) { + if ((comment = my_strtok(NULL, ";")) != NULL) { + time_t current_time = time(NULL); + add_new_host_comment(USER_COMMENT, host_name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + } + } + return OK; } @@ -1478,11 +1502,13 @@ int process_host_command(int cmd, time_t entry_time, char *args) { /* processes an external hostgroup command */ int process_hostgroup_command(int cmd, time_t entry_time, char *args) { char *hostgroup_name = NULL; + char *author = NULL, *comment = NULL; hostgroup *temp_hostgroup = NULL; hostsmember *temp_member = NULL; host *temp_host = NULL; service *temp_service = NULL; servicesmember *temp_servicesmember = NULL; + time_t current_time = time(NULL); /* get the hostgroup name */ if((hostgroup_name = my_strtok(args, ";")) == NULL) @@ -1492,6 +1518,9 @@ int process_hostgroup_command(int cmd, time_t entry_time, char *args) { if((temp_hostgroup = find_hostgroup(hostgroup_name)) == NULL) return ERROR; + if ((author = my_strtok(NULL, ";")) != NULL) + comment = my_strtok(NULL, ";"); + /* loop through all hosts in the hostgroup */ for(temp_member = temp_hostgroup->members; temp_member != NULL; temp_member = temp_member->next) { @@ -1502,26 +1531,38 @@ int process_hostgroup_command(int cmd, time_t entry_time, char *args) { case CMD_ENABLE_HOSTGROUP_HOST_NOTIFICATIONS: enable_host_notifications(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_HOST_NOTIFICATIONS: disable_host_notifications(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_HOSTGROUP_HOST_CHECKS: enable_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_HOST_CHECKS: disable_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS: enable_passive_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS: disable_passive_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; default: @@ -1535,26 +1576,38 @@ int process_hostgroup_command(int cmd, time_t entry_time, char *args) { case CMD_ENABLE_HOSTGROUP_SVC_NOTIFICATIONS: enable_service_notifications(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_SVC_NOTIFICATIONS: disable_service_notifications(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_HOSTGROUP_SVC_CHECKS: enable_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_SVC_CHECKS: disable_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS: enable_passive_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS: disable_passive_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_host->name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; default: @@ -1579,6 +1632,7 @@ int process_service_command(int cmd, time_t entry_time, char *args) { service *temp_service = NULL; char *str = NULL; char *buf[2] = {NULL, NULL}; + char *author, *comment; int intval = 0; /* get the host name */ @@ -1671,6 +1725,13 @@ int process_service_command(int cmd, time_t entry_time, char *args) { break; } + if ((author = my_strtok(NULL, ";")) != NULL) { + if ((comment = my_strtok(NULL, ";")) != NULL) { + time_t current_time = time(NULL); + add_new_service_comment(USER_COMMENT, host_name, svc_description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + } + } + return OK; } @@ -1678,11 +1739,13 @@ int process_service_command(int cmd, time_t entry_time, char *args) { /* processes an external servicegroup command */ int process_servicegroup_command(int cmd, time_t entry_time, char *args) { char *servicegroup_name = NULL; + char *author = NULL, *comment = NULL; servicegroup *temp_servicegroup = NULL; servicesmember *temp_member = NULL; host *temp_host = NULL; host *last_host = NULL; service *temp_service = NULL; + time_t current_time = time(NULL); /* get the servicegroup name */ if((servicegroup_name = my_strtok(args, ";")) == NULL) @@ -1692,6 +1755,9 @@ int process_servicegroup_command(int cmd, time_t entry_time, char *args) { if((temp_servicegroup = find_servicegroup(servicegroup_name)) == NULL) return ERROR; + if ((author = my_strtok(NULL, ";")) != NULL) + comment = my_strtok(NULL, ";"); + switch(cmd) { case CMD_ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS: @@ -1712,26 +1778,38 @@ int process_servicegroup_command(int cmd, time_t entry_time, char *args) { case CMD_ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS: enable_service_notifications(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS: disable_service_notifications(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_SERVICEGROUP_SVC_CHECKS: enable_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_SVC_CHECKS: disable_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS: enable_passive_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS: disable_passive_service_checks(temp_service); + if (comment) + add_new_service_comment(USER_COMMENT, temp_member->host_name, temp_service->description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; default: @@ -1762,26 +1840,38 @@ int process_servicegroup_command(int cmd, time_t entry_time, char *args) { case CMD_ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS: enable_host_notifications(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS: disable_host_notifications(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_SERVICEGROUP_HOST_CHECKS: enable_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_HOST_CHECKS: disable_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS: enable_passive_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; case CMD_DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS: disable_passive_host_checks(temp_host); + if (comment) + add_new_host_comment(USER_COMMENT, temp_host->name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); break; default: @@ -2028,6 +2118,7 @@ int cmd_delay_notification(int cmd, char *args) { service *temp_service = NULL; char *host_name = NULL; char *svc_description = NULL; + char *author, *comment; time_t delay_time = 0L; /* get the host name */ @@ -2054,7 +2145,7 @@ int cmd_delay_notification(int cmd, char *args) { } /* get the time that we should delay until... */ - if((temp_ptr = my_strtok(NULL, "\n")) == NULL) + if((temp_ptr = my_strtok(NULL, ";")) == NULL) return ERROR; delay_time = strtoul(temp_ptr, NULL, 10); @@ -2064,6 +2155,16 @@ int cmd_delay_notification(int cmd, char *args) { else temp_host->next_notification = delay_time; + if ((author = my_strtok(NULL, ";")) != NULL) { + if ((comment = my_strtok(NULL, ";")) != NULL) { + time_t current_time = time(NULL); + if(cmd == CMD_DELAY_SVC_NOTIFICATION) + add_new_service_comment(USER_COMMENT, host_name, svc_description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + else + add_new_host_comment(USER_COMMENT, host_name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + } + } + return OK; } @@ -2077,10 +2178,11 @@ int cmd_schedule_check(int cmd, char *args) { servicesmember *temp_servicesmember = NULL; char *host_name = NULL; char *svc_description = NULL; + char *author, *comment; time_t delay_time = 0L; /* get the host name */ - if((host_name = my_strtok(args, ";")) == NULL) + if((host_name = my_strtok_with_free(args, ";", FALSE)) == NULL) return ERROR; if(cmd == CMD_SCHEDULE_HOST_CHECK || cmd == CMD_SCHEDULE_FORCED_HOST_CHECK || cmd == CMD_SCHEDULE_HOST_SVC_CHECKS || cmd == CMD_SCHEDULE_FORCED_HOST_SVC_CHECKS) { @@ -2093,17 +2195,21 @@ int cmd_schedule_check(int cmd, char *args) { else { /* get the service description */ - if((svc_description = my_strtok(NULL, ";")) == NULL) + if((svc_description = my_strtok_with_free(NULL, ";", FALSE)) == NULL) return ERROR; /* verify that the service is valid */ - if((temp_service = find_service(host_name, svc_description)) == NULL) + if((temp_service = find_service(host_name, svc_description)) == NULL) { + temp_ptr = my_strtok_with_free(NULL, ";", TRUE); return ERROR; + } } /* get the next check time */ - if((temp_ptr = my_strtok(NULL, "\n")) == NULL) + if((temp_ptr = my_strtok_with_free(NULL, ";", FALSE)) == NULL) { + temp_ptr = my_strtok_with_free(NULL, ";", TRUE); return ERROR; + } delay_time = strtoul(temp_ptr, NULL, 10); /* schedule the host check */ @@ -2121,6 +2227,18 @@ int cmd_schedule_check(int cmd, char *args) { else schedule_service_check(temp_service, delay_time, (cmd == CMD_SCHEDULE_FORCED_SVC_CHECK) ? CHECK_OPTION_FORCE_EXECUTION : CHECK_OPTION_NONE); + if ((author = my_strtok_with_free(NULL, ";", FALSE)) != NULL) { + if ((comment = my_strtok_with_free(NULL, ";", FALSE)) != NULL) { + time_t current_time = time(NULL); + if (svc_description) + add_new_service_comment(USER_COMMENT, host_name, svc_description, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + else + add_new_host_comment(USER_COMMENT, host_name, current_time, author, comment, FALSE, COMMENTSOURCE_EXTERNAL, FALSE, (time_t)0, NULL); + } + } + + temp_ptr = my_strtok_with_free(NULL, ";", TRUE); + return OK; } @@ -2165,6 +2283,7 @@ int cmd_schedule_host_service_checks(int cmd, char *args, int force) { int cmd_signal_process(int cmd, char *args) { time_t scheduled_time = 0L; char *temp_ptr = NULL; + int event_signal = 0; /* get the time to schedule the event */ if((temp_ptr = my_strtok(args, "\n")) == NULL) @@ -2172,8 +2291,13 @@ int cmd_signal_process(int cmd, char *args) { else scheduled_time = strtoul(temp_ptr, NULL, 10); + /* what signal are we sending? */ + event_signal = EVENT_PROGRAM_RESTART; + if (cmd == CMD_SHUTDOWN_PROCESS) + event_signal = EVENT_PROGRAM_SHUTDOWN; + /* add a scheduled program shutdown or restart to the event list */ - if (!schedule_new_event((cmd == CMD_SHUTDOWN_PROCESS) ? EVENT_PROGRAM_SHUTDOWN : EVENT_PROGRAM_RESTART, TRUE, scheduled_time, FALSE, 0, NULL, FALSE, NULL, NULL, 0)) + if (!schedule_new_event(event_signal, TRUE, scheduled_time, FALSE, 0, NULL, FALSE, NULL, NULL, 0)) return ERROR; return OK; @@ -2245,23 +2369,39 @@ int process_passive_service_check(time_t check_time, char *host_name, char *svc_ if(host_name == NULL || svc_description == NULL || output == NULL) return ERROR; + /* find the host by its name or address */ temp_host = find_host_by_name_or_address(host_name); /* we couldn't find the host */ if(temp_host == NULL) { - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Passive check result was received for service '%s' on host '%s', but the host could not be found!\n", svc_description, host_name); + log_debug_info(DEBUGL_CHECKS, 0, + "Passive check result was received for service '%s' on host '%s', but the host could not be found!\n", + svc_description, host_name); + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: Passive check result was received for service '%s' on host '%s', but the host could not be found!\n", + svc_description, host_name); return ERROR; } - /* make sure the service exists */ - if((temp_service = find_service(temp_host->name, svc_description)) == NULL) { - logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Passive check result was received for service '%s' on host '%s', but the service could not be found!\n", svc_description, host_name); + /* now the service */ + temp_service = find_service(temp_host->name, svc_description); + + /* we couldn't find the service */ + if(temp_service == NULL) { + log_debug_info(DEBUGL_CHECKS, 0, + "Passive check result was received for service '%s' on host '%s', but the service could not be found!\n", + svc_description, host_name); + logit(NSLOG_RUNTIME_WARNING, TRUE, + "Warning: Passive check result was received for service '%s' on host '%s', but the service could not be found!\n", + svc_description, host_name); return ERROR; } /* skip this is we aren't accepting passive checks for this service */ - if(temp_service->accept_passive_checks == FALSE) + if(temp_service->accept_passive_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Service '%s' on host '%s' is not accepting passive checks, bailing\n", host_name, svc_description); return ERROR; + } memset(&cr, 0, sizeof(cr)); cr.exited_ok = 1; @@ -2350,12 +2490,15 @@ int process_passive_host_check(time_t check_time, char *host_name, int return_co /* we couldn't find the host */ if(temp_host == NULL) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Passive check result was received for host '%s', but the host could not be found!\n", host_name); + log_debug_info(DEBUGL_CHECKS, 0, "Passive check result was received for host '%s', but the host could not be found!\n", host_name); return ERROR; } /* skip this is we aren't accepting passive checks for this host */ - if(temp_host->accept_passive_checks == FALSE) + if(temp_host->accept_passive_checks == FALSE) { + log_debug_info(DEBUGL_CHECKS, 0, "Host '%s' is not accepting passive checks, bailing\n", host_name); return ERROR; + } memset(&cr, 0, sizeof(cr)); cr.exited_ok = 1; @@ -2714,49 +2857,58 @@ int cmd_delete_downtime(int cmd, char *args) { /* Deletes scheduled host and service downtime based on hostname and optionally other filter arguments */ -int cmd_delete_downtime_by_host_name(int cmd, char *args) { - char *temp_ptr = NULL; - char *end_ptr = NULL; - char *hostname = NULL; - char *service_description = NULL; - char *downtime_comment = NULL; +int cmd_delete_downtime_by_host_name(int cmd, char *args) +{ + char *temp_ptr = NULL; + char *end_ptr = NULL; + char *hostname = NULL; + char *service_description = NULL; + char *downtime_comment = NULL; time_t downtime_start_time = 0L; - int deleted = 0; + int deleted = 0; + + if (args == NULL) { + return ERROR; + } /* get the host name of the downtime to delete */ temp_ptr = my_strtok(args, ";"); - if(temp_ptr == NULL) + if (temp_ptr == NULL) { return ERROR; + } hostname = temp_ptr; /* get the optional service name */ temp_ptr = my_strtok(NULL, ";"); - if(temp_ptr != NULL) { - if(*temp_ptr != '\0') + if (temp_ptr != NULL) { + + if (*temp_ptr != '\0') { service_description = temp_ptr; + } /* get the optional start time */ temp_ptr = my_strtok(NULL, ";"); - if(temp_ptr != NULL) { + if (temp_ptr != NULL) { + downtime_start_time = strtoul(temp_ptr, &end_ptr, 10); /* get the optional comment */ temp_ptr = my_strtok(NULL, ";"); - if(temp_ptr != NULL) { - if(*temp_ptr != '\0') - downtime_comment = temp_ptr; - } + if (temp_ptr != NULL && *temp_ptr != '\0') { + downtime_comment = temp_ptr; } } + } deleted = delete_downtime_by_hostname_service_description_start_time_comment(hostname, service_description, downtime_start_time, downtime_comment); - if(deleted == 0) + if (deleted == 0) { return ERROR; + } return OK; - } +} int cmd_delete_downtime_by_hostgroup_name(int cmd, char *args) { char *temp_ptr = NULL; @@ -3538,6 +3690,36 @@ int cmd_change_object_custom_var(int cmd, char *args) { } } + /* find the object */ + switch(cmd) { + case CMD_CHANGE_CUSTOM_HOST_VAR: + if((temp_host = find_host(name1)) == NULL) { + my_free(name1); + my_free(name2); + return ERROR; + } + temp_customvariablesmember = temp_host->custom_variables; + break; + case CMD_CHANGE_CUSTOM_SVC_VAR: + if((temp_service = find_service(name1, name2)) == NULL) { + my_free(name1); + my_free(name2); + return ERROR; + } + temp_customvariablesmember = temp_service->custom_variables; + break; + case CMD_CHANGE_CUSTOM_CONTACT_VAR: + if((temp_contact = find_contact(name1)) == NULL) { + my_free(name1); + my_free(name2); + return ERROR; + } + temp_customvariablesmember = temp_contact->custom_variables; + break; + default: + break; + } + /* get the custom variable name */ if((temp_ptr = my_strtok(NULL, ";")) == NULL) { my_free(name1); @@ -3564,27 +3746,6 @@ int cmd_change_object_custom_var(int cmd, char *args) { return ERROR; } - /* find the object */ - switch(cmd) { - case CMD_CHANGE_CUSTOM_HOST_VAR: - if((temp_host = find_host(name1)) == NULL) - return ERROR; - temp_customvariablesmember = temp_host->custom_variables; - break; - case CMD_CHANGE_CUSTOM_SVC_VAR: - if((temp_service = find_service(name1, name2)) == NULL) - return ERROR; - temp_customvariablesmember = temp_service->custom_variables; - break; - case CMD_CHANGE_CUSTOM_CONTACT_VAR: - if((temp_contact = find_contact(name1)) == NULL) - return ERROR; - temp_customvariablesmember = temp_contact->custom_variables; - break; - default: - break; - } - /* capitalize the custom variable name */ for(x = 0; varname[x] != '\x0'; x++) varname[x] = toupper(varname[x]); @@ -5168,29 +5329,25 @@ void set_service_notification_number(service *svc, int num) { /* clears the flapping state for a specific host */ void clear_host_flapping_state(host *hst) { - int i; - double low_threshold = 0.0; - double high_threshold = 0.0; + int i = 0; + double low_threshold = 0.0; + double high_threshold = 0.0; - if (enable_flap_detection == FALSE || hst->flap_detection_enabled == FALSE) + if (enable_flap_detection == FALSE || hst->flap_detection_enabled == FALSE) { return; + } low_threshold = (hst->low_flap_threshold <= 0.0) ? low_host_flap_threshold : hst->low_flap_threshold; high_threshold = (hst->high_flap_threshold <= 0.0) ? high_host_flap_threshold : hst->high_flap_threshold; - for (i = 0; i < MAX_STATE_HISTORY_ENTRIES; ++i) - hst->state_history[i] = 0; /* clear the history */ - hst->state_history_index = 0; - hst->percent_state_change = 0.0; - if(hst->flapping_comment_id != 0) /* delete the comment we added earlier */ - delete_host_comment(hst->flapping_comment_id); - hst->flapping_comment_id = 0; - hst->is_flapping = FALSE; /* clear the flapping indicator */ - if (hst->is_flapping) { + log_debug_info(DEBUGL_FLAPPING, 1, "Host '%s' flapping state cleared.\n", hst->name); + /* log a notice - this one is parsed by the history CGI */ - logit(NSLOG_INFO_MESSAGE, FALSE, "HOST FLAPPING ALERT: %s;STOPPED; Flapping state cleared for host. (%2.1f%% change < %2.1f%% threshold)\n", hst->name, hst->percent_state_change, low_threshold); + logit(NSLOG_INFO_MESSAGE, FALSE, + "HOST FLAPPING ALERT: %s;STOPPED; Flapping state cleared for host. (%2.1f%% change < %2.1f%% threshold)\n", + hst->name, hst->percent_state_change, low_threshold); #ifdef USE_EVENT_BROKER /* send data to event broker */ @@ -5201,10 +5358,27 @@ void clear_host_flapping_state(host *hst) { host_notification(hst, NOTIFICATION_FLAPPINGSTOP, NULL, NULL, NOTIFICATION_OPTION_NONE); /* should we send a recovery notification? */ - if(hst->check_flapping_recovery_notification == TRUE && hst->current_state == HOST_UP) + if (hst->current_state == HOST_UP && hst->check_flapping_recovery_notification == TRUE) { host_notification(hst, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); + } } + /* clear the history and state change percent */ + for (i = 0; i < MAX_STATE_HISTORY_ENTRIES; ++i) { + hst->state_history[i] = 0; + } + hst->state_history_index = 0; + hst->percent_state_change = 0.0; + + /* delete the comment we added earlier */ + if (hst->flapping_comment_id != 0) { + delete_host_comment(hst->flapping_comment_id); + } + hst->flapping_comment_id = 0; + + /* clear the flapping indicator */ + hst->is_flapping = FALSE; + /* clear the recovery notification flag */ hst->check_flapping_recovery_notification = FALSE; } @@ -5212,29 +5386,25 @@ void clear_host_flapping_state(host *hst) { /* clears the flapping state for a specific service */ void clear_service_flapping_state(service *svc) { - int i; - double low_threshold = 0.0; - double high_threshold = 0.0; + int i = 0; + double low_threshold = 0.0; + double high_threshold = 0.0; - if (enable_flap_detection == FALSE || svc->flap_detection_enabled == FALSE) + if (enable_flap_detection == FALSE || svc->flap_detection_enabled == FALSE) { return; + } low_threshold = (svc->low_flap_threshold <= 0.0) ? low_service_flap_threshold : svc->low_flap_threshold; high_threshold = (svc->high_flap_threshold <= 0.0) ? high_service_flap_threshold : svc->high_flap_threshold; - for (i = 0; i < MAX_STATE_HISTORY_ENTRIES; ++i) - svc->state_history[i] = 0; /* clear the history */ - svc->state_history_index = 0; - svc->percent_state_change = 0.0; - if(svc->flapping_comment_id != 0) /* delete the comment we added earlier */ - delete_service_comment(svc->flapping_comment_id); - svc->flapping_comment_id = 0; - svc->is_flapping = FALSE; /* clear the flapping indicator */ - if (svc->is_flapping) { + log_debug_info(DEBUGL_FLAPPING, 1, "Service '%s' on host '%s' flapping state cleared.\n", svc->description, svc->host_name); + /* log a notice - this one is parsed by the history CGI */ - logit(NSLOG_INFO_MESSAGE, FALSE, "SERVICE FLAPPING ALERT: %s;%s;STOPPED; Flapping state cleared for service. (%2.1f%% change < %2.1f%% threshold)\n", svc->host_name, svc->description, svc->percent_state_change, low_threshold); + logit(NSLOG_INFO_MESSAGE, FALSE, + "SERVICE FLAPPING ALERT: %s;%s;STOPPED; Flapping state cleared for service. (%2.1f%% change < %2.1f%% threshold)\n", + svc->host_name, svc->description, svc->percent_state_change, low_threshold); #ifdef USE_EVENT_BROKER /* send data to event broker */ @@ -5245,10 +5415,27 @@ void clear_service_flapping_state(service *svc) { service_notification(svc, NOTIFICATION_FLAPPINGSTOP, NULL, NULL, NOTIFICATION_OPTION_NONE); /* should we send a recovery notification? */ - if(svc->check_flapping_recovery_notification == TRUE && svc->current_state == STATE_OK) + if (svc->current_state == STATE_OK && svc->check_flapping_recovery_notification == TRUE) { service_notification(svc, NOTIFICATION_NORMAL, NULL, NULL, NOTIFICATION_OPTION_NONE); + } } + /* clear the history and state change percent */ + for (i = 0; i < MAX_STATE_HISTORY_ENTRIES; ++i) { + svc->state_history[i] = 0; + } + svc->state_history_index = 0; + svc->percent_state_change = 0.0; + + /* delete the comment we added earlier */ + if (svc->flapping_comment_id != 0) { + delete_service_comment(svc->flapping_comment_id); + } + svc->flapping_comment_id = 0; + + /* clear the flapping indicator */ + svc->is_flapping = FALSE; + /* clear the recovery notification flag */ svc->check_flapping_recovery_notification = FALSE; } diff --git a/base/config.c b/base/config.c index edd43e1..6d04d1d 100644 --- a/base/config.c +++ b/base/config.c @@ -136,7 +136,7 @@ int read_main_config_file(char *main_config_file) { continue; /* get the variable name */ - if((temp_ptr = my_strtok(input, "=")) == NULL) { + if((temp_ptr = my_strtok_with_free(input, "=", FALSE)) == NULL) { asprintf(&error_message, "NULL variable"); error = TRUE; break; @@ -148,7 +148,7 @@ int read_main_config_file(char *main_config_file) { } /* get the value */ - if((temp_ptr = my_strtok(NULL, "\n")) == NULL) { + if((temp_ptr = my_strtok_with_free(NULL, "\n", FALSE)) == NULL) { asprintf(&error_message, "NULL value"); error = TRUE; break; @@ -158,6 +158,7 @@ int read_main_config_file(char *main_config_file) { error = TRUE; break; } + temp_ptr = my_strtok_with_free(NULL, "\n", TRUE); strip(variable); strip(value); @@ -176,8 +177,12 @@ int read_main_config_file(char *main_config_file) { } else if(!strcmp(variable, "website_url")) { + int lth; my_free(website_url); website_url = strdup(value); + lth = strlen(website_url); + if (website_url[lth-1] == '/') + website_url[lth-1] = '\0'; } else if(!strcmp(variable, "loadctl_options")) @@ -925,7 +930,7 @@ int read_main_config_file(char *main_config_file) { break; } } - + else if(!strcmp(variable, "status_update_interval")) { status_update_interval = atoi(value); @@ -1177,6 +1182,38 @@ int read_main_config_file(char *main_config_file) { else if(!strcmp(variable,"host_down_disable_service_checks")) { host_down_disable_service_checks = strtoul(value, NULL, 0); } + else if(!strcmp(variable,"service_skip_check_dependency_status")) { + service_skip_check_dependency_status = atoi(value); + if(service_skip_check_dependency_status < -1 || service_skip_check_dependency_status > 3) { + asprintf(&error_message, "Illegal value for service_skip_check_dependency_status"); + error = TRUE; + break; + } + } + else if(!strcmp(variable,"service_skip_check_parent_status")) { + service_skip_check_parent_status = atoi(value); + if(service_skip_check_parent_status < -1 || service_skip_check_parent_status > 3) { + asprintf(&error_message, "Illegal value for service_skip_check_parent_status"); + error = TRUE; + break; + } + } + else if(!strcmp(variable,"service_skip_check_host_down_status")) { + service_skip_check_host_down_status = atoi(value); + if(service_skip_check_host_down_status < -1 || service_skip_check_host_down_status > 3) { + asprintf(&error_message, "Illegal value for service_skip_check_host_down_status"); + error = TRUE; + break; + } + } + else if(!strcmp(variable,"host_skip_check_dependency_status")) { + host_skip_check_dependency_status = atoi(value); + if(host_skip_check_dependency_status < -1 || host_skip_check_dependency_status > 3) { + asprintf(&error_message, "Illegal value for host_skip_check_dependency_status"); + error = TRUE; + break; + } + } /* we don't know what this variable is... */ else { asprintf(&error_message, "UNKNOWN VARIABLE"); @@ -1320,7 +1357,7 @@ int read_resource_file(char *resource_file) { strip(input); /* get the variable name */ - if((temp_ptr = my_strtok(input, "=")) == NULL) { + if((temp_ptr = my_strtok_with_free(input, "=", FALSE)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: NULL variable - Line %d of resource file '%s'", current_line, resource_file); error = TRUE; break; @@ -1331,7 +1368,7 @@ int read_resource_file(char *resource_file) { } /* get the value */ - if((temp_ptr = my_strtok(NULL, "\n")) == NULL) { + if((temp_ptr = my_strtok_with_free(NULL, "\n", FALSE)) == NULL) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: NULL variable value - Line %d of resource file '%s'", current_line, resource_file); error = TRUE; break; @@ -1340,6 +1377,7 @@ int read_resource_file(char *resource_file) { error = TRUE; break; } + temp_ptr = my_strtok_with_free(NULL, "\n", TRUE); /* what should we do with the variable/value pair? */ diff --git a/base/events.c b/base/events.c index 301e2c8..469f272 100644 --- a/base/events.c +++ b/base/events.c @@ -757,65 +757,72 @@ int init_event_queue(void) unsigned int size; size = num_objects.hosts + num_objects.services; - if(size < 4096) + if (size < 4096) { size = 4096; + } nagios_squeue = squeue_create(size); return 0; } /* schedule a new timed event */ -timed_event *schedule_new_event(int event_type, int high_priority, time_t run_time, int recurring, unsigned long event_interval, void *timing_func, int compensate_for_time_change, void *event_data, void *event_args, int event_options) { - timed_event *new_event; - char run_time_string[MAX_DATETIME_LENGTH] = ""; +timed_event *schedule_new_event(int event_type, int high_priority, time_t run_time, + int recurring, unsigned long event_interval, void *timing_func, + int compensate_for_time_change, void *event_data, void *event_args, int event_options) +{ + timed_event * new_event = NULL; + char run_time_string[MAX_DATETIME_LENGTH] = ""; - log_debug_info(DEBUGL_FUNCTIONS, 0, "schedule_new_event()\n"); - - get_datetime_string(&run_time, run_time_string, MAX_DATETIME_LENGTH, - SHORT_DATE_TIME); - log_debug_info(DEBUGL_EVENTS, 0, "New Event Details:\n"); - log_debug_info(DEBUGL_EVENTS, 0, " Type: EVENT_%s\n", - EVENT_TYPE_STR(event_type)); - log_debug_info(DEBUGL_EVENTS, 0, " High Priority: %s\n", - ( high_priority ? "Yes" : "No")); - log_debug_info(DEBUGL_EVENTS, 0, " Run Time: %s\n", - run_time_string); - log_debug_info(DEBUGL_EVENTS, 0, " Recurring: %s\n", - ( recurring ? "Yes" : "No")); - log_debug_info(DEBUGL_EVENTS, 0, " Event Interval: %lu\n", - event_interval); - log_debug_info(DEBUGL_EVENTS, 0, " Compensate for Time Change: %s\n", - ( compensate_for_time_change ? "Yes" : "No")); - log_debug_info(DEBUGL_EVENTS, 0, " Event Options: %d\n", - event_options); + get_datetime_string(&run_time, run_time_string, MAX_DATETIME_LENGTH, SHORT_DATE_TIME); new_event = (timed_event *)calloc(1, sizeof(timed_event)); - if(new_event != NULL) { - new_event->event_type = event_type; - new_event->event_data = event_data; - new_event->event_args = event_args; - new_event->event_options = event_options; - new_event->run_time = run_time; - new_event->recurring = recurring; - new_event->event_interval = event_interval; - new_event->timing_func = timing_func; - new_event->compensate_for_time_change = compensate_for_time_change; - new_event->priority = high_priority; - } - else - return NULL; + if (new_event != NULL) { - log_debug_info(DEBUGL_EVENTS, 0, " Event ID: %p\n", new_event); + new_event->event_type = event_type; + new_event->event_data = event_data; + new_event->event_args = event_args; + new_event->event_options = event_options; + new_event->run_time = run_time; + new_event->recurring = recurring; + new_event->event_interval = event_interval; + new_event->timing_func = timing_func; + new_event->compensate_for_time_change = compensate_for_time_change; + new_event->priority = high_priority; + } + else { + return NULL; + } + + log_debug_info(DEBUGL_FUNCTIONS, 0, + "schedule_new_event()\n" + "New Event Details:\n" + " Event ID: %p\n" + " Type: EVENT_%s\n" + " High Priority: %d\n" + " Run Time: %s\n" + " Recurring: %d\n" + " Event Interval: %lu\n" + " Compensate for Time Change: %d\n" + " Event Options: %d\n", + new_event, + EVENT_TYPE_STR(event_type), + high_priority, + run_time_string, + recurring, + event_interval, + compensate_for_time_change, + event_options); /* add the event to the event list */ add_event(nagios_squeue, new_event); return new_event; - } +} /* reschedule an event in order of execution time */ -void reschedule_event(squeue_t *sq, timed_event *event) { +void reschedule_event(squeue_t *sq, timed_event *event) +{ time_t current_time = 0L; time_t (*timingfunc)(void); @@ -826,84 +833,99 @@ void reschedule_event(squeue_t *sq, timed_event *event) { /* use custom timing function */ if(event->timing_func != NULL) { - timingfunc = event->timing_func; + + timingfunc = event->timing_func; event->run_time = (*timingfunc)(); - } + } /* normal recurring events */ else { + event->run_time = event->run_time + event->event_interval; time(¤t_time); - if(event->run_time < current_time) + + if(event->run_time < current_time) { event->run_time = current_time; } } + } /* add the event to the event list */ add_event(sq, event); - - return; - } +} /* add an event to list ordered by execution time */ -void add_event(squeue_t *sq, timed_event *event) { - +void add_event(squeue_t *sq, timed_event *event) +{ log_debug_info(DEBUGL_FUNCTIONS, 0, "add_event()\n"); - if(event->sq_event) { + if (event->sq_event != NULL) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Adding %s event that seems to already be scheduled\n", EVENT_TYPE_STR(event->event_type)); + remove_event(sq, event); } - if(event->priority) { + if (event->priority > 0) { event->sq_event = squeue_add_usec(sq, event->run_time, event->priority - 1, event); - } + } else { event->sq_event = squeue_add(sq, event->run_time, event); - } - if(!event->sq_event) { - logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to add event to squeue '%p' with prio %u: %s\n", - sq, event->priority, strerror(errno)); - } + } - if(sq == nagios_squeue) + if (event->sq_event == NULL) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Error: Failed to add event to squeue '%p' with prio %u: %s\n", + sq, event->priority, strerror(errno)); + } + + /* this specifies + just to ensure different than `-1` visually */ + if (sq == nagios_squeue) { track_events(event->event_type, +1); + } #ifdef USE_EVENT_BROKER else { - /* send event data to broker */ broker_timed_event(NEBTYPE_TIMEDEVENT_ADD, NEBFLAG_NONE, NEBATTR_NONE, event, NULL); - } + } #endif - return; - } +} /* remove an event from the queue */ -void remove_event(squeue_t *sq, timed_event *event) { +void remove_event(squeue_t *sq, timed_event *event) +{ + #ifdef USE_EVENT_BROKER - /* send event data to broker */ broker_timed_event(NEBTYPE_TIMEDEVENT_REMOVE, NEBFLAG_NONE, NEBATTR_NONE, event, NULL); #endif - if(!event || !event->sq_event) + + if (event == NULL || event->sq_event == NULL) { return; + } - if (sq) + if (sq != NULL) { squeue_remove(sq, event->sq_event); - else + } + else { + logit(NSLOG_RUNTIME_ERROR, TRUE, - "Error: remove_event() called for %s event with NULL sq parameter\n", - EVENT_TYPE_STR(event->event_type)); + "Error: remove_event() called for %s event with NULL sq parameter\n", + EVENT_TYPE_STR(event->event_type)); + } - if(sq == nagios_squeue) + if (sq == nagios_squeue) { track_events(event->event_type, -1); + } - event->sq_event = NULL; /* mark this event as unscheduled */ + /* mark this event as unscheduled */ + event->sq_event = NULL; /* * if we catch an event from the queue which gets removed when @@ -915,89 +937,122 @@ void remove_event(squeue_t *sq, timed_event *event) { */ if (event == current_event) { current_event = NULL; - } } +} static int should_run_event(timed_event *temp_event) { - int run_event = TRUE; /* default action is to execute the event */ + /* default action is to execute the event */ + int run_event = TRUE; int nudge_seconds = 0; /* we only care about jobs that cause processes to run */ - if (temp_event->event_type != EVENT_HOST_CHECK && - temp_event->event_type != EVENT_SERVICE_CHECK) - { + if (temp_event->event_type != EVENT_HOST_CHECK + && temp_event->event_type != EVENT_SERVICE_CHECK) { + return TRUE; } /* if we can't spawn any more jobs, don't bother */ - if (!wproc_can_spawn(&loadctl)) { - wproc_reap(1, 1); /* Try to reap one job for one msec. */ + if (wproc_can_spawn(&loadctl) <= 0) { + + /* Try to reap one job for one msec. */ + wproc_reap(1, 1); return FALSE; } /* run a few checks before executing a service check... */ - if(temp_event->event_type == EVENT_SERVICE_CHECK) { + if (temp_event->event_type == EVENT_SERVICE_CHECK) { + service *temp_service = (service *)temp_event->event_data; /* forced checks override normal check logic */ - if((temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)) + if((temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)) { return TRUE; + } /* don't run a service check if we're already maxed out on the number of parallel service checks... */ - if(max_parallel_service_checks != 0 && (currently_running_service_checks >= max_parallel_service_checks)) { + if (max_parallel_service_checks != 0 + && currently_running_service_checks >= max_parallel_service_checks) { + nudge_seconds = ranged_urand(NUDGE_MIN, NUDGE_MAX); - logit(NSLOG_RUNTIME_WARNING, TRUE, "\tMax concurrent service checks (%d) has been reached. Nudging %s:%s by %d seconds...\n", max_parallel_service_checks, temp_service->host_name, temp_service->description, nudge_seconds); + logit(NSLOG_RUNTIME_WARNING, TRUE, + "\tMax concurrent service checks (%d) has been reached." + " Nudging %s:%s by %d seconds...\n", + max_parallel_service_checks, temp_service->host_name, + temp_service->description, nudge_seconds); + run_event = FALSE; } /* don't run a service check if active checks are disabled */ - if(execute_service_checks == FALSE) { - log_debug_info(DEBUGL_EVENTS | DEBUGL_CHECKS, 1, "We're not executing service checks right now, so we'll skip check event for service '%s;%s'.\n", temp_service->host_name, temp_service->description); + if (execute_service_checks == FALSE) { + + log_debug_info(DEBUGL_EVENTS | DEBUGL_CHECKS, 1, + "We're not executing service checks right now, so we'll skip check event for service '%s;%s'.\n", + temp_service->host_name, temp_service->description); + run_event = FALSE; } /* reschedule the check if we can't run it now */ - if(run_event == FALSE) { + if (run_event == FALSE) { + remove_event(nagios_squeue, temp_event); - if(nudge_seconds) { - /* We nudge the next check time when it is due to too many concurrent service checks */ + /* We nudge the next check time when it is + due to too many concurrent service checks */ + if (nudge_seconds) { temp_service->next_check = (time_t)(temp_service->next_check + nudge_seconds); } + + /* Otherwise just schedule as normal */ else { temp_service->next_check += check_window(temp_service); } temp_event->run_time = temp_service->next_check; + reschedule_event(nagios_squeue, temp_event); update_service_status(temp_service, FALSE); run_event = FALSE; } } + /* run a few checks before executing a host check... */ - else if(temp_event->event_type == EVENT_HOST_CHECK) { + else if (temp_event->event_type == EVENT_HOST_CHECK) { + host *temp_host = (host *)temp_event->event_data; /* forced checks override normal check logic */ - if((temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)) + if ((temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)) { + return TRUE; + } /* don't run a host check if active checks are disabled */ - if(execute_host_checks == FALSE) { - log_debug_info(DEBUGL_EVENTS | DEBUGL_CHECKS, 1, "We're not executing host checks right now, so we'll skip host check event for host '%s'.\n", temp_host->name); + if (execute_host_checks == FALSE) { + + log_debug_info(DEBUGL_EVENTS | DEBUGL_CHECKS, 1, + "We're not executing host checks right now, so we'll skip host check event for host '%s'.\n", + temp_host->name); + run_event = FALSE; } /* reschedule the host check if we can't run it right now */ - if(run_event == FALSE) { + if (run_event == FALSE) { + remove_event(nagios_squeue, temp_event); + temp_host->next_check += check_window(temp_host); temp_event->run_time = temp_host->next_check; + reschedule_event(nagios_squeue, temp_event); update_host_status(temp_host, FALSE); + run_event = FALSE; } } diff --git a/base/flapping.c b/base/flapping.c index c4bac1c..e8c771c 100644 --- a/base/flapping.c +++ b/base/flapping.c @@ -308,10 +308,12 @@ void set_service_flap(service *svc, double percent_change, double high_threshold /* log a notice - this one is parsed by the history CGI */ logit(NSLOG_RUNTIME_WARNING, FALSE, "SERVICE FLAPPING ALERT: %s;%s;STARTED; Service appears to have started flapping (%2.1f%% change >= %2.1f%% threshold)\n", svc->host_name, svc->description, percent_change, high_threshold); - /* add a non-persistent comment to the service */ - asprintf(&temp_buffer, "Notifications for this service are being suppressed because it was detected as having been flapping between different states (%2.1f%% change >= %2.1f%% threshold). When the service state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold); - add_new_service_comment(FLAPPING_COMMENT, svc->host_name, svc->description, time(NULL), "(Nagios Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(svc->flapping_comment_id)); - my_free(temp_buffer); + if (svc->flapping_comment_id == 0) { + /* add a non-persistent comment to the service */ + asprintf(&temp_buffer, "Notifications for this service are being suppressed because it was detected as having been flapping between different states (%2.1f%% change >= %2.1f%% threshold). When the service state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold); + add_new_service_comment(FLAPPING_COMMENT, svc->host_name, svc->description, time(NULL), "(Nagios Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(svc->flapping_comment_id)); + my_free(temp_buffer); + } /* set the flapping indicator */ svc->is_flapping = TRUE; @@ -396,10 +398,12 @@ void set_host_flap(host *hst, double percent_change, double high_threshold, doub /* log a notice - this one is parsed by the history CGI */ logit(NSLOG_RUNTIME_WARNING, FALSE, "HOST FLAPPING ALERT: %s;STARTED; Host appears to have started flapping (%2.1f%% change > %2.1f%% threshold)\n", hst->name, percent_change, high_threshold); - /* add a non-persistent comment to the host */ - asprintf(&temp_buffer, "Notifications for this host are being suppressed because it was detected as having been flapping between different states (%2.1f%% change > %2.1f%% threshold). When the host state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold); - add_new_host_comment(FLAPPING_COMMENT, hst->name, time(NULL), "(Nagios Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(hst->flapping_comment_id)); - my_free(temp_buffer); + if (hst->flapping_comment_id == 0) { + /* add a non-persistent comment to the host */ + asprintf(&temp_buffer, "Notifications for this host are being suppressed because it was detected as having been flapping between different states (%2.1f%% change > %2.1f%% threshold). When the host state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold); + add_new_host_comment(FLAPPING_COMMENT, hst->name, time(NULL), "(Nagios Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(hst->flapping_comment_id)); + my_free(temp_buffer); + } /* set the flapping indicator */ hst->is_flapping = TRUE; diff --git a/base/nagios.c b/base/nagios.c index 6811aa6..866dbe0 100644 --- a/base/nagios.c +++ b/base/nagios.c @@ -180,6 +180,8 @@ static int nagios_core_worker(const char *path) } enter_worker(sd, start_cmd); + free_worker_memory(WPROC_FORCE); + free_memory(get_global_macros()); return 0; } @@ -345,6 +347,7 @@ int main(int argc, char **argv) { printf("along with this program; if not, write to the Free Software\n"); printf("Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n"); + cleanup(); exit(OK); } @@ -374,6 +377,7 @@ int main(int argc, char **argv) { printf("the mailing lists, and commercial support options for Nagios.\n"); printf("\n"); + cleanup(); exit(ERROR); } @@ -384,7 +388,10 @@ int main(int argc, char **argv) { */ config_file = nspath_absolute(argv[optind], NULL); if(config_file == NULL) { + printf("Error allocating memory.\n"); + + cleanup(); exit(ERROR); } @@ -426,6 +433,7 @@ int main(int argc, char **argv) { result = read_main_config_file(config_file); if(result != OK) { printf(" Error processing main config file!\n\n"); + cleanup(); exit(EXIT_FAILURE); } @@ -435,6 +443,7 @@ int main(int argc, char **argv) { /* drop privileges */ if((result = drop_privileges(nagios_user, nagios_group)) == ERROR) { printf(" Failed to drop privileges. Aborting."); + cleanup(); exit(EXIT_FAILURE); } @@ -444,6 +453,7 @@ int main(int argc, char **argv) { */ if (!verify_config && test_configured_paths() == ERROR) { printf(" One or more path problems detected. Aborting.\n"); + cleanup(); exit(EXIT_FAILURE); } @@ -468,6 +478,7 @@ int main(int argc, char **argv) { printf(" may have been removed or modified in this version. Make sure to read\n"); printf(" the HTML documentation regarding the config files, as well as the\n"); printf(" 'Whats New' section to find out what has changed.\n\n"); + cleanup(); exit(EXIT_FAILURE); } @@ -488,6 +499,7 @@ int main(int argc, char **argv) { printf(" may have been removed or modified in this version. Make sure to read\n"); printf(" the HTML documentation regarding the config files, as well as the\n"); printf(" 'Whats New' section to find out what has changed.\n\n"); + cleanup(); exit(EXIT_FAILURE); } @@ -534,8 +546,9 @@ int main(int argc, char **argv) { /* make valgrind shut up about still reachable memory */ neb_free_module_list(); - free(config_file_dir); - free(config_file); + cleanup(); + my_free(config_file); + my_free(config_file_dir); exit(result); } @@ -556,17 +569,20 @@ int main(int argc, char **argv) { if (!nagios_binary_path) { logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Unable to allocate memory for nagios_binary_path\n"); + cleanup(); exit(EXIT_FAILURE); } if (!(nagios_iobs = iobroker_create())) { logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to create IO broker set: %s\n", strerror(errno)); + cleanup(); exit(EXIT_FAILURE); } /* keep monitoring things until we get a shutdown command */ do { + /* reset internal book-keeping (in case we're restarting) */ wproc_num_workers_spawned = wproc_num_workers_online = 0; caught_signal = sigshutdown = FALSE; @@ -583,6 +599,7 @@ int main(int argc, char **argv) { result = read_main_config_file(config_file); if (result != OK) { logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Failed to process config file '%s'. Aborting\n", config_file); + cleanup(); exit(EXIT_FAILURE); } timing_point("Main config file read\n"); @@ -592,7 +609,7 @@ int main(int argc, char **argv) { program_start = time(NULL); my_free(mac->x[MACRO_PROCESSSTARTTIME]); asprintf(&mac->x[MACRO_PROCESSSTARTTIME], "%llu", (unsigned long long)program_start); - + /* enter daemon mode (unless we're restarting...) */ if(daemon_mode == TRUE && sigrestart == FALSE) { @@ -621,11 +638,13 @@ int main(int argc, char **argv) { if (test_path_access(nagios_binary_path, X_OK)) { logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: failed to access() %s: %s\n", nagios_binary_path, strerror(errno)); logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Spawning workers will be impossible. Aborting.\n"); + cleanup(); exit(EXIT_FAILURE); } if (test_configured_paths() == ERROR) { /* error has already been logged */ + cleanup(); exit(EXIT_FAILURE); } @@ -664,8 +683,11 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } timing_point("Query handler initialized\n"); + +#ifdef ENABLE_NERD nerd_init(); timing_point("NERD initialized\n"); +#endif /* initialize check workers */ if(init_workers(num_check_workers) < 0) { @@ -690,6 +712,7 @@ int main(int argc, char **argv) { /* if we're dumping core, we must remove all dl-files */ if (daemon_dumps_core) neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD, NEBMODULE_NEB_SHUTDOWN); + cleanup(); exit(EXIT_FAILURE); } timing_point("Modules loaded\n"); @@ -733,6 +756,14 @@ int main(int argc, char **argv) { } timing_point("Object configuration parsed and understood\n"); + +#ifdef DETECT_RLIMIT_PROBLEM + /* lets do a quick system limit detection + to determine if we're likely to run into any + problems. */ + rlimit_problem_detection(num_check_workers); + timing_point("Limit detection"); +#endif /* write the objects.cache file */ fcache_objects(object_cache_file); @@ -747,7 +778,7 @@ int main(int argc, char **argv) { broker_program_state(NEBTYPE_PROCESS_START, NEBFLAG_NONE, NEBATTR_NONE, NULL); #endif - /* initialize status data unless we're starting */ + /* initialize status data only if we're starting (no restarts) */ if(sigrestart == FALSE) { initialize_status_data(config_file); timing_point("Status data initialized\n"); @@ -821,7 +852,7 @@ int main(int argc, char **argv) { qh_deinit(qh_socket_path ? qh_socket_path : DEFAULT_QUERY_SOCKET); /* 03/01/2007 EG Moved from sighandler() to prevent FUTEX locking problems under NPTL */ - /* 03/21/2007 EG SIGSEGV signals are still logged in sighandler() so we don't loose them */ + /* 03/21/2007 EG SIGSEGV signals are still logged in sighandler() so we don't lose them */ /* did we catch a signal? */ if(caught_signal == TRUE) { @@ -849,7 +880,10 @@ int main(int argc, char **argv) { /* clean up the scheduled downtime data */ cleanup_downtime_data(); - /* clean up the status data unless we're restarting */ + /* clean up comment data */ + free_comment_data(); + + /* clean up the status data if we are not restarting */ if(sigrestart == FALSE) { cleanup_status_data(TRUE); } @@ -857,6 +891,7 @@ int main(int argc, char **argv) { free_worker_memory(WPROC_FORCE); /* shutdown stuff... */ if(sigshutdown == TRUE) { + shutdown_command_file_worker(); iobroker_destroy(nagios_iobs, IOBROKER_CLOSE_SOCKETS); nagios_iobs = NULL; @@ -864,8 +899,22 @@ int main(int argc, char **argv) { logit(NSLOG_PROCESS_INFO, TRUE, "Successfully shutdown... (PID=%d)\n", (int)getpid()); } - /* clean up after ourselves */ - cleanup(); + /* try and collect any zombie processes */ + if (sigrestart == TRUE) { + + int status = 0; + pid_t child_pid; + log_debug_info(DEBUGL_PROCESS, 1, "Calling waitpid() on all children...\n"); + + while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) { + + log_debug_info(DEBUGL_PROCESS, 2, " * child PID: (%d), status: (%d)\n", child_pid, status); + } + + log_debug_info(DEBUGL_PROCESS, 1, "All children have been wait()ed on\n"); + + cleanup(); + } /* close debug log */ close_debug_log(); @@ -877,6 +926,7 @@ int main(int argc, char **argv) { unlink(lock_file); /* free misc memory */ + cleanup(); my_free(lock_file); my_free(config_file); my_free(config_file_dir); diff --git a/base/nerd.c b/base/nerd.c index ffa8bd3..5eb9571 100644 --- a/base/nerd.c +++ b/base/nerd.c @@ -1,3 +1,4 @@ +#ifdef ENABLE_NERD /* * Nagios Event Radio Dispatcher * @@ -7,6 +8,10 @@ * * This code uses the eventbroker api to get its data, which means * we're finally eating our own dogfood in that respect. + * + * Note: Disabled by default as of 4.4.0 + * ./configure --enable-nerd + * to enable! */ #define _GNU_SOURCE 1 @@ -493,3 +498,5 @@ int nerd_init(void) logit(NSLOG_INFO_MESSAGE, TRUE, "nerd: Fully initialized and ready to rock!\n"); return 0; } + +#endif \ No newline at end of file diff --git a/base/notifications.c b/base/notifications.c index 4b52a3d..0d218b4 100644 --- a/base/notifications.c +++ b/base/notifications.c @@ -54,7 +54,7 @@ const char *notification_reason_name(unsigned int reason_type) "CUSTOM" }; - if (reason_type < sizeof(names)) + if (reason_type < ARRAY_SIZE(names)) return names[reason_type]; return "(unknown)"; @@ -106,7 +106,7 @@ int service_notification(service *svc, int type, char *not_author, char *not_dat if (temp_host->scheduled_downtime_depth > 0 || svc->scheduled_downtime_depth > 0) svc->next_notification = current_time; } - return OK; + return ERROR; } log_debug_info(DEBUGL_NOTIFICATIONS, 0, "Notification viability test passed.\n"); @@ -222,7 +222,7 @@ int service_notification(service *svc, int type, char *not_author, char *not_dat /* set the notification number macro */ asprintf(&mac.x[MACRO_SERVICENOTIFICATIONNUMBER], "%d", svc->current_notification_number); - /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */ + /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatibility */ mac.x[MACRO_NOTIFICATIONNUMBER] = strdup(mac.x[MACRO_SERVICENOTIFICATIONNUMBER]); /* set the notification id macro */ @@ -342,7 +342,6 @@ int check_service_notification_viability(service *svc, int type, int options) { timeperiod *temp_period; time_t current_time; time_t timeperiod_start; - time_t first_problem_time; log_debug_info(DEBUGL_FUNCTIONS, 0, "check_service_notification_viability()\n"); @@ -547,15 +546,20 @@ int check_service_notification_viability(service *svc, int type, int options) { /* see if enough time has elapsed for first notification (Mathias Sundman) */ /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time ok (or program start) in calculation */ /* it is reasonable to assume that if the service was never up, the program start time should be used in this calculation */ - if(type == NOTIFICATION_NORMAL && svc->current_notification_number == 0 && svc->current_state != STATE_OK) { + /* check if delay of notifications is activated (ccztux) */ + if(type == NOTIFICATION_NORMAL + && svc->first_notification_delay > 0 + && svc->current_notification_number == 0 + && svc->current_state != STATE_OK) + { + time_t last_problem_time = svc->last_hard_state_change > 0 ? svc->last_hard_state_change : program_start; - first_problem_time = svc->last_time_ok > 0 ? svc->last_time_ok : program_start; - - if(current_time < first_problem_time + (time_t)(svc->first_notification_delay * interval_length)) { + /* determine the time to use of the last problem point */ + if(current_time < last_problem_time + (time_t)(svc->first_notification_delay * interval_length)) { log_debug_info(DEBUGL_NOTIFICATIONS, 1, "Not enough time has elapsed since the service changed to a non-OK state, so we should not notify about this problem yet\n"); return ERROR; } - } + } /* if this service is currently flapping, don't send the notification */ if(svc->is_flapping == TRUE) { @@ -563,29 +567,6 @@ int check_service_notification_viability(service *svc, int type, int options) { return ERROR; } - /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/ - if(svc->current_state == STATE_OK) - return OK; - - /* don't notify contacts about this service problem again if the notification interval is set to 0 */ - if(svc->no_more_notifications == TRUE) { - log_debug_info(DEBUGL_NOTIFICATIONS, 1, "We shouldn't re-notify contacts about this service problem.\n"); - return ERROR; - } - - /* if the host is down or unreachable, don't notify contacts about service failures */ - if(temp_host->current_state != STATE_UP && temp_host->state_type == HARD_STATE) { - log_debug_info(DEBUGL_NOTIFICATIONS, 1, "The host is either down or unreachable, so we won't notify contacts about this service.\n"); - return ERROR; - } - - /* don't notify if we haven't waited long enough since the last time (and the service is not marked as being volatile) */ - if((current_time < svc->next_notification) && svc->is_volatile == FALSE) { - log_debug_info(DEBUGL_NOTIFICATIONS, 1, "We haven't waited long enough to re-notify contacts about this service.\n"); - log_debug_info(DEBUGL_NOTIFICATIONS, 1, "Next valid notification time: %s", ctime(&svc->next_notification)); - return ERROR; - } - /* if this service is currently in a scheduled downtime period, don't send the notification */ if(svc->scheduled_downtime_depth > 0) { log_debug_info(DEBUGL_NOTIFICATIONS, 1, "This service is currently in a scheduled downtime, so we won't send notifications.\n"); @@ -610,6 +591,25 @@ int check_service_notification_viability(service *svc, int type, int options) { return ERROR; } + /* don't notify contacts about this service problem again if the notification interval is set to 0 */ + if(svc->no_more_notifications == TRUE) { + log_debug_info(DEBUGL_NOTIFICATIONS, 1, "We shouldn't re-notify contacts about this service problem.\n"); + return ERROR; + } + + /* if the host is down or unreachable, don't notify contacts about service failures */ + if(temp_host->current_state != STATE_UP && temp_host->state_type == HARD_STATE) { + log_debug_info(DEBUGL_NOTIFICATIONS, 1, "The host is either down or unreachable, so we won't notify contacts about this service.\n"); + return ERROR; + } + + /* don't notify if we haven't waited long enough since the last time (and the service is not marked as being volatile) */ + if((current_time < svc->next_notification) && svc->is_volatile == FALSE) { + log_debug_info(DEBUGL_NOTIFICATIONS, 1, "We haven't waited long enough to re-notify contacts about this service.\n"); + log_debug_info(DEBUGL_NOTIFICATIONS, 1, "Next valid notification time: %s", ctime(&svc->next_notification)); + return ERROR; + } + return OK; } @@ -1066,7 +1066,7 @@ int host_notification(host *hst, int type, char *not_author, char *not_data, int /* check viability of sending out a host notification */ if(check_host_notification_viability(hst, type, options) == ERROR) { log_debug_info(DEBUGL_NOTIFICATIONS, 0, "Notification viability test failed. No notification will be sent out.\n"); - return OK; + return ERROR; } log_debug_info(DEBUGL_NOTIFICATIONS, 0, "Notification viability test passed.\n"); @@ -1179,7 +1179,7 @@ int host_notification(host *hst, int type, char *not_author, char *not_data, int /* set the notification number macro */ asprintf(&mac.x[MACRO_HOSTNOTIFICATIONNUMBER], "%d", hst->current_notification_number); - /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */ + /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatibility */ mac.x[MACRO_NOTIFICATIONNUMBER] = strdup(mac.x[MACRO_HOSTNOTIFICATIONNUMBER]); /* set the notification id macro */ @@ -1296,7 +1296,6 @@ int host_notification(host *hst, int type, char *not_author, char *not_data, int int check_host_notification_viability(host *hst, int type, int options) { time_t current_time; time_t timeperiod_start; - time_t first_problem_time; log_debug_info(DEBUGL_FUNCTIONS, 0, "check_host_notification_viability()\n"); @@ -1470,15 +1469,21 @@ int check_host_notification_viability(host *hst, int type, int options) { /* see if enough time has elapsed for first notification (Mathias Sundman) */ /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time up (or program start) in calculation */ /* it is reasonable to assume that if the host was never up, the program start time should be used in this calculation */ - if(type == NOTIFICATION_NORMAL && hst->current_notification_number == 0 && hst->current_state != HOST_UP) { + /* check if delay of notifications is activated (ccztux) */ + if(type == NOTIFICATION_NORMAL + && hst->first_notification_delay > 0 + && hst->current_notification_number == 0 + && hst->current_state != STATE_OK) + { - first_problem_time = hst->last_time_up > 0 ? hst->last_time_up : program_start; + time_t last_problem_time = hst->last_hard_state_change > 0 ? hst->last_hard_state_change : program_start; - if(current_time < first_problem_time + (time_t)(hst->first_notification_delay * interval_length)) { + /* determine the time to use of the last problem point */ + if(current_time < last_problem_time + (time_t)(hst->first_notification_delay * interval_length)) { log_debug_info(DEBUGL_NOTIFICATIONS, 1, "Not enough time has elapsed since the host changed to a non-UP state (or since program start), so we shouldn't notify about this problem yet.\n"); return ERROR; - } - } + } + } /* if this host is currently flapping, don't send the notification */ if(hst->is_flapping == TRUE) { @@ -1486,10 +1491,6 @@ int check_host_notification_viability(host *hst, int type, int options) { return ERROR; } - /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/ - if(hst->current_state == HOST_UP) - return OK; - /* if this host is currently in a scheduled downtime period, don't send the notification */ if(hst->scheduled_downtime_depth > 0) { log_debug_info(DEBUGL_NOTIFICATIONS, 1, "This host is currently in a scheduled downtime, so we won't send notifications.\n"); diff --git a/base/query-handler.c b/base/query-handler.c index 44b0dfc..9e67a3c 100644 --- a/base/query-handler.c +++ b/base/query-handler.c @@ -24,12 +24,20 @@ static dkhash_table *qh_table; /* the echo service. stupid, but useful for testing */ static int qh_echo(int sd, char *buf, unsigned int len) { - if (!strcmp(buf, "help")) { + int result = 0; + + if (buf == NULL || !strcmp(buf, "help")) { + nsock_printf_nul(sd, "Query handler that simply echoes back what you send it."); return 0; } - (void)write(sd, buf, len); + + result = write(sd, buf, len); + if (result == -1) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: qh_echo() error on write(sd,buf=[%s],len=%d): %s\n", buf, len, strerror(errno)); + } return 0; } @@ -41,22 +49,28 @@ static struct query_handler *qh_find_handler(const char *name) /* subset of http error codes */ const char *qh_strerror(int code) { - if (code < 0) + if (code < 0) { return "Low-level system error"; + } - if (code == 100) + if (code == 100) { return "Continue"; - if (code == 101) + } + if (code == 101) { return "Switching protocols"; + } - if (code < 300) + if (code < 300) { return "OK"; + } - if (code < 400) + if (code < 400) { return "Redirected (possibly deprecated address)"; + } switch (code) { - /* client errors */ + + /* client errors */ case 400: return "Bad request"; case 401: return "Unauthorized"; case 403: return "Forbidden (disabled by config)"; @@ -72,36 +86,48 @@ const char *qh_strerror(int code) case 413: return "Request too large"; case 414: return "Request-URI too long"; - /* server errors */ + /* server errors */ case 500: return "Internal server error"; case 501: return "Not implemented"; case 502: return "Bad gateway"; case 503: return "Service unavailable"; case 504: return "Gateway timeout"; case 505: return "Version not supported"; + } + return "Unknown error"; } static int qh_input(int sd, int events, void *ioc_) { - iocache *ioc = (iocache *)ioc_; + iocache * ioc = (iocache *) ioc_; + int result = 0; + + /* + input on main socket, so accept one + this is when a worker initially connects + we create the iocache and then register + that to a new socket descriptor and this function + so that ioc_ != NULL next time + */ + if (sd == qh_listen_sock) { - /* input on main socket, so accept one */ - if(sd == qh_listen_sock) { struct sockaddr sa; socklen_t slen = 0; - int nsd; + int nsd = 0; - memset(&sa, 0, sizeof(sa)); /* shut valgrind up */ + /* shut valgrind up */ + memset(&sa, 0, sizeof(sa)); nsd = accept(sd, &sa, &slen); - if(qh_max_running && qh_running >= qh_max_running) { + if (qh_max_running && qh_running >= qh_max_running) { nsock_printf(nsd, "503: Server full"); close(nsd); return 0; } - if(!(ioc = iocache_create(16384))) { + ioc = iocache_create(16384); + if (ioc == NULL) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to create iocache for inbound request\n"); nsock_printf(nsd, "500: Internal server error"); close(nsd); @@ -112,7 +138,8 @@ static int qh_input(int sd, int events, void *ioc_) * @todo: Stash the iocache and the socket in some * addressable list so we can release them on deinit */ - if(iobroker_register(nagios_iobs, nsd, ioc, qh_input) < 0) { + result = iobroker_register(nagios_iobs, nsd, ioc, qh_input); + if (result < 0) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to register input socket %d with I/O broker: %s\n", nsd, strerror(errno)); iocache_destroy(ioc); close(nsd); @@ -124,17 +151,26 @@ static int qh_input(int sd, int events, void *ioc_) qh_running++; return 0; } + + /* + this is when an existing connection + sends more data after they've already made + the connection + */ else { - int result; - unsigned long len; - unsigned int query_len = 0; - char *buf, *space; - struct query_handler *qh; - char *handler = NULL, *query = NULL; + + unsigned long len = 0; + unsigned int query_len = 0; + struct query_handler * qh = NULL; + char * buf = NULL; + char * space = NULL; + char * handler = NULL; + char * query = NULL; result = iocache_read(ioc, sd); + /* disconnect? */ - if(result == 0 || (result < 0 && errno == EPIPE)) { + if (result == 0 || (result < 0 && errno == EPIPE)) { iocache_destroy(ioc); iobroker_close(nagios_iobs, sd); qh_running--; @@ -152,8 +188,9 @@ static int qh_input(int sd, int events, void *ioc_) /* Use data up to the first nul byte */ buf = iocache_use_delim(ioc, "\0", 1, &len); - if(!buf) + if (buf == NULL) { return 0; + } /* Identify handler part and any magic query bytes */ if (*buf == '@' || *buf == '#') { @@ -161,18 +198,18 @@ static int qh_input(int sd, int events, void *ioc_) } /* Locate query (if any) */ - if((space = strchr(buf, ' '))) { + space = strchr(buf, ' '); + if (space != NULL) { *space = 0; query = space + 1; - query_len = len - ((unsigned long)query - (unsigned long)buf); - } else { - query = ""; - query_len = 0; + query_len = len - (unsigned long)(query - buf); } /* locate the handler */ - if(!(qh = qh_find_handler(handler))) { - /* not found. that's a 404 */ + qh = qh_find_handler(handler); + + /* not found. that's a 404 */ + if (qh == NULL) { nsock_printf(sd, "404: %s: No such handler", handler); iobroker_close(nagios_iobs, sd); iocache_destroy(ioc); @@ -180,16 +217,20 @@ static int qh_input(int sd, int events, void *ioc_) } /* strip trailing newlines */ - while (query_len > 0 && (query[query_len - 1] == 0 || query[query_len - 1] == '\n')) - query[--query_len] = 0; + while (query_len > 0 + && (query[query_len - 1] == 0 || query[query_len - 1] == '\n')) { + + query[--query_len] = 0; + } /* now pass the query to the handler */ - if ((result = qh->handler(sd, query, query_len)) >= 100) { + result = qh->handler(sd, query, query_len); + if (result >= 100) { nsock_printf_nul(sd, "%d: %s", result, qh_strerror(result)); } - if(result >= 300 || *buf == '#') { - /* error code or one-shot query */ + /* error code or one-shot query */ + if (result >= 300 || *buf == '#') { iobroker_close(nagios_iobs, sd); iocache_destroy(ioc); return 0; @@ -197,34 +238,53 @@ static int qh_input(int sd, int events, void *ioc_) /* check for magic handler codes */ switch (result) { - case QH_CLOSE: /* oneshot handler */ - case -1: /* general error */ + + /* oneshot handler */ + case QH_CLOSE: + + /* general error */ + case -1: iobroker_close(nagios_iobs, sd); - /* fallthrough */ - case QH_TAKEOVER: /* handler takes over */ - case 101: /* switch protocol (takeover + message) */ + + /* fallthrough */ + + /* handler takes over */ + case QH_TAKEOVER: + + /* switch protocol (takeover + message) */ + case 101: iocache_destroy(ioc); break; } } + return 0; } int qh_deregister_handler(const char *name) { - struct query_handler *qh, *next, *prev; + struct query_handler *qh = NULL; + struct query_handler *next = NULL; + struct query_handler *prev = NULL; - if (!(qh = dkhash_remove(qh_table, name, NULL))) + qh = dkhash_remove(qh_table, name, NULL); + if (qh != NULL) { return 0; + } next = qh->next_qh; prev = qh->prev_qh; - if (next) + + if (next != NULL) { next->prev_qh = prev; - if (prev) + } + + if (prev != NULL) { prev->next_qh = next; - else + } + else { qhandlers = next; + } free(qh); @@ -233,44 +293,50 @@ int qh_deregister_handler(const char *name) int qh_register_handler(const char *name, const char *description, unsigned int options, qh_handler handler) { - struct query_handler *qh; - int result; + struct query_handler *qh = NULL; + int result = 0; - if(!name) + if (name == NULL) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to register handler with no name\n"); return -1; + } - if(!handler) { + if (handler == NULL) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to register handler '%s': No handler function specified\n", name); return -1; } - if(strlen(name) > 128) { + if (strlen(name) > 128) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to register handler '%s': Name too long\n", name); return -ENAMETOOLONG; } /* names must be unique */ - if(qh_find_handler(name)) { + if (qh_find_handler(name)) { logit(NSLOG_RUNTIME_WARNING, TRUE, "qh: Handler '%s' registered more than once\n", name); return -1; } - if (!(qh = calloc(1, sizeof(*qh)))) { + qh = calloc(1, sizeof(*qh)); + if (qh == NULL) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to allocate memory for handler '%s'\n", name); return -errno; } - qh->name = name; - qh->description = description; - qh->handler = handler; - qh->options = options; - qh->next_qh = qhandlers; - if (qhandlers) + qh->name = name; + qh->description = description; + qh->handler = handler; + qh->options = options; + qh->next_qh = qhandlers; + + if (qhandlers) { qhandlers->prev_qh = qh; - qhandlers = qh; + } + + qhandlers = qh; result = dkhash_insert(qh_table, qh->name, NULL, qh); - if(result < 0) { + if (result < 0) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to insert query handler '%s' (%p) into hash table %p (%d): %s\n", name, qh, qh_table, result, strerror(errno)); @@ -283,27 +349,29 @@ int qh_register_handler(const char *name, const char *description, unsigned int void qh_deinit(const char *path) { - struct query_handler *qh, *next; + struct query_handler *qh = NULL; + + for (qh = qhandlers; qh != NULL; qh = qh->next_qh) { - for(qh = qhandlers; qh; qh = next) { - next = qh->next_qh; qh_deregister_handler(qh->name); } + dkhash_destroy(qh_table); qh_table = NULL; qhandlers = NULL; - if(!path) + if (path == NULL) { return; + } unlink(path); } static int qh_help(int sd, char *buf, unsigned int len) { - struct query_handler *qh; + struct query_handler *qh = NULL; - if (!*buf || !strcmp(buf, "help")) { + if (buf == NULL || !strcmp(buf, "help")) { nsock_printf_nul(sd, " help show help for handler \n" " help list list registered handlers\n"); @@ -311,16 +379,22 @@ static int qh_help(int sd, char *buf, unsigned int len) } if (!strcmp(buf, "list")) { - for (qh = qhandlers; qh; qh = qh->next_qh) { + + for (qh = qhandlers; qh != NULL; qh = qh->next_qh) { nsock_printf(sd, "%-10s %s\n", qh->name, qh->description ? qh->description : "(No description available)"); } + nsock_printf(sd, "%c", 0); return 0; } - if (!(qh = qh_find_handler(buf))) { + qh = qh_find_handler(buf); + if (qh == NULL) { + nsock_printf_nul(sd, "No handler named '%s' is registered\n", buf); + } else if (qh->handler(sd, "help", 4) > 200) { + nsock_printf_nul(sd, "The handler %s doesn't have any help yet.", buf); } @@ -331,8 +405,10 @@ static int qh_core(int sd, char *buf, unsigned int len) { char *space; - if (!*buf || !strcmp(buf, "help")) { - nsock_printf_nul(sd, "Query handler for manipulating nagios core.\n" + if (buf == NULL || !strcmp(buf, "help")) { + + nsock_printf_nul(sd, + "Query handler for manipulating nagios core.\n" "Available commands:\n" " loadctl Print information about current load control settings\n" " loadctl Configure nagios load control.\n" @@ -340,13 +416,21 @@ static int qh_core(int sd, char *buf, unsigned int len) " returned above.\n" " squeuestats scheduling queue statistics\n" ); + return 0; } - if ((space = memchr(buf, ' ', len))) + space = memchr(buf, ' ', len); + + if (space != NULL) { *(space++) = 0; - if (!space && !strcmp(buf, "loadctl")) { - nsock_printf_nul - (sd, "jobs_max=%u;jobs_min=%u;" + } + + if (space == NULL) { + + if (!strcmp(buf, "loadctl")) { + + nsock_printf_nul(sd, + "jobs_max=%u;jobs_min=%u;" "jobs_running=%u;jobs_limit=%u;" "load=%.2f;" "backoff_limit=%.2f;backoff_change=%u;" @@ -359,15 +443,23 @@ static int qh_core(int sd, char *buf, unsigned int len) loadctl.backoff_limit, loadctl.backoff_change, loadctl.rampup_limit, loadctl.rampup_change, loadctl.nproc_limit, loadctl.nofile_limit, - loadctl.options, loadctl.changes); - return 0; + loadctl.options, loadctl.changes + ); + + return 0; + } + + else if (!strcmp(buf, "squeuestats")) { + + return dump_event_stats(sd); + } } - if (!space && !strcmp(buf, "squeuestats")) - return dump_event_stats(sd); + /* space != NULL: */ + else { + + len -= (unsigned long)(space - buf); - if (space) { - len -= (unsigned long)space - (unsigned long)buf; if (!strcmp(buf, "loadctl")) { return set_loadctl_options(space, len) == OK ? 200 : 400; } @@ -379,12 +471,15 @@ static int qh_core(int sd, char *buf, unsigned int len) int qh_init(const char *path) { - int result, old_umask; + int result = 0; + int old_umask = 0; - if(qh_listen_sock >= 0) + if (qh_listen_sock >= 0) { iobroker_close(nagios_iobs, qh_listen_sock); + } + + if (path == NULL) { - if(!path) { logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: query_socket is NULL. What voodoo is this?\n"); return ERROR; } @@ -393,17 +488,25 @@ int qh_init(const char *path) errno = 0; qh_listen_sock = nsock_unix(path, NSOCK_TCP | NSOCK_UNLINK); umask(old_umask); - if(qh_listen_sock < 0) { + + if (qh_listen_sock < 0) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to init socket '%s'. %s: %s\n", path, nsock_strerror(qh_listen_sock), strerror(errno)); return ERROR; } /* plugins shouldn't have this socket */ - (void)fcntl(qh_listen_sock, F_SETFD, FD_CLOEXEC); + result = fcntl(qh_listen_sock, F_SETFD, FD_CLOEXEC); + if (result == -1) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to fcntl() query handler socket\n"); + } /* most likely overkill, but it's small, so... */ - if(!(qh_table = dkhash_create(1024))) { + qh_table = dkhash_create(1024); + if (qh_table == NULL) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to create hash table\n"); close(qh_listen_sock); return ERROR; @@ -411,7 +514,8 @@ int qh_init(const char *path) errno = 0; result = iobroker_register(nagios_iobs, qh_listen_sock, NULL, qh_input); - if(result < 0) { + if (result < 0) { + dkhash_destroy(qh_table); close(qh_listen_sock); logit(NSLOG_RUNTIME_ERROR, TRUE, "qh: Failed to register socket with io broker: %s; errno=%d: %s\n", iobroker_strerror(result), errno, strerror(errno)); @@ -421,10 +525,20 @@ int qh_init(const char *path) logit(NSLOG_INFO_MESSAGE, FALSE, "qh: Socket '%s' successfully initialized\n", path); /* now register our the in-core handlers */ - if(!qh_register_handler("core", "Nagios Core control and info", 0, qh_core)) + result = qh_register_handler("core", "Nagios Core control and info", 0, qh_core); + if (result == OK) { logit(NSLOG_INFO_MESSAGE, FALSE, "qh: core query handler registered\n"); - qh_register_handler("echo", "The Echo Service - What You Put Is What You Get", 0, qh_echo); - qh_register_handler("help", "Help for the query handler", 0, qh_help); + } + + result = qh_register_handler("echo", "The Echo Service - What You Put Is What You Get", 0, qh_echo); + if (result == OK) { + logit(NSLOG_INFO_MESSAGE, FALSE, "qh: echo service query handler registered\n"); + } + + result = qh_register_handler("help", "Help for the query handler", 0, qh_help); + if (result == OK) { + logit(NSLOG_INFO_MESSAGE, FALSE, "qh: help for the query handler registered\n"); + } return 0; } diff --git a/base/utils.c b/base/utils.c index 8116ebf..5e4438c 100644 --- a/base/utils.c +++ b/base/utils.c @@ -25,14 +25,22 @@ #include "../include/objects.h" #include "../include/statusdata.h" #include "../include/comments.h" +#include "../include/downtime.h" #include "../include/macros.h" #include "../include/nagios.h" #include "../include/netutils.h" +#include "../include/perfdata.h" #include "../include/broker.h" #include "../include/nebmods.h" #include "../include/nebmodules.h" #include "../include/workers.h" +#include "../xdata/xodtemplate.h" + +#include +#include + + /* global variables only used by the daemon */ char *nagios_binary_path = NULL; char *config_file = NULL; @@ -194,6 +202,10 @@ char *website_url; int allow_empty_hostgroup_assignment; int host_down_disable_service_checks; +int service_skip_check_dependency_status; +int service_skip_check_parent_status; +int service_skip_check_host_down_status; +int host_skip_check_dependency_status; /*** perfdata variables ***/ int perfdata_timeout; @@ -376,6 +388,10 @@ void init_main_cfg_vars(int first_time) { allow_empty_hostgroup_assignment = DEFAULT_ALLOW_EMPTY_HOSTGROUP_ASSIGNMENT; host_down_disable_service_checks = FALSE; + service_skip_check_dependency_status = -1; + service_skip_check_parent_status = -1; + service_skip_check_host_down_status = -1; + host_skip_check_dependency_status = -1; perfdata_timeout = 0; host_perfdata_command = NULL; service_perfdata_command = NULL; @@ -1426,6 +1442,9 @@ time_t calculate_time_from_day_of_month(int year, int month, int monthday) { day--; /* make the new time */ + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; t.tm_mon = month; t.tm_year = year; t.tm_mday = day; @@ -1617,6 +1636,7 @@ void setup_sighandler(void) { sigaction(SIGHUP, &sig_action, NULL); if(daemon_dumps_core == FALSE && daemon_mode == TRUE) sigaction(SIGSEGV, &sig_action, NULL); + sig_action.sa_flags = SA_NOCLDWAIT; #else /* HAVE_SIGACTION */ signal(SIGPIPE, SIG_IGN); signal(SIGQUIT, sighandler); @@ -1701,7 +1721,7 @@ void my_system_sighandler(int sig) { /* Handle the SIGXFSZ signal. A SIGXFSZ signal is received when a file exceeds - the maximum allowable size either as dictated by the fzise parameter in + the maximum allowable size either as dictated by the fsize parameter in /etc/security/limits.conf (ulimit -f) or by the maximum size allowed by the filesystem */ void handle_sigxfsz(int sig) { @@ -1824,36 +1844,48 @@ static long long check_file_size(char *path, unsigned long fudge, /************************ DAEMON FUNCTIONS ************************/ /******************************************************************/ -int daemon_init(void) { - pid_t pid = -1; - int pidno = 0; - int lockfile = 0; - int val = 0; - char buf[256]; - struct flock lock; +int daemon_init(void) +{ + pid_t pid = -1; + int pidno = 0; + int lockfile = 0; + int val = 0; + char buf[256] = { 0 }; char *homedir = NULL; - char *cp; + char *cp = NULL; + struct flock lock; #ifdef RLIMIT_CORE struct rlimit limit; #endif /* change working directory. scuttle home if we're dumping core */ - if(daemon_dumps_core == TRUE) { + if (daemon_dumps_core == TRUE) { + homedir = getenv("HOME"); - if (homedir && *homedir) + + if (homedir && *homedir) { chdir(homedir); + } else if (log_file && *log_file) { + homedir = strdup(log_file); + cp = strrchr(homedir, '/'); - if (cp) + + if (cp) { *cp = '\0'; - else + } + else { strcpy(homedir, "/"); + } + chdir(homedir); free(homedir); - } else + + } else { chdir("/"); + } } umask(S_IWGRP | S_IWOTH); @@ -1871,43 +1903,77 @@ int daemon_init(void) { lockfile = open(lock_file, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); - if(lockfile < 0) { - logit(NSLOG_RUNTIME_ERROR, TRUE, "Failed to obtain lock on file %s: %s\n", lock_file, strerror(errno)); - logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, TRUE, "Bailing out due to errors encountered while attempting to daemonize... (PID=%d)", (int)getpid()); + if (lockfile < 0) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Failed to obtain lock on file %s: %s\n", lock_file, strerror(errno)); + logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, TRUE, + "Bailing out due to errors encountered while attempting to daemonize... (PID=%d)", (int)getpid()); cleanup(); exit(ERROR); - } + } /* see if we can read the contents of the lockfile */ - if((val = read(lockfile, buf, (size_t)10)) < 0) { + val = read(lockfile, buf, (size_t)10); + if (val < 0) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "Lockfile exists but cannot be read"); cleanup(); exit(ERROR); - } + } /* we read something - check the PID */ - if(val > 0) { - if((val = sscanf(buf, "%d", &pidno)) < 1) { + if (val > 0) { + + val = sscanf(buf, "%d", &pidno); + if (val < 1) { logit(NSLOG_RUNTIME_ERROR, TRUE, "Lockfile '%s' does not contain a valid PID (%s)", lock_file, buf); cleanup(); exit(ERROR); - } + } + } + + pid = (pid_t)pidno; + if (val == 1) { + + /* check for SIGHUP */ + if (pid == getpid()) { + close(lockfile); + return OK; } - /* check for SIGHUP */ - if(val == 1 && (pid = (pid_t)pidno) == getpid()) { - close(lockfile); - return OK; + /* send a signal to see if pid alive */ + val = kill(pid, 0); + + /* is this process alive? */ + if (val == 0) { + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Lockfile '%s' contains PID of running process (%d)", lock_file, pidno); + cleanup(); + exit(ERROR); } + } /* exit on errors... */ - if((pid = fork()) < 0) + pid = fork(); + if (pid < 0) { return(ERROR); + } /* parent process goes away.. */ - else if((int)pid != 0) + else if (pid != 0) { + + iobroker_destroy(nagios_iobs, IOBROKER_CLOSE_SOCKETS); + cleanup(); + cleanup_performance_data(); + cleanup_downtime_data(); + my_free(lock_file); + my_free(config_file); + my_free(config_file_dir); + my_free(nagios_binary_path); exit(OK); + } /* child continues... */ @@ -1915,21 +1981,29 @@ int daemon_init(void) { setsid(); /* place a file lock on the lock file */ - lock.l_type = F_WRLCK; - lock.l_start = 0; + lock.l_type = F_WRLCK; + lock.l_start = 0; lock.l_whence = SEEK_SET; - lock.l_len = 0; - if(fcntl(lockfile, F_SETLK, &lock) < 0) { - if(errno == EACCES || errno == EAGAIN) { + lock.l_len = 0; + + val = fcntl(lockfile, F_SETLK, &lock); + + if (val < 0) { + if (errno == EACCES || errno == EAGAIN) { fcntl(lockfile, F_GETLK, &lock); - logit(NSLOG_RUNTIME_ERROR, TRUE, "Lockfile '%s' looks like its already held by another instance of Nagios (PID %d). Bailing out...", lock_file, (int)lock.l_pid); - } - else - logit(NSLOG_RUNTIME_ERROR, TRUE, "Cannot lock lockfile '%s': %s. Bailing out...", lock_file, strerror(errno)); + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Lockfile '%s' looks like its already held by another instance of Nagios (PID %d). Bailing out...", + lock_file, (int)lock.l_pid); + } + else { + logit(NSLOG_RUNTIME_ERROR, TRUE, + "Cannot lock lockfile '%s': %s. Bailing out...", + lock_file, strerror(errno)); + } cleanup(); exit(ERROR); - } + } /* prevent daemon from dumping a core file... */ #ifdef RLIMIT_CORE @@ -1937,7 +2011,7 @@ int daemon_init(void) { getrlimit(RLIMIT_CORE, &limit); limit.rlim_cur = 0; setrlimit(RLIMIT_CORE, &limit); - } + } #endif /* write PID to lockfile... */ @@ -1957,7 +2031,7 @@ int daemon_init(void) { #endif return OK; - } +} @@ -2094,12 +2168,13 @@ int process_check_result_queue(char *dirname) { return ERROR; } - log_debug_info(DEBUGL_CHECKS, 1, "Starting to read check result queue '%s'...\n", dirname); + log_debug_info(DEBUGL_CHECKS, 0, "Starting to read check result queue '%s'...\n", dirname); start = time(NULL); /* process all files in the directory... */ while((dirfile = readdir(dirp)) != NULL) { + /* bail out if we encountered a signal */ if (sigshutdown == TRUE || sigrestart == TRUE) { log_debug_info(DEBUGL_CHECKS, 0, "Breaking out of check result reaper: signal encountered\n"); @@ -2116,7 +2191,13 @@ int process_check_result_queue(char *dirname) { snprintf(file, sizeof(file), "%s/%s", dirname, dirfile->d_name); file[sizeof(file) - 1] = '\x0'; - /* process this if it's a check result file... */ + /* process this if it's a check result file... + remember it needs to be in the format of + filename = cXXXXXX + where X is any integer + there must also be a filename present + okfile = cXXXXXX.ok + where the XXXXXX is the same as in the filename */ x = strlen(dirfile->d_name); if(x == 7 && dirfile->d_name[0] == 'c') { @@ -2152,8 +2233,10 @@ int process_check_result_queue(char *dirname) { result = process_check_result_file(file); /* break out if we encountered an error */ - if(result == ERROR) + if(result == ERROR) { + log_debug_info(DEBUGL_CHECKS, 0, "Encountered an error processing the check result file\n"); break; + } check_result_files++; } @@ -2161,6 +2244,8 @@ int process_check_result_queue(char *dirname) { closedir(dirp); + log_debug_info(DEBUGL_CHECKS, 0, "Finished reaping %d check results\n", check_result_files); + return check_result_files; } @@ -2213,17 +2298,21 @@ int process_check_result(check_result *cr) /* static char *unescape_check_result_file_output(char*); */ /* reads check result(s) from a file */ -int process_check_result_file(char *fname) { - mmapfile *thefile = NULL; - char *input = NULL; - char *var = NULL; - char *val = NULL; +int process_check_result_file(char *fname) +{ + mmapfile *thefile = NULL; + char *input = NULL; + char *var = NULL; + char *val = NULL; + char *vartok = NULL; + char *valtok = NULL; char *v1 = NULL, *v2 = NULL; time_t current_time; check_result cr; - if(fname == NULL) + if (fname == NULL) { return ERROR; + } init_check_result(&cr); cr.engine = &nagios_spool_check_engine; @@ -2233,102 +2322,142 @@ int process_check_result_file(char *fname) { log_debug_info(DEBUGL_CHECKS, 1, "Processing check result file: '%s'\n", fname); /* open the file for reading */ - if((thefile = mmap_fopen(fname)) == NULL) { + thefile = mmap_fopen(fname); + if (thefile == NULL) { /* try removing the file - zero length files can't be mmap()'ed, so it might exist */ log_debug_info(DEBUGL_CHECKS, 1, "Failed to open check result file for reading: '%s'\n", fname); delete_check_result_file(fname); return ERROR; - } + } /* read in all lines from the file */ while(1) { /* free memory */ my_free(input); + my_free(var); + my_free(val); /* read the next line */ - if((input = mmap_fgets_multiline(thefile)) == NULL) + input = mmap_fgets_multiline(thefile); + if (input == NULL) { break; + } /* skip comments */ - if(input[0] == '#') + if (input[0] == '#') { continue; + } /* empty line indicates end of record */ - else if(input[0] == '\n') { + else if (input[0] == '\n') { /* do we have the minimum amount of data? */ - if(cr.host_name != NULL && cr.output != NULL) { + if (cr.host_name != NULL && cr.output != NULL) { /* process the check result */ process_check_result(&cr); - - } + } /* cleanse for next check result */ free_check_result(&cr); init_check_result(&cr); cr.output_file = fname; - } + } - if((var = my_strtok(input, "=")) == NULL) + vartok = my_strtok_with_free(input, "=", FALSE); + if (vartok == NULL) { continue; - if((val = my_strtok(NULL, "\n")) == NULL) + } + + valtok = my_strtok_with_free(NULL, "\n", FALSE); + if (valtok == NULL) { + + vartok = my_strtok_with_free(NULL, NULL, TRUE); continue; + } + + /* clean up some memory before we go any further */ + var = strdup(vartok); + val = strdup(valtok); + vartok = my_strtok_with_free(NULL, NULL, TRUE); + + log_debug_info(DEBUGL_CHECKS, 2, " * %25s: %s\n", var, val); /* found the file time */ - if(!strcmp(var, "file_time")) { + if (!strcmp(var, "file_time")) { /* file is too old - ignore check results it contains and delete it */ /* this will only work as intended if file_time comes before check results */ - if(max_check_result_file_age > 0 && (current_time - (strtoul(val, NULL, 0)) > max_check_result_file_age)) { + if ((max_check_result_file_age > 0) + && (current_time - (strtoul(val, NULL, 0)) > max_check_result_file_age)) { + + log_debug_info(DEBUGL_CHECKS, 1, + "Skipping check_result because file_time is %s and max cr file age is %lu", + val, max_check_result_file_age); break; - } } + } /* else we have check result data */ else { - if(!strcmp(var, "host_name")) + + if (!strcmp(var, "host_name")) { cr.host_name = (char *)strdup(val); - else if(!strcmp(var, "service_description")) { + } + else if (!strcmp(var, "service_description")) { cr.service_description = (char *)strdup(val); cr.object_check_type = SERVICE_CHECK; - } - else if(!strcmp(var, "check_type")) + } + else if (!strcmp(var, "check_type")) { cr.check_type = atoi(val); - else if(!strcmp(var, "check_options")) + } + else if (!strcmp(var, "check_options")) { cr.check_options = atoi(val); - else if(!strcmp(var, "scheduled_check")) + } + else if (!strcmp(var, "scheduled_check")) { cr.scheduled_check = atoi(val); - else if(!strcmp(var, "reschedule_check")) + } + else if (!strcmp(var, "reschedule_check")) { cr.reschedule_check = atoi(val); - else if(!strcmp(var, "latency")) + } + else if (!strcmp(var, "latency")) { cr.latency = strtod(val, NULL); - else if(!strcmp(var, "start_time")) { - if((v1 = strtok(val, ".")) == NULL) + } + else if (!strcmp(var, "start_time") || !strcmp(var, "finish_time")) { + + v1 = strtok(val, "."); + if (v1 == NULL) { continue; - if((v2 = strtok(NULL, "\n")) == NULL) - continue; - cr.start_time.tv_sec = strtoul(v1, NULL, 0); - cr.start_time.tv_usec = strtoul(v2, NULL, 0); } - else if(!strcmp(var, "finish_time")) { - if((v1 = strtok(val, ".")) == NULL) + + v2 = strtok(NULL, "\n"); + if (v2 == NULL) { continue; - if((v2 = strtok(NULL, "\n")) == NULL) - continue; - cr.finish_time.tv_sec = strtoul(v1, NULL, 0); - cr.finish_time.tv_usec = strtoul(v2, NULL, 0); } - else if(!strcmp(var, "early_timeout")) + + if (!strcmp(var, "start_time")) { + cr.start_time.tv_sec = strtoul(v1, NULL, 0); + cr.start_time.tv_usec = strtoul(v2, NULL, 0); + } + else { + cr.finish_time.tv_sec = strtoul(v1, NULL, 0); + cr.finish_time.tv_usec = strtoul(v2, NULL, 0); + } + } + else if (!strcmp(var, "early_timeout")) { cr.early_timeout = atoi(val); - else if(!strcmp(var, "exited_ok")) + } + else if (!strcmp(var, "exited_ok")) { cr.exited_ok = atoi(val); - else if(!strcmp(var, "return_code")) + } + else if (!strcmp(var, "return_code")) { cr.return_code = atoi(val); - else if(!strcmp(var, "output")) + } + else if (!strcmp(var, "output")) { + /* Interpolate "\\\\" and "\\n" escape sequences to the literal * characters they represent. This converts from the single line * format used to store the output in a checkresult file, to the @@ -2338,14 +2467,21 @@ int process_check_result_file(char *fname) { cr.output = unescape_check_result_output(val); } } + } + + my_free(var); + my_free(val); + + log_debug_info(DEBUGL_CHECKS, 2, " **************\n"); /* do we have the minimum amount of data? */ - if(cr.host_name != NULL && cr.output != NULL) { + if (cr.host_name != NULL && cr.output != NULL) { /* process check result */ process_check_result(&cr); } else { + /* log a debug message */ log_debug_info(DEBUGL_CHECKS, 1, "Minimum amount of data not present; Skipped check result file: '%s'\n", fname); } @@ -2359,74 +2495,79 @@ int process_check_result_file(char *fname) { delete_check_result_file(fname); return OK; - } +} /* deletes as check result file, as well as its ok-to-go file */ -int delete_check_result_file(char *fname) { +int delete_check_result_file(char *fname) +{ char *temp_buffer = NULL; - int result = OK; + int result = OK; /* delete the result file */ result = unlink(fname); /* delete the ok-to-go file */ asprintf(&temp_buffer, "%s.ok", fname); + result |= unlink(temp_buffer); + my_free(temp_buffer); return result; - } +} /* initializes a host/service check result */ -int init_check_result(check_result *info) { - - if(info == NULL) +int init_check_result(check_result *info) +{ + if (info == NULL) { return ERROR; + } /* reset vars */ - info->object_check_type = HOST_CHECK; - info->host_name = NULL; + info->object_check_type = HOST_CHECK; + info->host_name = NULL; info->service_description = NULL; - info->check_type = CHECK_TYPE_ACTIVE; - info->check_options = CHECK_OPTION_NONE; - info->scheduled_check = FALSE; - info->reschedule_check = FALSE; - info->output_file_fp = NULL; - info->latency = 0.0; - info->start_time.tv_sec = 0; - info->start_time.tv_usec = 0; - info->finish_time.tv_sec = 0; + info->check_type = CHECK_TYPE_ACTIVE; + info->check_options = CHECK_OPTION_NONE; + info->scheduled_check = FALSE; + info->reschedule_check = FALSE; + info->output_file_fp = NULL; + info->latency = 0.0; + info->start_time.tv_sec = 0; + info->start_time.tv_usec = 0; + info->finish_time.tv_sec = 0; info->finish_time.tv_usec = 0; - info->early_timeout = FALSE; - info->exited_ok = TRUE; - info->return_code = 0; - info->output = NULL; - info->source = NULL; - info->engine = NULL; + info->early_timeout = FALSE; + info->exited_ok = TRUE; + info->return_code = 0; + info->output = NULL; + info->source = NULL; + info->engine = NULL; return OK; - } +} /* frees memory associated with a host/service check result */ -int free_check_result(check_result *info) { - - if(info == NULL) +int free_check_result(check_result *info) +{ + if (info == NULL) { return OK; + } my_free(info->host_name); my_free(info->service_description); my_free(info->output); return OK; - } +} /******************************************************************/ @@ -3307,6 +3448,7 @@ char *get_program_modification_date(void) { /* do some cleanup before we exit */ void cleanup(void) { + xodtemplate_free_memory(); #ifdef USE_EVENT_BROKER /* unload modules */ @@ -3332,8 +3474,6 @@ void free_memory(nagios_macros *mac) { /* free all allocated memory for the object definitions */ free_object_data(); - - /* free memory allocated to comments */ free_comment_data(); /* free event queue data */ @@ -3386,22 +3526,31 @@ void free_memory(nagios_macros *mac) { mac->x[MACRO_TEMPFILE] = NULL; /* assigned from temp_file */ my_free(temp_path); mac->x[MACRO_TEMPPATH] = NULL; /*assigned from temp_path */ - my_free(check_result_path); my_free(command_file); mac->x[MACRO_COMMANDFILE] = NULL; /* assigned from command_file */ + + my_free(check_result_path); my_free(log_archive_path); my_free(website_url); + my_free(status_file); + my_free(retention_file); for (i = 0; i < MAX_USER_MACROS; i++) { my_free(macro_user[i]); } /* these have no other reference */ + my_free(mac->x[MACRO_PROCESSSTARTTIME]); + my_free(mac->x[MACRO_EVENTSTARTTIME]); my_free(mac->x[MACRO_ADMINEMAIL]); my_free(mac->x[MACRO_ADMINPAGER]); my_free(mac->x[MACRO_RESOURCEFILE]); my_free(mac->x[MACRO_OBJECTCACHEFILE]); my_free(mac->x[MACRO_MAINCONFIGFILE]); + my_free(mac->x[MACRO_RETENTIONDATAFILE]); + my_free(mac->x[MACRO_HOSTPERFDATAFILE]); + my_free(mac->x[MACRO_STATUSDATAFILE]); + my_free(mac->x[MACRO_SERVICEPERFDATAFILE]); return; } @@ -3504,3 +3653,129 @@ int reset_variables(void) { return OK; } + +/* try and detect any problems with sys limits + we're specifically interested in NPROC + but could easily add NOFILE here if necessary */ +#ifdef DETECT_RLIMIT_PROBLEM +void rlimit_problem_detection(int desired_workers) { + + log_debug_info(DEBUGL_PROCESS, 2, "rlimit_problem_detection()\n"); + + struct rlimit rlim; + int ilim; + host * temp_host = NULL; + service * temp_service = NULL; + + /* how many times a worker forks/execs to run a plugin */ + int forks_per_worker_per_check = 2; + + /* time period to calculate over (in minutes) */ + int time_period_calc = 5; + + /* how many processes do we just want to account for? */ + int arbitrary_user_processes = 300; + + double checks_per_time_period = 0.0; + double this_interval = 0.0; + int total_num_procs = 0; + + + /* first, we grab the NPROC limit, then we check if it isn't unlimited + if it isn't, but the max is, then we set the soft limit to the max + if that doesn't work, or the max isn't unlimited, then we try and + calculate what the current usage is really, and how many workers + we expect to have, and calculate what our usage (generally) is + going to be */ + + ilim = getrlimit(RLIMIT_NPROC, &rlim); + if (ilim != 0) { + + /* nothing we can do here, so just let it keep moving along */ + logit(NSLOG_PROCESS_INFO, TRUE, "WARNING: getrlimit(RLIMIT_NPROC) failed with errno: %s\n", strerror(errno)); + return; + } + + if (rlim.rlim_cur == RLIM_INFINITY) { + + /* we won't have any problems due to fork constraints */ + log_debug_info(DEBUGL_PROCESS, 0, " * RLIMIT_NPROC is unlimited, no need to continue checking.\n"); + return; + } + + desired_workers = get_desired_workers(desired_workers); + + /* calculate the amount of checks + and the worst-case (estimation) frequency in which they repeat */ + for (temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) { + + this_interval = 0; + + if (!(temp_host->checks_enabled)) { + continue; + } + + /* get the smallest possible */ + if (temp_host->check_interval > temp_host->retry_interval + && temp_host->retry_interval != 0) { + + this_interval = temp_host->retry_interval; + } else { + this_interval = temp_host->check_interval; + } + + /* get them on an average scale (5 min) */ + if (this_interval > 0) { + this_interval = ceil((double) time_period_calc / this_interval); + } + + checks_per_time_period += this_interval; + } + + for (temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) { + + this_interval = 0; + + if (!(temp_service->checks_enabled)) { + continue; + } + + /* get the smallest possible */ + if (temp_service->check_interval > temp_service->retry_interval + && temp_service->retry_interval != 0) { + + this_interval = temp_service->retry_interval; + } else { + this_interval = temp_service->check_interval; + } + + /* get them on an average scale (5 min) */ + if (this_interval > 0) { + this_interval = ceil(time_period_calc / this_interval); + } + + checks_per_time_period += this_interval; + } + + total_num_procs = checks_per_time_period * forks_per_worker_per_check; + total_num_procs += desired_workers; + total_num_procs += arbitrary_user_processes; + + log_debug_info(DEBUGL_PROCESS, 0, " * total_num_procs is: %d\n", total_num_procs); + log_debug_info(DEBUGL_PROCESS, 0, " * using forks_per_worker_per_check: %d\n", forks_per_worker_per_check); + log_debug_info(DEBUGL_PROCESS, 0, " * using desired_workers: %d\n", desired_workers); + log_debug_info(DEBUGL_PROCESS, 0, " * using arbitrary_user_processes: %d\n", arbitrary_user_processes); + + + if (rlim.rlim_cur > total_num_procs) { + + log_debug_info(DEBUGL_PROCESS, 0, " * RLIMIT_NPROC is %d, total max estimated processes is %d, everything looks okay!\n", + (int) rlim.rlim_cur, total_num_procs); + } else { + + /* just warn the user - no need to bail out */ + logit(NSLOG_RUNTIME_WARNING, TRUE, "WARNING: RLIMIT_NPROC is %d, total max estimated processes is %d! You should increase your limits (ulimit -u, or limits.conf)\n", + (int) rlim.rlim_cur, total_num_procs); + } +} +#endif diff --git a/base/workers.c b/base/workers.c index 9c74e0c..0d37f4f 100644 --- a/base/workers.c +++ b/base/workers.c @@ -73,17 +73,38 @@ extern struct kvvec * macros_to_kvv(nagios_macros *); static const char *wpjob_type_name(unsigned int type) { switch (type) { - case WPJOB_CHECK: return "CHECK"; - case WPJOB_NOTIFY: return "NOTIFY"; - case WPJOB_OCSP: return "OCSP"; - case WPJOB_OCHP: return "OCHP"; - case WPJOB_GLOBAL_SVC_EVTHANDLER: return "GLOBAL SERVICE EVENTHANDLER"; - case WPJOB_SVC_EVTHANDLER: return "SERVICE EVENTHANDLER"; - case WPJOB_GLOBAL_HOST_EVTHANDLER: return "GLOBAL HOST EVENTHANDLER"; - case WPJOB_HOST_EVTHANDLER: return "HOST EVENTHANDLER"; - case WPJOB_CALLBACK: return "CALLBACK"; - case WPJOB_HOST_PERFDATA: return "HOST PERFDATA"; - case WPJOB_SVC_PERFDATA: return "SERVICE PERFDATA"; + case WPJOB_CHECK: + return "CHECK"; + + case WPJOB_NOTIFY: + return "NOTIFY"; + + case WPJOB_OCSP: + return "OCSP"; + + case WPJOB_OCHP: + return "OCHP"; + + case WPJOB_GLOBAL_SVC_EVTHANDLER: + return "GLOBAL SERVICE EVENTHANDLER"; + + case WPJOB_SVC_EVTHANDLER: + return "SERVICE EVENTHANDLER"; + + case WPJOB_GLOBAL_HOST_EVTHANDLER: + return "GLOBAL HOST EVENTHANDLER"; + + case WPJOB_HOST_EVTHANDLER: + return "HOST EVENTHANDLER"; + + case WPJOB_CALLBACK: + return "CALLBACK"; + + case WPJOB_HOST_PERFDATA: + return "HOST PERFDATA"; + + case WPJOB_SVC_PERFDATA: + return "SERVICE PERFDATA"; } return "UNKNOWN"; } @@ -93,16 +114,21 @@ static void wproc_logdump_buffer(int level, int show, const char *prefix, char * char *ptr, *eol; unsigned int line = 1; - if (!buf || !*buf) + if (!buf || !*buf) { return; + } + for (ptr = buf; ptr && *ptr; ptr = eol ? eol + 1 : NULL) { - if ((eol = strchr(ptr, '\n'))) + if ((eol = strchr(ptr, '\n'))) { *eol = 0; + } logit(level, show, "%s line %.02d: %s\n", prefix, line++, ptr); - if (eol) + if (eol) { *eol = '\n'; - else + } + else { break; + } } } @@ -113,13 +139,17 @@ void wproc_reap(int jobs, int msecs) gettimeofday(&start, NULL); while (jobs > 0 && msecs > 0) { + int inputs = iobroker_poll(nagios_iobs, msecs); - if (inputs < 0) return; + if (inputs < 0) { + return; + } jobs -= inputs; /* One input is roughly equivalent to one job. */ struct timeval now; gettimeofday(&now, NULL); + msecs -= tv_delta_msec(&start, &now); start = now; } @@ -131,20 +161,24 @@ int wproc_can_spawn(struct load_control *lc) time_t now; /* if no load control is enabled, we can safely run this job */ - if (!(lc->options & LOADCTL_ENABLED)) + if (!(lc->options & LOADCTL_ENABLED)) { return 1; + } now = time(NULL); if (lc->last_check + lc->check_interval > now) { + lc->last_check = now; - if (getloadavg(lc->load, 3) < 0) + if (getloadavg(lc->load, 3) < 0) { return lc->jobs_limit > lc->jobs_running; + } if (lc->load[0] > lc->backoff_limit) { old = lc->jobs_limit; lc->jobs_limit -= lc->backoff_change; } + else if (lc->load[0] < lc->rampup_limit) { old = lc->jobs_limit; lc->jobs_limit += lc->rampup_change; @@ -153,6 +187,7 @@ int wproc_can_spawn(struct load_control *lc) if (lc->jobs_limit > lc->jobs_max) { lc->jobs_limit = lc->jobs_max; } + else if (lc->jobs_limit < lc->jobs_min) { logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Tried to set jobs_limit to %u, below jobs_min (%u)\n", lc->jobs_limit, lc->jobs_min); @@ -184,19 +219,28 @@ static struct wproc_job *get_job(struct wproc_worker *wp, int job_id) static struct wproc_list *get_wproc_list(const char *cmd) { - struct wproc_list *wp_list; - char *cmd_name = NULL, *slash = NULL, *space; + struct wproc_list *wp_list = NULL; + char *cmd_name = NULL; + char *slash = NULL; + char *space = NULL; - if (!specialized_workers) + if (!specialized_workers) { return &workers; + } /* first, look for a specialized worker for this command */ - if ((space = strchr(cmd, ' ')) != NULL) { - int namelen = (unsigned long)space - (unsigned long)cmd; + space = strchr(cmd, ' '); + if (space != NULL) { + + int namelen = (unsigned long) space - (unsigned long) cmd; + cmd_name = calloc(1, namelen + 1); + /* not exactly optimal, but what the hells */ - if (!cmd_name) + if (!cmd_name) { return &workers; + } + memcpy(cmd_name, cmd, namelen); slash = strrchr(cmd_name, '/'); } @@ -208,47 +252,85 @@ static struct wproc_list *get_wproc_list(const char *cmd) if (wp_list != NULL) { log_debug_info(DEBUGL_CHECKS, 1, "Found specialized worker(s) for '%s'", (slash && *slash != '/') ? slash : cmd_name); } - if (cmd_name) + if (cmd_name) { free(cmd_name); + } - return wp_list ? wp_list : &workers; + if (wp_list) { + return wp_list; + } + + return &workers; } static struct wproc_worker *get_worker(const char *cmd) { - struct wproc_list *wp_list; + struct wproc_list *wp_list = NULL; - if (!cmd) + log_debug_info(DEBUGL_WORKERS, 0, "get_worker()\n"); + + if (!cmd) { + log_debug_info(DEBUGL_WORKERS, 1, " * cmd is null, bailing\n"); return NULL; + } wp_list = get_wproc_list(cmd); - if (!wp_list || !wp_list->wps || !wp_list->len) + if (!wp_list) { + log_debug_info(DEBUGL_WORKERS, 1, " * wp_list is null, bailing\n"); return NULL; + } + + if (!wp_list->wps) { + log_debug_info(DEBUGL_WORKERS, 1, " * wp_list->wps is null, bailing\n"); + return NULL; + } + + if (!wp_list->len) { + log_debug_info(DEBUGL_WORKERS, 2, " * wp_list->len is <= 0, bailing\n"); + return NULL; + } return wp_list->wps[wp_list->idx++ % wp_list->len]; } static struct wproc_job *create_job(int type, void *arg, time_t timeout, const char *cmd) { - struct wproc_job *job; - struct wproc_worker *wp; + struct wproc_job *job = NULL; + struct wproc_worker *wp = NULL; + int result = 0; + + log_debug_info(DEBUGL_WORKERS, 0, "create_job()\n"); wp = get_worker(cmd); - if (!wp) + if (wp == NULL) { return NULL; + } job = calloc(1, sizeof(*job)); - if (!job) { + if (job == NULL) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to allocate memory for worker job: %s\n", strerror(errno)); return NULL; } - job->wp = wp; - job->id = get_job_id(wp); - job->type = type; - job->arg = arg; + job->wp = wp; + job->id = get_job_id(wp); + job->type = type; + job->arg = arg; job->timeout = timeout; - if (fanout_add(wp->jobs, job->id, job) < 0 || !(job->command = strdup(cmd))) { + + result = fanout_add(wp->jobs, job->id, job); + if (result < 0) { + + log_debug_info(DEBUGL_WORKERS, 1, " * Can't add job to wp->jobs, bailing\n"); + free(job); + return NULL; + } + + job->command = strdup(cmd); + if (job->command == NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * job command can't be null, bailing\n"); free(job); return NULL; } @@ -260,26 +342,48 @@ static void run_job_callback(struct wproc_job *job, struct wproc_result *wpres, { wproc_callback_job *cj; - if (!job || !job->arg) + log_debug_info(DEBUGL_WORKERS, 0, "run_job_callback()\n"); + + if (job == NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * job is null, bailing\n"); return; + } + + if (job->arg == NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * job arg is null, bailing\n"); + return; + } + cj = (struct wproc_callback_job *)job->arg; - if (!cj->callback) + if (cj->callback == NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * callback_job callback is null, bailing\n"); return; + } + cj->callback(wpres, cj->data, val); cj->callback = NULL; } static void destroy_job(struct wproc_job *job) { - if (!job) + if (job == NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * destroy_job -> job is null, bailing\n"); return; + } + + log_debug_info(DEBUGL_WORKERS, 0, "destroy_job(%d=%s)\n", job->type, wpjob_type_name(job->type)); switch (job->type) { case WPJOB_CHECK: free_check_result(job->arg); free(job->arg); break; + case WPJOB_NOTIFY: case WPJOB_OCSP: case WPJOB_OCHP: @@ -294,20 +398,25 @@ static void destroy_job(struct wproc_job *job) case WPJOB_SVC_PERFDATA: /* these require nothing special */ break; + case WPJOB_CALLBACK: /* call with NULL result to make callback clean things up */ run_job_callback(job, NULL, 0); break; + default: logit(NSLOG_RUNTIME_WARNING, TRUE, "wproc: Unknown job type: %d\n", job->type); break; } my_free(job->command); - if (job->wp) { + if (job->wp != NULL) { + + log_debug_info(DEBUGL_WORKERS, 1, " * removing job->wp\n"); fanout_remove(job->wp->jobs, job->id); job->wp->jobs_running--; } + loadctl.jobs_running--; free(job); @@ -320,8 +429,10 @@ static void fo_destroy_job(void *job) static int wproc_is_alive(struct wproc_worker *wp) { - if (!wp || !wp->pid) + if (wp == NULL || wp->pid <= 0) { return 0; + } + if (kill(wp->pid, 0) == 0 && iobroker_is_registered(nagios_iobs, wp->sd)) return 1; return 0; @@ -329,18 +440,22 @@ static int wproc_is_alive(struct wproc_worker *wp) static int wproc_destroy(struct wproc_worker *wp, int flags) { - int i = 0, force = 0, self; + int i = 0; + int force = 0; + int self = 0; - if (!wp) + if (!wp) { return 0; + } force = !!(flags & WPROC_FORCE); self = getpid(); /* master retains workers through restarts */ - if (self == nagios_pid && !force) + if (self == nagios_pid && !force) { return 0; + } /* free all memory when either forcing or a worker called us */ iocache_destroy(wp->ioc); @@ -350,8 +465,9 @@ static int wproc_destroy(struct wproc_worker *wp, int flags) wp->jobs = NULL; /* workers must never control other workers, so they return early */ - if (self != nagios_pid) + if (self != nagios_pid) { return 0; + } /* kill(0, SIGKILL) equals suicide, so we avoid it */ if (wp->pid) { @@ -374,39 +490,54 @@ static int remove_specialized(void *data) { if (data == to_remove) { return DKHASH_WALK_REMOVE; - } else if (to_remove == NULL) { + } + + else if (to_remove == NULL) { + /* remove all specialised workers and their lists */ struct wproc_list *h = data; int i; - for (i=0;ilen;i++) { + + for (i = 0; i < h->len; i++) { + /* not sure what WPROC_FORCE is actually for. * Nagios does *not* retain workers across * restarts, as stated in wproc_destroy? */ wproc_destroy(h->wps[i], WPROC_FORCE); } + h->len = 0; free(h->wps); free(h); + return DKHASH_WALK_REMOVE; } + return 0; } /* remove worker from job assignment list */ static void remove_worker(struct wproc_worker *worker) { - unsigned int i, j = 0; + unsigned int i = 0; + unsigned int j = 0; struct wproc_list *wpl = worker->wp_list; + for (i = 0; i < wpl->len; i++) { - if (wpl->wps[i] == worker) + + if (wpl->wps[i] == worker) { continue; + } + wpl->wps[j++] = wpl->wps[i]; } + wpl->len = j; - if (!specialized_workers || wpl->len) + if (specialized_workers == NULL || wpl->len > 0) { return; + } to_remove = wpl; dkhash_walk_data(specialized_workers, remove_specialized); @@ -438,22 +569,28 @@ void free_worker_memory(int flags) to_remove = NULL; dkhash_walk_data(specialized_workers, remove_specialized); dkhash_destroy(specialized_workers); - specialized_workers = NULL; /* Don't leave pointers to freed memory. */ + + /* Don't leave pointers to freed memory. */ + specialized_workers = NULL; } static int str2timeval(char *str, struct timeval *tv) { - char *ptr, *ptr2; + char *ptr = NULL; + char *ptr2 = NULL; tv->tv_sec = strtoul(str, &ptr, 10); + if (ptr == str) { tv->tv_sec = tv->tv_usec = 0; return -1; } + if (*ptr == '.' || *ptr == ',') { ptr2 = ptr + 1; tv->tv_usec = strtoul(ptr2, &ptr, 10); } + return 0; } @@ -462,29 +599,32 @@ static int handle_worker_check(wproc_result *wpres, struct wproc_worker *wp, str int result = ERROR; check_result *cr = (check_result *)job->arg; - memcpy(&cr->rusage, &wpres->rusage, sizeof(wpres->rusage)); - cr->start_time.tv_sec = wpres->start.tv_sec; - cr->start_time.tv_usec = wpres->start.tv_usec; - cr->finish_time.tv_sec = wpres->stop.tv_sec; + cr->start_time.tv_sec = wpres->start.tv_sec; + cr->start_time.tv_usec = wpres->start.tv_usec; + cr->finish_time.tv_sec = wpres->stop.tv_sec; cr->finish_time.tv_usec = wpres->stop.tv_usec; + if (WIFEXITED(wpres->wait_status)) { cr->return_code = WEXITSTATUS(wpres->wait_status); - } else { + } + else { cr->return_code = STATE_UNKNOWN; } if (wpres->outstd && *wpres->outstd) { cr->output = strdup(wpres->outstd); - } else if (wpres->outerr) { + } + else if (wpres->outerr) { asprintf(&cr->output, "(No output on stdout) stderr: %s", wpres->outerr); - } else { + } + else { cr->output = NULL; } cr->early_timeout = wpres->early_timeout; - cr->exited_ok = wpres->exited_ok; - cr->engine = NULL; - cr->source = wp->name; + cr->exited_ok = wpres->exited_ok; + cr->engine = NULL; + cr->source = wp->name; process_check_result(cr); free_check_result(cr); @@ -554,42 +694,6 @@ static int parse_worker_result(wproc_result *wpres, struct kvvec *kvv) case WPRES_runtime: /* ignored */ break; - case WPRES_ru_utime: - str2timeval(value, &wpres->rusage.ru_utime); - break; - case WPRES_ru_stime: - str2timeval(value, &wpres->rusage.ru_stime); - break; - case WPRES_ru_minflt: - wpres->rusage.ru_minflt = atoi(value); - break; - case WPRES_ru_majflt: - wpres->rusage.ru_majflt = atoi(value); - break; - case WPRES_ru_nswap: - wpres->rusage.ru_nswap = atoi(value); - break; - case WPRES_ru_inblock: - wpres->rusage.ru_inblock = atoi(value); - break; - case WPRES_ru_oublock: - wpres->rusage.ru_oublock = atoi(value); - break; - case WPRES_ru_msgsnd: - wpres->rusage.ru_msgsnd = atoi(value); - break; - case WPRES_ru_msgrcv: - wpres->rusage.ru_msgrcv = atoi(value); - break; - case WPRES_ru_nsignals: - wpres->rusage.ru_nsignals = atoi(value); - break; - case WPRES_ru_nvcsw: - wpres->rusage.ru_nsignals = atoi(value); - break; - case WPRES_ru_nivcsw: - wpres->rusage.ru_nsignals = atoi(value); - break; default: logit(NSLOG_RUNTIME_WARNING, TRUE, "wproc: Recognized but unhandled result variable: %s=%s\n", key, value); @@ -622,8 +726,8 @@ static int handle_worker_result(int sd, int events, void *arg) static struct kvvec kvv = KVVEC_INITIALIZER; struct wproc_worker *wp = (struct wproc_worker *)arg; - if(iocache_capacity(wp->ioc) == 0) { - logit(NSLOG_RUNTIME_WARNING, TRUE, "wproc: iocache_capacity() is 0 for worker %s.\n", wp->name); + if((ret = iocache_capacity(wp->ioc)) < 0) { + logit(NSLOG_RUNTIME_WARNING, TRUE, "wproc: iocache_capacity() is %d for worker %s.\n", ret, wp->name); } ret = iocache_read(wp->ioc, wp->sd); @@ -954,21 +1058,7 @@ static int spawn_core_worker(void) return ret; } - -int init_workers(int desired_workers) -{ - specialized_workers = dkhash_create(512); - if (!specialized_workers) { - logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to allocate specialized worker table.\n"); - return -1; - } - - /* Register our query handler before launching workers, so other workers - * can join us whenever they're ready. */ - if (!qh_register_handler("wproc", "Worker process management and info", 0, wproc_query_handler)) - logit(NSLOG_INFO_MESSAGE, TRUE, "wproc: Successfully registered manager as @wproc with query handler\n"); - else - logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to register manager with query handler\n"); +int get_desired_workers(int desired_workers) { if (desired_workers <= 0) { int cpus = online_cpus(); /* Always at least 1 CPU. */ @@ -992,6 +1082,28 @@ int init_workers(int desired_workers) } } } + + return desired_workers; +} + +/* if this function is updated, the function rlimit_problem_detection() + must be updated as well */ +int init_workers(int desired_workers) +{ + specialized_workers = dkhash_create(512); + if (!specialized_workers) { + logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to allocate specialized worker table.\n"); + return -1; + } + + /* Register our query handler before launching workers, so other workers + * can join us whenever they're ready. */ + if (!qh_register_handler("wproc", "Worker process management and info", 0, wproc_query_handler)) + logit(NSLOG_INFO_MESSAGE, TRUE, "wproc: Successfully registered manager as @wproc with query handler\n"); + else + logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to register manager with query handler\n"); + + desired_workers = get_desired_workers(desired_workers); wproc_num_workers_desired = desired_workers; if (workers_alive() == desired_workers) @@ -1001,8 +1113,10 @@ int init_workers(int desired_workers) if (desired_workers < (int)workers.len) return -1; - while (desired_workers-- > 0) - spawn_core_worker(); + while (desired_workers-- > 0) { + int worker_pid = spawn_core_worker(); + log_debug_info(DEBUGL_WORKERS, 2, "Spawned new worker with pid: (%d)\n", worker_pid); + } return 0; } @@ -1014,21 +1128,33 @@ int init_workers(int desired_workers) */ static int wproc_run_job(struct wproc_job *job, nagios_macros *mac) { - static struct kvvec kvv = KVVEC_INITIALIZER; - struct kvvec_buf *kvvb; - struct kvvec *env_kvvp = NULL; + static struct kvvec kvv = KVVEC_INITIALIZER; + struct kvvec_buf *kvvb = NULL; + struct kvvec *env_kvvp = NULL; struct kvvec_buf *env_kvvb = NULL; - struct wproc_worker *wp; - int ret, result = OK; - ssize_t written = 0; + struct wproc_worker *wp = NULL; + int ret = OK; + int result = OK; + ssize_t written = 0; - if (!job || !job->wp) + log_debug_info(DEBUGL_WORKERS, 1, "wproc_run_job()\n"); + + if (job == NULL) { + log_debug_info(DEBUGL_WORKERS, 1, " * failed because job was null\n"); return ERROR; + } + + if (job->wp == NULL) { + log_debug_info(DEBUGL_WORKERS, 1, " * failed because job worker process was null\n"); + return ERROR; + } wp = job->wp; - if (!kvvec_init(&kvv, 4)) /* job_id, type, command and timeout */ + /* job_id, type, command and timeout */ + if (!kvvec_init(&kvv, 4)) { return ERROR; + } kvvec_addkv(&kvv, "job_id", (char *)mkstr("%d", job->id)); kvvec_addkv(&kvv, "type", (char *)mkstr("%d", job->type)); @@ -1036,37 +1162,53 @@ static int wproc_run_job(struct wproc_job *job, nagios_macros *mac) kvvec_addkv(&kvv, "timeout", (char *)mkstr("%u", job->timeout)); /* Add the macro environment variables */ - if(mac) { + if (mac != NULL) { + env_kvvp = macros_to_kvv(mac); - if(NULL != env_kvvp) { + + if (env_kvvp != NULL) { + env_kvvb = kvvec2buf(env_kvvp, '=', '\n', 0); - if(NULL == env_kvvb) { + + if (env_kvvb == NULL) { kvvec_destroy(env_kvvp, KVVEC_FREE_KEYS); } else { - kvvec_addkv_wlen(&kvv, "env", strlen("env"), env_kvvb->buf, - env_kvvb->buflen); + /* no reason to call strlen("env") + when we know it's 3 characters */ + kvvec_addkv_wlen(&kvv, "env", 3, env_kvvb->buf, env_kvvb->buflen); } } } + kvvb = build_kvvec_buf(&kvv); + /* ret = write(wp->sd, kvvb->buf, kvvb->bufsize); */ ret = nwrite(wp->sd, kvvb->buf, kvvb->bufsize, &written); - if (ret != (int)kvvb->bufsize) { - logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: '%s' seems to be choked. ret = %d; bufsize = %lu: written = %lu; errno = %d (%s)\n", - wp->name, ret, kvvb->bufsize, written, errno, strerror(errno)); + + if (ret != (int) kvvb->bufsize) { + + logit(NSLOG_RUNTIME_ERROR, TRUE, + "wproc: '%s' seems to be choked. ret = %d; bufsize = %lu: written = %lu; errno = %d (%s)\n", + wp->name, ret, kvvb->bufsize, (long unsigned int) written, errno, strerror(errno)); destroy_job(job); result = ERROR; + } else { wp->jobs_running++; wp->jobs_started++; loadctl.jobs_running++; } - if(NULL != env_kvvp) kvvec_destroy(env_kvvp, KVVEC_FREE_KEYS); - if(NULL != env_kvvb) { + + if (env_kvvp != NULL) { + kvvec_destroy(env_kvvp, KVVEC_FREE_KEYS); + } + + if (env_kvvb != NULL) { free(env_kvvb->buf); free(env_kvvb); } + free(kvvb->buf); free(kvvb); diff --git a/cgi/Makefile.in b/cgi/Makefile.in index 24e314d..23d703c 100644 --- a/cgi/Makefile.in +++ b/cgi/Makefile.in @@ -15,8 +15,8 @@ exec_prefix=@exec_prefix@ LOGDIR=@localstatedir@ CFGDIR=@sysconfdir@ BINDIR=@bindir@ -CGIDIR=@sbindir@ -HTMLDIR=@datarootdir@ +CGIDIR=@cgibindir@ +HTMLDIR=@webdir@ INSTALL=@INSTALL@ INSTALL_OPTS=@INSTALL_OPTS@ COMMAND_OPTS=@COMMAND_OPTS@ diff --git a/cgi/archivejson.c b/cgi/archivejson.c index ccf486c..eeb41e5 100644 --- a/cgi/archivejson.c +++ b/cgi/archivejson.c @@ -638,7 +638,7 @@ int main(void) { reset_cgi_vars(); /* read the CGI configuration file */ - result = read_cgi_config_file(get_cgi_config_location()); + result = read_cgi_config_file(get_cgi_config_location(), NULL); if(result == ERROR) { json_object_append_object(json_root, "result", json_result(query_time, THISCGI, @@ -1083,7 +1083,7 @@ int process_cgivars(json_object *json_root, archive_json_cgi_data *cgi_data, variables = getcgivars(); - for(x = 0; variables[x] != NULL; x++) { + for(x = 0; variables[x]; x++) { /* We set these each iteration because they could change with each iteration */ @@ -3291,7 +3291,7 @@ int get_initial_downtime_state(au_linked_list *log_entries, time_t start_time, return initial_state; } else { - /* If we dont' have a downtime state yet, the first downtime + /* If we don't have a downtime state yet, the first downtime state we encounter will be opposite the initial downtime state */ if(AU_LOGTYPE_NOTIFICATION == current_log_entry->entry_type) { diff --git a/cgi/avail.c b/cgi/avail.c index c61262e..54d0e1c 100644 --- a/cgi/avail.c +++ b/cgi/avail.c @@ -285,23 +285,28 @@ int main(int argc, char **argv) { t1 = (time_t)(current_time - (60 * 60 * 24)); /* default number of backtracked archives */ - switch(log_rotation_method) { - case LOG_ROTATION_MONTHLY: - backtrack_archives = 1; - break; - case LOG_ROTATION_WEEKLY: - backtrack_archives = 2; - break; - case LOG_ROTATION_DAILY: - backtrack_archives = 4; - break; - case LOG_ROTATION_HOURLY: - backtrack_archives = 8; - break; - default: - backtrack_archives = 2; - break; - } + switch (log_rotation_method) { + + case LOG_ROTATION_MONTHLY: + backtrack_archives = 1; + break; + + case LOG_ROTATION_WEEKLY: + backtrack_archives = 2; + break; + + case LOG_ROTATION_DAILY: + backtrack_archives = 4; + break; + + case LOG_ROTATION_HOURLY: + backtrack_archives = 8; + break; + + default: + backtrack_archives = 2; + break; + } /* get the arguments passed in the URL */ process_cgivars(); @@ -312,24 +317,24 @@ int main(int argc, char **argv) { get_authentication_information(¤t_authdata); - if(compute_time_from_parts == TRUE) + if (compute_time_from_parts == TRUE) compute_report_times(); /* make sure times are sane, otherwise swap them */ - if(t2 < t1) { + if (t2 < t1) { t3 = t2; t2 = t1; t1 = t3; } /* don't let user create reports in the future */ - if(t2 > current_time) { + if (t2 > current_time) { t2 = current_time; - if(t1 > t2) + if (t1 > t2) t1 = t2 - (60 * 60 * 24); } - if(display_header == TRUE) { + if (display_header == TRUE) { /* begin top table */ printf("\n"); @@ -338,32 +343,37 @@ int main(int argc, char **argv) { /* left column of the first row */ printf("
\n"); - switch(display_type) { - case DISPLAY_HOST_AVAIL: - snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Host Availability Report"); - break; - case DISPLAY_SERVICE_AVAIL: - snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Service Availability Report"); - break; - case DISPLAY_HOSTGROUP_AVAIL: - snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Hostgroup Availability Report"); - break; - case DISPLAY_SERVICEGROUP_AVAIL: - snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Servicegroup Availability Report"); - break; - default: - snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Availability Report"); - break; - } + switch (display_type) { + + case DISPLAY_HOST_AVAIL: + snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Host Availability Report"); + break; + + case DISPLAY_SERVICE_AVAIL: + snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Service Availability Report"); + break; + + case DISPLAY_HOSTGROUP_AVAIL: + snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Hostgroup Availability Report"); + break; + + case DISPLAY_SERVICEGROUP_AVAIL: + snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Servicegroup Availability Report"); + break; + + default: + snprintf(temp_buffer, sizeof(temp_buffer) - 1, "Availability Report"); + break; + } temp_buffer[sizeof(temp_buffer) - 1] = '\x0'; display_info_table(temp_buffer, FALSE, ¤t_authdata); - if(((display_type == DISPLAY_HOST_AVAIL && show_all_hosts == FALSE) || (display_type == DISPLAY_SERVICE_AVAIL && show_all_services == FALSE)) && get_date_parts == FALSE) { + if (((display_type == DISPLAY_HOST_AVAIL && show_all_hosts == FALSE) || (display_type == DISPLAY_SERVICE_AVAIL && show_all_services == FALSE)) && get_date_parts == FALSE) { printf("\n"); printf("