summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am144
-rw-r--r--plugins/Makefile.in3232
-rw-r--r--plugins/check_apt.c561
-rw-r--r--plugins/check_by_ssh.c496
-rw-r--r--plugins/check_cluster.c289
-rw-r--r--plugins/check_curl.c2704
-rw-r--r--plugins/check_dbi.c826
-rw-r--r--plugins/check_dig.c380
-rw-r--r--plugins/check_disk.c1170
-rw-r--r--plugins/check_dns.c619
-rw-r--r--plugins/check_dummy.c124
-rw-r--r--plugins/check_fping.c527
-rw-r--r--plugins/check_game.c348
-rw-r--r--plugins/check_hpjd.c442
-rw-r--r--plugins/check_http.c1895
-rw-r--r--plugins/check_ide_smart.c608
-rw-r--r--plugins/check_ldap.c517
-rw-r--r--plugins/check_load.c417
-rw-r--r--plugins/check_mrtg.c385
-rw-r--r--plugins/check_mrtgtraf.c381
-rw-r--r--plugins/check_mysql.c612
-rw-r--r--plugins/check_mysql_query.c354
-rw-r--r--plugins/check_nagios.c325
-rw-r--r--plugins/check_nt.c801
-rw-r--r--plugins/check_ntp.c900
-rw-r--r--plugins/check_ntp_peer.c756
-rw-r--r--plugins/check_ntp_time.c654
-rw-r--r--plugins/check_nwstat.c1687
-rw-r--r--plugins/check_overcr.c469
-rw-r--r--plugins/check_pgsql.c636
-rw-r--r--plugins/check_ping.c620
-rw-r--r--plugins/check_procs.c834
-rw-r--r--plugins/check_radius.c416
-rw-r--r--plugins/check_real.c454
-rw-r--r--plugins/check_smtp.c929
-rw-r--r--plugins/check_snmp.c1379
-rw-r--r--plugins/check_ssh.c328
-rw-r--r--plugins/check_swap.c610
-rw-r--r--plugins/check_tcp.c715
-rw-r--r--plugins/check_time.c374
-rw-r--r--plugins/check_ups.c665
-rw-r--r--plugins/check_users.c277
-rw-r--r--plugins/common.h228
-rw-r--r--plugins/negate.c275
-rw-r--r--plugins/netutils.c379
-rw-r--r--plugins/netutils.h120
-rw-r--r--plugins/picohttpparser/Makefile.am3
-rw-r--r--plugins/picohttpparser/Makefile.in2026
-rw-r--r--plugins/picohttpparser/picohttpparser.c651
-rw-r--r--plugins/picohttpparser/picohttpparser.h87
-rw-r--r--plugins/popen.c294
-rw-r--r--plugins/popen.h13
-rw-r--r--plugins/runcmd.c342
-rw-r--r--plugins/runcmd.h43
-rw-r--r--plugins/sslutils.c330
-rw-r--r--plugins/t/check_apt.t106
-rw-r--r--plugins/t/check_apt_input/debian14
-rw-r--r--plugins/t/check_apt_input/debian237
-rw-r--r--plugins/t/check_apt_input/debian342
-rw-r--r--plugins/t/check_apt_input/ubuntu114
-rw-r--r--plugins/t/check_apt_input/ubuntu254
-rw-r--r--plugins/t/check_by_ssh.t153
-rw-r--r--plugins/t/check_cluster.t82
-rw-r--r--plugins/t/check_curl.t213
-rw-r--r--plugins/t/check_dbi.t103
-rw-r--r--plugins/t/check_dig.t98
-rw-r--r--plugins/t/check_disk.t378
-rw-r--r--plugins/t/check_dns.t115
-rw-r--r--plugins/t/check_dummy.t54
-rw-r--r--plugins/t/check_fping.t34
-rw-r--r--plugins/t/check_ftp.t28
-rw-r--r--plugins/t/check_hpjd.t71
-rw-r--r--plugins/t/check_http.t190
-rw-r--r--plugins/t/check_imap.t38
-rw-r--r--plugins/t/check_jabber.t50
-rw-r--r--plugins/t/check_ldap.t71
-rw-r--r--plugins/t/check_load.t43
-rw-r--r--plugins/t/check_mysql.t74
-rw-r--r--plugins/t/check_mysql_query.t58
-rw-r--r--plugins/t/check_nagios.nagios1.status.log5
-rw-r--r--plugins/t/check_nagios.nagios2.status.dat127
-rw-r--r--plugins/t/check_nagios.t92
-rw-r--r--plugins/t/check_ntp.t110
-rw-r--r--plugins/t/check_ping.t109
-rw-r--r--plugins/t/check_pop.t55
-rw-r--r--plugins/t/check_procs.t49
-rw-r--r--plugins/t/check_smtp.t84
-rw-r--r--plugins/t/check_snmp.t176
-rw-r--r--plugins/t/check_ssh.t41
-rw-r--r--plugins/t/check_swap.t31
-rw-r--r--plugins/t/check_tcp.t55
-rw-r--r--plugins/t/check_time.t36
-rw-r--r--plugins/t/check_udp.t71
-rw-r--r--plugins/t/check_users.t30
-rw-r--r--plugins/t/negate.t90
-rw-r--r--plugins/tests/certs/.gitignore2
-rw-r--r--plugins/tests/certs/client-cert.pem22
-rw-r--r--plugins/tests/certs/client-key.pem28
-rw-r--r--plugins/tests/certs/clientca-cert.pem25
-rw-r--r--plugins/tests/certs/clientca-key.pem28
-rw-r--r--plugins/tests/certs/clientchain-cert.pem45
-rw-r--r--plugins/tests/certs/clientchain-key.pem28
-rw-r--r--plugins/tests/certs/clientintermediate-cert.pem23
-rw-r--r--plugins/tests/certs/clientintermediate-key.pem28
-rw-r--r--plugins/tests/certs/expired-cert.pem24
-rw-r--r--plugins/tests/certs/expired-key.pem28
-rw-r--r--plugins/tests/certs/ext.cnf2
-rwxr-xr-xplugins/tests/certs/generate-certs.sh63
-rw-r--r--plugins/tests/certs/server-cert.pem24
-rw-r--r--plugins/tests/certs/server-key.pem28
-rwxr-xr-xplugins/tests/check_curl.t526
-rwxr-xr-xplugins/tests/check_http.t581
-rwxr-xr-xplugins/tests/check_nt.t80
-rwxr-xr-xplugins/tests/check_procs.t148
-rwxr-xr-xplugins/tests/check_snmp.t286
-rw-r--r--plugins/tests/check_snmp_agent.pl111
-rw-r--r--plugins/tests/conf/snmpd.conf23
-rw-r--r--plugins/tests/var/ps-axwo.darwin96
-rw-r--r--plugins/tests/var/ps-axwo.debian219
-rw-r--r--plugins/tests/var/root1
-rw-r--r--plugins/urlize.c198
-rw-r--r--plugins/utils.c806
-rw-r--r--plugins/utils.h198
123 files changed, 42593 insertions, 0 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..49086b7
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,144 @@
+## Process this file with automake to produce Makefile.in
+
+if RELEASE_PRESENT
+NP_VERSION = @NP_RELEASE@
+else
+NP-VERSION-FILE: .FORCE-NP-VERSION-FILE
+ @$(SHELL_PATH) $(top_srcdir)/NP-VERSION-GEN
+.FORCE-NP-VERSION-FILE:
+-include NP-VERSION-FILE
+endif
+
+AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"'
+
+VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t
+
+AM_CPPFLAGS = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl \
+ @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@
+
+localedir = $(datadir)/locale
+# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+# gettext docs say to use LDADD, but per module_LDADD override
+LIBS = @LTLIBINTL@ @LIBS@
+MATHLIBS = @MATHLIBS@
+
+# This is not portable. Run ". tools/devmode" to get development compile flags
+#AM_CFLAGS = -Wall
+
+libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
+ check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_overcr check_ping \
+ check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
+ check_ups check_users negate \
+ urlize @EXTRAS@
+
+check_tcp_programs = check_ftp check_imap check_nntp check_pop \
+ check_udp check_clamd @check_tcp_ssl@
+
+EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
+ check_swap check_fping check_ldap check_game check_dig \
+ check_nagios check_by_ssh check_dns check_nt check_ide_smart \
+ check_procs check_mysql_query check_apt check_dbi check_curl
+
+SUBDIRS = picohttpparser
+
+EXTRA_DIST = t tests
+
+PLUGINHDRS = common.h
+
+noinst_LIBRARIES = libnpcommon.a
+
+libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
+ popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
+
+BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
+NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
+NETLIBS = $(NETOBJS) $(SOCKETLIBS)
+SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
+
+TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
+
+TESTS = @PLUGIN_TEST@
+
+test:
+ perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
+
+test-debug:
+ NPTEST_DEBUG=1 HARNESS_VERBOSE=1 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
+
+##############################################################################
+# the actual targets
+
+check_apt_LDADD = $(BASEOBJS)
+check_cluster_LDADD = $(BASEOBJS)
+check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
+check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
+check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
+check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
+check_dig_LDADD = $(NETLIBS)
+check_disk_LDADD = $(BASEOBJS)
+check_dns_LDADD = $(NETLIBS)
+check_dummy_LDADD = $(BASEOBJS)
+check_fping_LDADD = $(NETLIBS)
+check_game_LDADD = $(BASEOBJS)
+check_http_LDADD = $(SSLOBJS)
+check_hpjd_LDADD = $(NETLIBS)
+check_ldap_LDADD = $(NETLIBS) $(LDAPLIBS)
+check_load_LDADD = $(BASEOBJS)
+check_mrtg_LDADD = $(BASEOBJS)
+check_mrtgtraf_LDADD = $(BASEOBJS)
+check_mysql_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
+check_mysql_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
+check_mysql_LDADD = $(NETLIBS) $(MYSQLLIBS)
+check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
+check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
+check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
+check_nagios_LDADD = $(BASEOBJS)
+check_nt_LDADD = $(NETLIBS)
+check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
+check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
+check_nwstat_LDADD = $(NETLIBS)
+check_overcr_LDADD = $(NETLIBS)
+check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
+check_ping_LDADD = $(NETLIBS)
+check_procs_LDADD = $(BASEOBJS)
+check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
+check_real_LDADD = $(NETLIBS)
+check_snmp_LDADD = $(BASEOBJS)
+check_smtp_LDADD = $(SSLOBJS)
+check_ssh_LDADD = $(NETLIBS)
+check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
+check_tcp_LDADD = $(SSLOBJS)
+check_time_LDADD = $(NETLIBS)
+check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS)
+check_ups_LDADD = $(NETLIBS)
+check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS)
+check_by_ssh_LDADD = $(NETLIBS)
+check_ide_smart_LDADD = $(BASEOBJS)
+negate_LDADD = $(BASEOBJS)
+urlize_LDADD = $(BASEOBJS)
+
+if !HAVE_UTMPX
+check_users_LDADD += popen.o
+endif
+
+##############################################################################
+# secondary dependencies
+
+all-local: $(check_tcp_programs)
+
+$(check_tcp_programs): check_tcp
+ rm -f $@
+ ln -s check_tcp $@
+
+install-exec-hook:
+ cd $(DESTDIR)$(libexecdir) && \
+ for i in $(check_tcp_programs) ; do rm -f $$i; ln -s check_tcp $$i ; done ;\
+ if [ -x check_ldap ] ; then rm -f check_ldaps ; ln -s check_ldap check_ldaps ; fi
+
+clean-local:
+ rm -f $(check_tcp_programs)
+ rm -f NP-VERSION-FILE
+
+uninstall-local:
+ cd $(DESTDIR)$(libexecdir) && rm -f $(check_tcp_programs)
diff --git a/plugins/Makefile.in b/plugins/Makefile.in
new file mode 100644
index 0000000..dc5f6cf
--- /dev/null
+++ b/plugins/Makefile.in
@@ -0,0 +1,3232 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+libexec_PROGRAMS = check_apt$(EXEEXT) check_cluster$(EXEEXT) \
+ check_disk$(EXEEXT) check_dummy$(EXEEXT) check_http$(EXEEXT) \
+ check_load$(EXEEXT) check_mrtg$(EXEEXT) \
+ check_mrtgtraf$(EXEEXT) check_ntp$(EXEEXT) \
+ check_ntp_peer$(EXEEXT) check_nwstat$(EXEEXT) \
+ check_overcr$(EXEEXT) check_ping$(EXEEXT) check_real$(EXEEXT) \
+ check_smtp$(EXEEXT) check_ssh$(EXEEXT) check_tcp$(EXEEXT) \
+ check_time$(EXEEXT) check_ntp_time$(EXEEXT) check_ups$(EXEEXT) \
+ check_users$(EXEEXT) negate$(EXEEXT) urlize$(EXEEXT) @EXTRAS@
+EXTRA_PROGRAMS = check_mysql$(EXEEXT) check_radius$(EXEEXT) \
+ check_pgsql$(EXEEXT) check_snmp$(EXEEXT) check_hpjd$(EXEEXT) \
+ check_swap$(EXEEXT) check_fping$(EXEEXT) check_ldap$(EXEEXT) \
+ check_game$(EXEEXT) check_dig$(EXEEXT) check_nagios$(EXEEXT) \
+ check_by_ssh$(EXEEXT) check_dns$(EXEEXT) check_nt$(EXEEXT) \
+ check_ide_smart$(EXEEXT) check_procs$(EXEEXT) \
+ check_mysql_query$(EXEEXT) check_apt$(EXEEXT) \
+ check_dbi$(EXEEXT) check_curl$(EXEEXT)
+@HAVE_UTMPX_FALSE@am__append_1 = popen.o
+subdir = plugins
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \
+ $(top_srcdir)/m4/np_mysqlclient.m4 \
+ $(top_srcdir)/m4/uriparser.m4 $(top_srcdir)/gl/m4/00gnulib.m4 \
+ $(top_srcdir)/gl/m4/__inline.m4 \
+ $(top_srcdir)/gl/m4/absolute-header.m4 \
+ $(top_srcdir)/gl/m4/af_alg.m4 $(top_srcdir)/gl/m4/alloca.m4 \
+ $(top_srcdir)/gl/m4/arpa_inet_h.m4 \
+ $(top_srcdir)/gl/m4/assert_h.m4 $(top_srcdir)/gl/m4/base64.m4 \
+ $(top_srcdir)/gl/m4/btowc.m4 \
+ $(top_srcdir)/gl/m4/builtin-expect.m4 \
+ $(top_srcdir)/gl/m4/byteswap.m4 $(top_srcdir)/gl/m4/c-bool.m4 \
+ $(top_srcdir)/gl/m4/calloc.m4 $(top_srcdir)/gl/m4/close.m4 \
+ $(top_srcdir)/gl/m4/codeset.m4 \
+ $(top_srcdir)/gl/m4/double-slash-root.m4 \
+ $(top_srcdir)/gl/m4/dup2.m4 $(top_srcdir)/gl/m4/eealloc.m4 \
+ $(top_srcdir)/gl/m4/environ.m4 $(top_srcdir)/gl/m4/errno_h.m4 \
+ $(top_srcdir)/gl/m4/error.m4 $(top_srcdir)/gl/m4/exponentd.m4 \
+ $(top_srcdir)/gl/m4/extensions.m4 \
+ $(top_srcdir)/gl/m4/extern-inline.m4 \
+ $(top_srcdir)/gl/m4/fcntl-o.m4 $(top_srcdir)/gl/m4/fcntl.m4 \
+ $(top_srcdir)/gl/m4/fcntl_h.m4 $(top_srcdir)/gl/m4/fflush.m4 \
+ $(top_srcdir)/gl/m4/float_h.m4 $(top_srcdir)/gl/m4/floorf.m4 \
+ $(top_srcdir)/gl/m4/fopen.m4 $(top_srcdir)/gl/m4/fpurge.m4 \
+ $(top_srcdir)/gl/m4/freading.m4 $(top_srcdir)/gl/m4/free.m4 \
+ $(top_srcdir)/gl/m4/fseek.m4 $(top_srcdir)/gl/m4/fseeko.m4 \
+ $(top_srcdir)/gl/m4/fstat.m4 $(top_srcdir)/gl/m4/fstypename.m4 \
+ $(top_srcdir)/gl/m4/fsusage.m4 $(top_srcdir)/gl/m4/ftell.m4 \
+ $(top_srcdir)/gl/m4/ftello.m4 \
+ $(top_srcdir)/gl/m4/getaddrinfo.m4 \
+ $(top_srcdir)/gl/m4/getdelim.m4 \
+ $(top_srcdir)/gl/m4/getdtablesize.m4 \
+ $(top_srcdir)/gl/m4/gethostname.m4 \
+ $(top_srcdir)/gl/m4/getline.m4 \
+ $(top_srcdir)/gl/m4/getloadavg.m4 \
+ $(top_srcdir)/gl/m4/getopt.m4 \
+ $(top_srcdir)/gl/m4/getprogname.m4 \
+ $(top_srcdir)/gl/m4/gl-openssl.m4 \
+ $(top_srcdir)/gl/m4/gnulib-common.m4 \
+ $(top_srcdir)/gl/m4/gnulib-comp.m4 \
+ $(top_srcdir)/gl/m4/hostent.m4 $(top_srcdir)/gl/m4/idpriv.m4 \
+ $(top_srcdir)/gl/m4/include_next.m4 \
+ $(top_srcdir)/gl/m4/inet_ntop.m4 \
+ $(top_srcdir)/gl/m4/intmax_t.m4 \
+ $(top_srcdir)/gl/m4/inttypes.m4 \
+ $(top_srcdir)/gl/m4/inttypes_h.m4 \
+ $(top_srcdir)/gl/m4/langinfo_h.m4 \
+ $(top_srcdir)/gl/m4/largefile.m4 \
+ $(top_srcdir)/gl/m4/libtool.m4 $(top_srcdir)/gl/m4/limits-h.m4 \
+ $(top_srcdir)/gl/m4/localcharset.m4 \
+ $(top_srcdir)/gl/m4/locale-fr.m4 \
+ $(top_srcdir)/gl/m4/locale-ja.m4 \
+ $(top_srcdir)/gl/m4/locale-zh.m4 \
+ $(top_srcdir)/gl/m4/locale_h.m4 \
+ $(top_srcdir)/gl/m4/localeconv.m4 $(top_srcdir)/gl/m4/lock.m4 \
+ $(top_srcdir)/gl/m4/lseek.m4 $(top_srcdir)/gl/m4/ltoptions.m4 \
+ $(top_srcdir)/gl/m4/ltsugar.m4 \
+ $(top_srcdir)/gl/m4/ltversion.m4 \
+ $(top_srcdir)/gl/m4/lt~obsolete.m4 \
+ $(top_srcdir)/gl/m4/malloc.m4 $(top_srcdir)/gl/m4/malloca.m4 \
+ $(top_srcdir)/gl/m4/math_h.m4 $(top_srcdir)/gl/m4/mbrtowc.m4 \
+ $(top_srcdir)/gl/m4/mbsinit.m4 \
+ $(top_srcdir)/gl/m4/mbstate_t.m4 $(top_srcdir)/gl/m4/mbtowc.m4 \
+ $(top_srcdir)/gl/m4/memchr.m4 $(top_srcdir)/gl/m4/minmax.m4 \
+ $(top_srcdir)/gl/m4/mktime.m4 $(top_srcdir)/gl/m4/mmap-anon.m4 \
+ $(top_srcdir)/gl/m4/mode_t.m4 $(top_srcdir)/gl/m4/mountlist.m4 \
+ $(top_srcdir)/gl/m4/msvc-inval.m4 \
+ $(top_srcdir)/gl/m4/msvc-nothrow.m4 \
+ $(top_srcdir)/gl/m4/multiarch.m4 \
+ $(top_srcdir)/gl/m4/netdb_h.m4 \
+ $(top_srcdir)/gl/m4/netinet_in_h.m4 \
+ $(top_srcdir)/gl/m4/nl_langinfo.m4 \
+ $(top_srcdir)/gl/m4/nocrash.m4 $(top_srcdir)/gl/m4/off_t.m4 \
+ $(top_srcdir)/gl/m4/open-cloexec.m4 \
+ $(top_srcdir)/gl/m4/open-slash.m4 $(top_srcdir)/gl/m4/open.m4 \
+ $(top_srcdir)/gl/m4/pathmax.m4 $(top_srcdir)/gl/m4/pid_t.m4 \
+ $(top_srcdir)/gl/m4/printf.m4 \
+ $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \
+ $(top_srcdir)/gl/m4/realloc.m4 \
+ $(top_srcdir)/gl/m4/reallocarray.m4 \
+ $(top_srcdir)/gl/m4/regex.m4 $(top_srcdir)/gl/m4/servent.m4 \
+ $(top_srcdir)/gl/m4/setenv.m4 \
+ $(top_srcdir)/gl/m4/setlocale_null.m4 \
+ $(top_srcdir)/gl/m4/sha256.m4 $(top_srcdir)/gl/m4/size_max.m4 \
+ $(top_srcdir)/gl/m4/snprintf.m4 \
+ $(top_srcdir)/gl/m4/socketlib.m4 \
+ $(top_srcdir)/gl/m4/sockets.m4 $(top_srcdir)/gl/m4/socklen.m4 \
+ $(top_srcdir)/gl/m4/sockpfaf.m4 $(top_srcdir)/gl/m4/ssize_t.m4 \
+ $(top_srcdir)/gl/m4/stat-time.m4 $(top_srcdir)/gl/m4/stat.m4 \
+ $(top_srcdir)/gl/m4/std-gnu11.m4 \
+ $(top_srcdir)/gl/m4/stdalign.m4 \
+ $(top_srcdir)/gl/m4/stddef_h.m4 $(top_srcdir)/gl/m4/stdint.m4 \
+ $(top_srcdir)/gl/m4/stdint_h.m4 $(top_srcdir)/gl/m4/stdio_h.m4 \
+ $(top_srcdir)/gl/m4/stdlib_h.m4 $(top_srcdir)/gl/m4/strcase.m4 \
+ $(top_srcdir)/gl/m4/strcasestr.m4 \
+ $(top_srcdir)/gl/m4/strerror.m4 \
+ $(top_srcdir)/gl/m4/string_h.m4 \
+ $(top_srcdir)/gl/m4/strings_h.m4 $(top_srcdir)/gl/m4/strsep.m4 \
+ $(top_srcdir)/gl/m4/strstr.m4 \
+ $(top_srcdir)/gl/m4/sys_socket_h.m4 \
+ $(top_srcdir)/gl/m4/sys_stat_h.m4 \
+ $(top_srcdir)/gl/m4/sys_types_h.m4 \
+ $(top_srcdir)/gl/m4/sys_uio_h.m4 \
+ $(top_srcdir)/gl/m4/threadlib.m4 $(top_srcdir)/gl/m4/time_h.m4 \
+ $(top_srcdir)/gl/m4/time_r.m4 $(top_srcdir)/gl/m4/timegm.m4 \
+ $(top_srcdir)/gl/m4/ungetc.m4 $(top_srcdir)/gl/m4/unistd_h.m4 \
+ $(top_srcdir)/gl/m4/unlocked-io.m4 \
+ $(top_srcdir)/gl/m4/vararrays.m4 \
+ $(top_srcdir)/gl/m4/vasnprintf.m4 \
+ $(top_srcdir)/gl/m4/vasprintf.m4 \
+ $(top_srcdir)/gl/m4/visibility.m4 \
+ $(top_srcdir)/gl/m4/vsnprintf.m4 \
+ $(top_srcdir)/gl/m4/warn-on-use.m4 \
+ $(top_srcdir)/gl/m4/wchar_h.m4 $(top_srcdir)/gl/m4/wchar_t.m4 \
+ $(top_srcdir)/gl/m4/wcrtomb.m4 $(top_srcdir)/gl/m4/wctype_h.m4 \
+ $(top_srcdir)/gl/m4/wint_t.m4 $(top_srcdir)/gl/m4/xalloc.m4 \
+ $(top_srcdir)/gl/m4/xsize.m4 $(top_srcdir)/gl/m4/zzgnulib.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(libexecdir)"
+PROGRAMS = $(libexec_PROGRAMS)
+LIBRARIES = $(noinst_LIBRARIES)
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libnpcommon_a_AR = $(AR) $(ARFLAGS)
+libnpcommon_a_LIBADD =
+am_libnpcommon_a_OBJECTS = utils.$(OBJEXT) netutils.$(OBJEXT) \
+ sslutils.$(OBJEXT) runcmd.$(OBJEXT) popen.$(OBJEXT) \
+ runcmd.$(OBJEXT)
+libnpcommon_a_OBJECTS = $(am_libnpcommon_a_OBJECTS)
+check_apt_SOURCES = check_apt.c
+check_apt_OBJECTS = check_apt.$(OBJEXT)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = libnpcommon.a ../lib/libmonitoringplug.a \
+ ../gl/libgnu.a $(am__DEPENDENCIES_1)
+check_apt_DEPENDENCIES = $(am__DEPENDENCIES_2)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+check_by_ssh_SOURCES = check_by_ssh.c
+check_by_ssh_OBJECTS = check_by_ssh.$(OBJEXT)
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2)
+am__DEPENDENCIES_4 = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
+check_by_ssh_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_cluster_SOURCES = check_cluster.c
+check_cluster_OBJECTS = check_cluster.$(OBJEXT)
+check_cluster_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_curl_SOURCES = check_curl.c
+check_curl_OBJECTS = check_curl-check_curl.$(OBJEXT)
+am__DEPENDENCIES_5 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+check_curl_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_1) \
+ picohttpparser/libpicohttpparser.a
+check_curl_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(check_curl_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+check_dbi_SOURCES = check_dbi.c
+check_dbi_OBJECTS = check_dbi.$(OBJEXT)
+check_dbi_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+check_dig_SOURCES = check_dig.c
+check_dig_OBJECTS = check_dig.$(OBJEXT)
+check_dig_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_disk_SOURCES = check_disk.c
+check_disk_OBJECTS = check_disk.$(OBJEXT)
+check_disk_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_dns_SOURCES = check_dns.c
+check_dns_OBJECTS = check_dns.$(OBJEXT)
+check_dns_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_dummy_SOURCES = check_dummy.c
+check_dummy_OBJECTS = check_dummy.$(OBJEXT)
+check_dummy_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_fping_SOURCES = check_fping.c
+check_fping_OBJECTS = check_fping.$(OBJEXT)
+check_fping_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_game_SOURCES = check_game.c
+check_game_OBJECTS = check_game.$(OBJEXT)
+check_game_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_hpjd_SOURCES = check_hpjd.c
+check_hpjd_OBJECTS = check_hpjd.$(OBJEXT)
+check_hpjd_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_http_SOURCES = check_http.c
+check_http_OBJECTS = check_http.$(OBJEXT)
+check_http_DEPENDENCIES = $(am__DEPENDENCIES_5)
+check_ide_smart_SOURCES = check_ide_smart.c
+check_ide_smart_OBJECTS = check_ide_smart.$(OBJEXT)
+check_ide_smart_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_ldap_SOURCES = check_ldap.c
+check_ldap_OBJECTS = check_ldap.$(OBJEXT)
+check_ldap_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+check_load_SOURCES = check_load.c
+check_load_OBJECTS = check_load.$(OBJEXT)
+check_load_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_mrtg_SOURCES = check_mrtg.c
+check_mrtg_OBJECTS = check_mrtg.$(OBJEXT)
+check_mrtg_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_mrtgtraf_SOURCES = check_mrtgtraf.c
+check_mrtgtraf_OBJECTS = check_mrtgtraf.$(OBJEXT)
+check_mrtgtraf_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_mysql_SOURCES = check_mysql.c
+check_mysql_OBJECTS = check_mysql-check_mysql.$(OBJEXT)
+check_mysql_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+check_mysql_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(check_mysql_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+check_mysql_query_SOURCES = check_mysql_query.c
+check_mysql_query_OBJECTS = \
+ check_mysql_query-check_mysql_query.$(OBJEXT)
+check_mysql_query_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1)
+check_mysql_query_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(check_mysql_query_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+check_nagios_SOURCES = check_nagios.c
+check_nagios_OBJECTS = check_nagios.$(OBJEXT)
+check_nagios_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_nt_SOURCES = check_nt.c
+check_nt_OBJECTS = check_nt.$(OBJEXT)
+check_nt_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_ntp_SOURCES = check_ntp.c
+check_ntp_OBJECTS = check_ntp.$(OBJEXT)
+check_ntp_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+check_ntp_peer_SOURCES = check_ntp_peer.c
+check_ntp_peer_OBJECTS = check_ntp_peer.$(OBJEXT)
+check_ntp_peer_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1)
+check_ntp_time_SOURCES = check_ntp_time.c
+check_ntp_time_OBJECTS = check_ntp_time.$(OBJEXT)
+check_ntp_time_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1)
+check_nwstat_SOURCES = check_nwstat.c
+check_nwstat_OBJECTS = check_nwstat.$(OBJEXT)
+check_nwstat_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_overcr_SOURCES = check_overcr.c
+check_overcr_OBJECTS = check_overcr.$(OBJEXT)
+check_overcr_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_pgsql_SOURCES = check_pgsql.c
+check_pgsql_OBJECTS = check_pgsql.$(OBJEXT)
+check_pgsql_DEPENDENCIES = $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+check_ping_SOURCES = check_ping.c
+check_ping_OBJECTS = check_ping.$(OBJEXT)
+check_ping_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_procs_SOURCES = check_procs.c
+check_procs_OBJECTS = check_procs.$(OBJEXT)
+check_procs_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_radius_SOURCES = check_radius.c
+check_radius_OBJECTS = check_radius.$(OBJEXT)
+check_radius_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_1)
+check_real_SOURCES = check_real.c
+check_real_OBJECTS = check_real.$(OBJEXT)
+check_real_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_smtp_SOURCES = check_smtp.c
+check_smtp_OBJECTS = check_smtp.$(OBJEXT)
+check_smtp_DEPENDENCIES = $(am__DEPENDENCIES_5)
+check_snmp_SOURCES = check_snmp.c
+check_snmp_OBJECTS = check_snmp.$(OBJEXT)
+check_snmp_DEPENDENCIES = $(am__DEPENDENCIES_2)
+check_ssh_SOURCES = check_ssh.c
+check_ssh_OBJECTS = check_ssh.$(OBJEXT)
+check_ssh_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_swap_SOURCES = check_swap.c
+check_swap_OBJECTS = check_swap.$(OBJEXT)
+check_swap_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+check_tcp_SOURCES = check_tcp.c
+check_tcp_OBJECTS = check_tcp.$(OBJEXT)
+check_tcp_DEPENDENCIES = $(am__DEPENDENCIES_5)
+check_time_SOURCES = check_time.c
+check_time_OBJECTS = check_time.$(OBJEXT)
+check_time_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_ups_SOURCES = check_ups.c
+check_ups_OBJECTS = check_ups.$(OBJEXT)
+check_ups_DEPENDENCIES = $(am__DEPENDENCIES_4)
+check_users_SOURCES = check_users.c
+check_users_OBJECTS = check_users.$(OBJEXT)
+check_users_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__append_1)
+negate_SOURCES = negate.c
+negate_OBJECTS = negate.$(OBJEXT)
+negate_DEPENDENCIES = $(am__DEPENDENCIES_2)
+urlize_SOURCES = urlize.c
+urlize_OBJECTS = urlize.$(OBJEXT)
+urlize_DEPENDENCIES = $(am__DEPENDENCIES_2)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/check_apt.Po \
+ ./$(DEPDIR)/check_by_ssh.Po ./$(DEPDIR)/check_cluster.Po \
+ ./$(DEPDIR)/check_curl-check_curl.Po ./$(DEPDIR)/check_dbi.Po \
+ ./$(DEPDIR)/check_dig.Po ./$(DEPDIR)/check_disk.Po \
+ ./$(DEPDIR)/check_dns.Po ./$(DEPDIR)/check_dummy.Po \
+ ./$(DEPDIR)/check_fping.Po ./$(DEPDIR)/check_game.Po \
+ ./$(DEPDIR)/check_hpjd.Po ./$(DEPDIR)/check_http.Po \
+ ./$(DEPDIR)/check_ide_smart.Po ./$(DEPDIR)/check_ldap.Po \
+ ./$(DEPDIR)/check_load.Po ./$(DEPDIR)/check_mrtg.Po \
+ ./$(DEPDIR)/check_mrtgtraf.Po \
+ ./$(DEPDIR)/check_mysql-check_mysql.Po \
+ ./$(DEPDIR)/check_mysql_query-check_mysql_query.Po \
+ ./$(DEPDIR)/check_nagios.Po ./$(DEPDIR)/check_nt.Po \
+ ./$(DEPDIR)/check_ntp.Po ./$(DEPDIR)/check_ntp_peer.Po \
+ ./$(DEPDIR)/check_ntp_time.Po ./$(DEPDIR)/check_nwstat.Po \
+ ./$(DEPDIR)/check_overcr.Po ./$(DEPDIR)/check_pgsql.Po \
+ ./$(DEPDIR)/check_ping.Po ./$(DEPDIR)/check_procs.Po \
+ ./$(DEPDIR)/check_radius.Po ./$(DEPDIR)/check_real.Po \
+ ./$(DEPDIR)/check_smtp.Po ./$(DEPDIR)/check_snmp.Po \
+ ./$(DEPDIR)/check_ssh.Po ./$(DEPDIR)/check_swap.Po \
+ ./$(DEPDIR)/check_tcp.Po ./$(DEPDIR)/check_time.Po \
+ ./$(DEPDIR)/check_ups.Po ./$(DEPDIR)/check_users.Po \
+ ./$(DEPDIR)/negate.Po ./$(DEPDIR)/netutils.Po \
+ ./$(DEPDIR)/popen.Po ./$(DEPDIR)/runcmd.Po \
+ ./$(DEPDIR)/sslutils.Po ./$(DEPDIR)/urlize.Po \
+ ./$(DEPDIR)/utils.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libnpcommon_a_SOURCES) check_apt.c check_by_ssh.c \
+ check_cluster.c check_curl.c check_dbi.c check_dig.c \
+ check_disk.c check_dns.c check_dummy.c check_fping.c \
+ check_game.c check_hpjd.c check_http.c check_ide_smart.c \
+ check_ldap.c check_load.c check_mrtg.c check_mrtgtraf.c \
+ check_mysql.c check_mysql_query.c check_nagios.c check_nt.c \
+ check_ntp.c check_ntp_peer.c check_ntp_time.c check_nwstat.c \
+ check_overcr.c check_pgsql.c check_ping.c check_procs.c \
+ check_radius.c check_real.c check_smtp.c check_snmp.c \
+ check_ssh.c check_swap.c check_tcp.c check_time.c check_ups.c \
+ check_users.c negate.c urlize.c
+DIST_SOURCES = $(libnpcommon_a_SOURCES) check_apt.c check_by_ssh.c \
+ check_cluster.c check_curl.c check_dbi.c check_dig.c \
+ check_disk.c check_dns.c check_dummy.c check_fping.c \
+ check_game.c check_hpjd.c check_http.c check_ide_smart.c \
+ check_ldap.c check_load.c check_mrtg.c check_mrtgtraf.c \
+ check_mysql.c check_mysql_query.c check_nagios.c check_nt.c \
+ check_ntp.c check_ntp_peer.c check_ntp_time.c check_nwstat.c \
+ check_overcr.c check_pgsql.c check_ping.c check_procs.c \
+ check_radius.c check_real.c check_smtp.c check_snmp.c \
+ check_ssh.c check_swap.c check_tcp.c check_time.c check_ups.c \
+ check_users.c negate.c urlize.c
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ check recheck distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp \
+ $(top_srcdir)/build-aux/mkinstalldirs \
+ $(top_srcdir)/build-aux/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+ASSERT_H = @ASSERT_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASENAME = @BASENAME@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+BYTESWAP_H = @BYTESWAP_H@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBILIBS = @DBILIBS@
+# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+DEPDIR = @DEPDIR@
+DEPLIBS = @DEPLIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+EXEEXT = @EXEEXT@
+EXTRAS = @EXTRAS@
+EXTRAS_ROOT = @EXTRAS_ROOT@
+EXTRA_NETOBJS = @EXTRA_NETOBJS@
+EXTRA_TEST = @EXTRA_TEST@
+FGREP = @FGREP@
+FLOAT_H = @FLOAT_H@
+FLOORF_LIBM = @FLOORF_LIBM@
+GETADDRINFO_LIB = @GETADDRINFO_LIB@
+GETHOSTNAME_LIB = @GETHOSTNAME_LIB@
+GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
+GETOPT_CDEFS_H = @GETOPT_CDEFS_H@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@
+GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@
+GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@
+GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ACOSF = @GL_GNULIB_ACOSF@
+GL_GNULIB_ACOSL = @GL_GNULIB_ACOSL@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ASINF = @GL_GNULIB_ASINF@
+GL_GNULIB_ASINL = @GL_GNULIB_ASINL@
+GL_GNULIB_ATAN2F = @GL_GNULIB_ATAN2F@
+GL_GNULIB_ATANF = @GL_GNULIB_ATANF@
+GL_GNULIB_ATANL = @GL_GNULIB_ATANL@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_BIND = @GL_GNULIB_BIND@
+GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@
+GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CBRT = @GL_GNULIB_CBRT@
+GL_GNULIB_CBRTF = @GL_GNULIB_CBRTF@
+GL_GNULIB_CBRTL = @GL_GNULIB_CBRTL@
+GL_GNULIB_CEIL = @GL_GNULIB_CEIL@
+GL_GNULIB_CEILF = @GL_GNULIB_CEILF@
+GL_GNULIB_CEILL = @GL_GNULIB_CEILL@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@
+GL_GNULIB_COPYSIGN = @GL_GNULIB_COPYSIGN@
+GL_GNULIB_COPYSIGNF = @GL_GNULIB_COPYSIGNF@
+GL_GNULIB_COPYSIGNL = @GL_GNULIB_COPYSIGNL@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_COSF = @GL_GNULIB_COSF@
+GL_GNULIB_COSHF = @GL_GNULIB_COSHF@
+GL_GNULIB_COSL = @GL_GNULIB_COSL@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXP2 = @GL_GNULIB_EXP2@
+GL_GNULIB_EXP2F = @GL_GNULIB_EXP2F@
+GL_GNULIB_EXP2L = @GL_GNULIB_EXP2L@
+GL_GNULIB_EXPF = @GL_GNULIB_EXPF@
+GL_GNULIB_EXPL = @GL_GNULIB_EXPL@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_EXPM1 = @GL_GNULIB_EXPM1@
+GL_GNULIB_EXPM1F = @GL_GNULIB_EXPM1F@
+GL_GNULIB_EXPM1L = @GL_GNULIB_EXPM1L@
+GL_GNULIB_FABSF = @GL_GNULIB_FABSF@
+GL_GNULIB_FABSL = @GL_GNULIB_FABSL@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFS = @GL_GNULIB_FFS@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FLOOR = @GL_GNULIB_FLOOR@
+GL_GNULIB_FLOORF = @GL_GNULIB_FLOORF@
+GL_GNULIB_FLOORL = @GL_GNULIB_FLOORL@
+GL_GNULIB_FMA = @GL_GNULIB_FMA@
+GL_GNULIB_FMAF = @GL_GNULIB_FMAF@
+GL_GNULIB_FMAL = @GL_GNULIB_FMAL@
+GL_GNULIB_FMOD = @GL_GNULIB_FMOD@
+GL_GNULIB_FMODF = @GL_GNULIB_FMODF@
+GL_GNULIB_FMODL = @GL_GNULIB_FMODL@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FREXP = @GL_GNULIB_FREXP@
+GL_GNULIB_FREXPF = @GL_GNULIB_FREXPF@
+GL_GNULIB_FREXPL = @GL_GNULIB_FREXPL@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETADDRINFO = @GL_GNULIB_GETADDRINFO@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@
+GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@
+GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@
+GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_HYPOT = @GL_GNULIB_HYPOT@
+GL_GNULIB_HYPOTF = @GL_GNULIB_HYPOTF@
+GL_GNULIB_HYPOTL = @GL_GNULIB_HYPOTL@
+GL_GNULIB_ILOGB = @GL_GNULIB_ILOGB@
+GL_GNULIB_ILOGBF = @GL_GNULIB_ILOGBF@
+GL_GNULIB_ILOGBL = @GL_GNULIB_ILOGBL@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_INET_NTOP = @GL_GNULIB_INET_NTOP@
+GL_GNULIB_INET_PTON = @GL_GNULIB_INET_PTON@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_ISFINITE = @GL_GNULIB_ISFINITE@
+GL_GNULIB_ISINF = @GL_GNULIB_ISINF@
+GL_GNULIB_ISNAN = @GL_GNULIB_ISNAN@
+GL_GNULIB_ISNAND = @GL_GNULIB_ISNAND@
+GL_GNULIB_ISNANF = @GL_GNULIB_ISNANF@
+GL_GNULIB_ISNANL = @GL_GNULIB_ISNANL@
+GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@
+GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@
+GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@
+GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LDEXPF = @GL_GNULIB_LDEXPF@
+GL_GNULIB_LDEXPL = @GL_GNULIB_LDEXPL@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@
+GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@
+GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LOG = @GL_GNULIB_LOG@
+GL_GNULIB_LOG10 = @GL_GNULIB_LOG10@
+GL_GNULIB_LOG10F = @GL_GNULIB_LOG10F@
+GL_GNULIB_LOG10L = @GL_GNULIB_LOG10L@
+GL_GNULIB_LOG1P = @GL_GNULIB_LOG1P@
+GL_GNULIB_LOG1PF = @GL_GNULIB_LOG1PF@
+GL_GNULIB_LOG1PL = @GL_GNULIB_LOG1PL@
+GL_GNULIB_LOG2 = @GL_GNULIB_LOG2@
+GL_GNULIB_LOG2F = @GL_GNULIB_LOG2F@
+GL_GNULIB_LOG2L = @GL_GNULIB_LOG2L@
+GL_GNULIB_LOGB = @GL_GNULIB_LOGB@
+GL_GNULIB_LOGBF = @GL_GNULIB_LOGBF@
+GL_GNULIB_LOGBL = @GL_GNULIB_LOGBL@
+GL_GNULIB_LOGF = @GL_GNULIB_LOGF@
+GL_GNULIB_LOGL = @GL_GNULIB_LOGL@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@
+GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_J0 = @GL_GNULIB_MDA_J0@
+GL_GNULIB_MDA_J1 = @GL_GNULIB_MDA_J1@
+GL_GNULIB_MDA_JN = @GL_GNULIB_MDA_JN@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MDA_Y0 = @GL_GNULIB_MDA_Y0@
+GL_GNULIB_MDA_Y1 = @GL_GNULIB_MDA_Y1@
+GL_GNULIB_MDA_YN = @GL_GNULIB_MDA_YN@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_MODF = @GL_GNULIB_MODF@
+GL_GNULIB_MODFF = @GL_GNULIB_MODFF@
+GL_GNULIB_MODFL = @GL_GNULIB_MODFL@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_POWF = @GL_GNULIB_POWF@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_RECV = @GL_GNULIB_RECV@
+GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@
+GL_GNULIB_REMAINDER = @GL_GNULIB_REMAINDER@
+GL_GNULIB_REMAINDERF = @GL_GNULIB_REMAINDERF@
+GL_GNULIB_REMAINDERL = @GL_GNULIB_REMAINDERL@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_RINT = @GL_GNULIB_RINT@
+GL_GNULIB_RINTF = @GL_GNULIB_RINTF@
+GL_GNULIB_RINTL = @GL_GNULIB_RINTL@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_ROUND = @GL_GNULIB_ROUND@
+GL_GNULIB_ROUNDF = @GL_GNULIB_ROUNDF@
+GL_GNULIB_ROUNDL = @GL_GNULIB_ROUNDL@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SEND = @GL_GNULIB_SEND@
+GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@
+GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@
+GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@
+GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SIGNBIT = @GL_GNULIB_SIGNBIT@
+GL_GNULIB_SINF = @GL_GNULIB_SINF@
+GL_GNULIB_SINHF = @GL_GNULIB_SINHF@
+GL_GNULIB_SINL = @GL_GNULIB_SINL@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_SQRTF = @GL_GNULIB_SQRTF@
+GL_GNULIB_SQRTL = @GL_GNULIB_SQRTL@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TANF = @GL_GNULIB_TANF@
+GL_GNULIB_TANHF = @GL_GNULIB_TANHF@
+GL_GNULIB_TANL = @GL_GNULIB_TANL@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@
+GL_GNULIB_TRUNC = @GL_GNULIB_TRUNC@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TRUNCF = @GL_GNULIB_TRUNCF@
+GL_GNULIB_TRUNCL = @GL_GNULIB_TRUNCL@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@
+GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@
+GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@
+GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@
+GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@
+GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@
+GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@
+GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@
+GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@
+GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@
+GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@
+GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@
+GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@
+GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@
+GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@
+GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@
+GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@
+GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@
+GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@
+GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@
+GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@
+GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@
+GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@
+GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@
+GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@
+GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@
+GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@
+GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@
+GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@
+GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@
+GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@
+GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@
+GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@
+GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@
+GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@
+GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GREP = @GREP@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ACOSF = @HAVE_ACOSF@
+HAVE_ACOSL = @HAVE_ACOSL@
+HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ASINF = @HAVE_ASINF@
+HAVE_ASINL = @HAVE_ASINL@
+HAVE_ATAN2F = @HAVE_ATAN2F@
+HAVE_ATANF = @HAVE_ATANF@
+HAVE_ATANL = @HAVE_ATANL@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CBRT = @HAVE_CBRT@
+HAVE_CBRTF = @HAVE_CBRTF@
+HAVE_CBRTL = @HAVE_CBRTL@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_COPYSIGN = @HAVE_COPYSIGN@
+HAVE_COPYSIGNL = @HAVE_COPYSIGNL@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_COSF = @HAVE_COSF@
+HAVE_COSHF = @HAVE_COSHF@
+HAVE_COSL = @HAVE_COSL@
+HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
+HAVE_DECL_ACOSL = @HAVE_DECL_ACOSL@
+HAVE_DECL_ASINL = @HAVE_DECL_ASINL@
+HAVE_DECL_ATANL = @HAVE_DECL_ATANL@
+HAVE_DECL_CBRTF = @HAVE_DECL_CBRTF@
+HAVE_DECL_CBRTL = @HAVE_DECL_CBRTL@
+HAVE_DECL_CEILF = @HAVE_DECL_CEILF@
+HAVE_DECL_CEILL = @HAVE_DECL_CEILL@
+HAVE_DECL_COPYSIGNF = @HAVE_DECL_COPYSIGNF@
+HAVE_DECL_COSL = @HAVE_DECL_COSL@
+HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@
+HAVE_DECL_EXP2 = @HAVE_DECL_EXP2@
+HAVE_DECL_EXP2F = @HAVE_DECL_EXP2F@
+HAVE_DECL_EXP2L = @HAVE_DECL_EXP2L@
+HAVE_DECL_EXPL = @HAVE_DECL_EXPL@
+HAVE_DECL_EXPM1L = @HAVE_DECL_EXPM1L@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@
+HAVE_DECL_FCVT = @HAVE_DECL_FCVT@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+HAVE_DECL_FLOORF = @HAVE_DECL_FLOORF@
+HAVE_DECL_FLOORL = @HAVE_DECL_FLOORL@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_FREEADDRINFO = @HAVE_DECL_FREEADDRINFO@
+HAVE_DECL_FREXPL = @HAVE_DECL_FREXPL@
+HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@
+HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@
+HAVE_DECL_GAI_STRERROR = @HAVE_DECL_GAI_STRERROR@
+HAVE_DECL_GCVT = @HAVE_DECL_GCVT@
+HAVE_DECL_GETADDRINFO = @HAVE_DECL_GETADDRINFO@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_GETNAMEINFO = @HAVE_DECL_GETNAMEINFO@
+HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@
+HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@
+HAVE_DECL_LDEXPL = @HAVE_DECL_LDEXPL@
+HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@
+HAVE_DECL_LOG10L = @HAVE_DECL_LOG10L@
+HAVE_DECL_LOG2 = @HAVE_DECL_LOG2@
+HAVE_DECL_LOG2F = @HAVE_DECL_LOG2F@
+HAVE_DECL_LOG2L = @HAVE_DECL_LOG2L@
+HAVE_DECL_LOGB = @HAVE_DECL_LOGB@
+HAVE_DECL_LOGL = @HAVE_DECL_LOGL@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_REMAINDER = @HAVE_DECL_REMAINDER@
+HAVE_DECL_REMAINDERL = @HAVE_DECL_REMAINDERL@
+HAVE_DECL_RINTF = @HAVE_DECL_RINTF@
+HAVE_DECL_ROUND = @HAVE_DECL_ROUND@
+HAVE_DECL_ROUNDF = @HAVE_DECL_ROUNDF@
+HAVE_DECL_ROUNDL = @HAVE_DECL_ROUNDL@
+HAVE_DECL_SETENV = @HAVE_DECL_SETENV@
+HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@
+HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@
+HAVE_DECL_SINL = @HAVE_DECL_SINL@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_SQRTL = @HAVE_DECL_SQRTL@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_TANL = @HAVE_DECL_TANL@
+HAVE_DECL_TRUNC = @HAVE_DECL_TRUNC@
+HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@
+HAVE_DECL_TRUNCF = @HAVE_DECL_TRUNCF@
+HAVE_DECL_TRUNCL = @HAVE_DECL_TRUNCL@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCSDUP = @HAVE_DECL_WCSDUP@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_EXECVPE = @HAVE_EXECVPE@
+HAVE_EXPF = @HAVE_EXPF@
+HAVE_EXPL = @HAVE_EXPL@
+HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@
+HAVE_EXPM1 = @HAVE_EXPM1@
+HAVE_EXPM1F = @HAVE_EXPM1F@
+HAVE_FABSF = @HAVE_FABSF@
+HAVE_FABSL = @HAVE_FABSL@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHDIR = @HAVE_FCHDIR@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDATASYNC = @HAVE_FDATASYNC@
+HAVE_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFS = @HAVE_FFS@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+HAVE_FMA = @HAVE_FMA@
+HAVE_FMAF = @HAVE_FMAF@
+HAVE_FMAL = @HAVE_FMAL@
+HAVE_FMODF = @HAVE_FMODF@
+HAVE_FMODL = @HAVE_FMODL@
+HAVE_FREELOCALE = @HAVE_FREELOCALE@
+HAVE_FREXPF = @HAVE_FREXPF@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETENTROPY = @HAVE_GETENTROPY@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETPASS = @HAVE_GETPASS@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETUMASK = @HAVE_GETUMASK@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_HYPOTF = @HAVE_HYPOTF@
+HAVE_HYPOTL = @HAVE_HYPOTL@
+HAVE_ILOGB = @HAVE_ILOGB@
+HAVE_ILOGBF = @HAVE_ILOGBF@
+HAVE_ILOGBL = @HAVE_ILOGBL@
+HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@
+HAVE_INITSTATE = @HAVE_INITSTATE@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISNAND = @HAVE_ISNAND@
+HAVE_ISNANF = @HAVE_ISNANF@
+HAVE_ISNANL = @HAVE_ISNANL@
+HAVE_ISWBLANK = @HAVE_ISWBLANK@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@
+HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@
+HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@
+HAVE_LANGINFO_H = @HAVE_LANGINFO_H@
+HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@
+HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LDEXPF = @HAVE_LDEXPF@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LOG10F = @HAVE_LOG10F@
+HAVE_LOG10L = @HAVE_LOG10L@
+HAVE_LOG1P = @HAVE_LOG1P@
+HAVE_LOG1PF = @HAVE_LOG1PF@
+HAVE_LOG1PL = @HAVE_LOG1PL@
+HAVE_LOGBF = @HAVE_LOGBF@
+HAVE_LOGBL = @HAVE_LOGBL@
+HAVE_LOGF = @HAVE_LOGF@
+HAVE_LOGL = @HAVE_LOGL@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMP = @HAVE_MKSTEMP@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_MODFF = @HAVE_MODFF@
+HAVE_MODFL = @HAVE_MODFL@
+HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@
+HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NETDB_H = @HAVE_NETDB_H@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+HAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@
+HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@
+HAVE_POWF = @HAVE_POWF@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_PTSNAME = @HAVE_PTSNAME@
+HAVE_PTSNAME_R = @HAVE_PTSNAME_R@
+HAVE_PWRITE = @HAVE_PWRITE@
+HAVE_QSORT_R = @HAVE_QSORT_R@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_REMAINDER = @HAVE_REMAINDER@
+HAVE_REMAINDERF = @HAVE_REMAINDERF@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RINT = @HAVE_RINT@
+HAVE_RINTL = @HAVE_RINTL@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
+HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@
+HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SINF = @HAVE_SINF@
+HAVE_SINHF = @HAVE_SINHF@
+HAVE_SINL = @HAVE_SINL@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_SQRTF = @HAVE_SQRTF@
+HAVE_SQRTL = @HAVE_SQRTL@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@
+HAVE_STRINGS_H = @HAVE_STRINGS_H@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
+HAVE_STRTOLD = @HAVE_STRTOLD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_ADDRINFO = @HAVE_STRUCT_ADDRINFO@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@
+HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@
+HAVE_TANF = @HAVE_TANF@
+HAVE_TANHF = @HAVE_TANHF@
+HAVE_TANL = @HAVE_TANL@
+HAVE_TIMEGM = @HAVE_TIMEGM@
+HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@
+HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@
+HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNLOCKPT = @HAVE_UNLOCKPT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCPCPY = @HAVE_WCPCPY@
+HAVE_WCPNCPY = @HAVE_WCPNCPY@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSCASECMP = @HAVE_WCSCASECMP@
+HAVE_WCSCAT = @HAVE_WCSCAT@
+HAVE_WCSCHR = @HAVE_WCSCHR@
+HAVE_WCSCMP = @HAVE_WCSCMP@
+HAVE_WCSCOLL = @HAVE_WCSCOLL@
+HAVE_WCSCPY = @HAVE_WCSCPY@
+HAVE_WCSCSPN = @HAVE_WCSCSPN@
+HAVE_WCSDUP = @HAVE_WCSDUP@
+HAVE_WCSFTIME = @HAVE_WCSFTIME@
+HAVE_WCSLEN = @HAVE_WCSLEN@
+HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@
+HAVE_WCSNCAT = @HAVE_WCSNCAT@
+HAVE_WCSNCMP = @HAVE_WCSNCMP@
+HAVE_WCSNCPY = @HAVE_WCSNCPY@
+HAVE_WCSNLEN = @HAVE_WCSNLEN@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSPBRK = @HAVE_WCSPBRK@
+HAVE_WCSRCHR = @HAVE_WCSRCHR@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCSSPN = @HAVE_WCSSPN@
+HAVE_WCSSTR = @HAVE_WCSSTR@
+HAVE_WCSTOK = @HAVE_WCSTOK@
+HAVE_WCSWIDTH = @HAVE_WCSWIDTH@
+HAVE_WCSXFRM = @HAVE_WCSXFRM@
+HAVE_WCTRANS_T = @HAVE_WCTRANS_T@
+HAVE_WCTYPE_H = @HAVE_WCTYPE_H@
+HAVE_WCTYPE_T = @HAVE_WCTYPE_T@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE_WMEMCHR = @HAVE_WMEMCHR@
+HAVE_WMEMCMP = @HAVE_WMEMCMP@
+HAVE_WMEMCPY = @HAVE_WMEMCPY@
+HAVE_WMEMMOVE = @HAVE_WMEMMOVE@
+HAVE_WMEMPCPY = @HAVE_WMEMPCPY@
+HAVE_WMEMSET = @HAVE_WMEMSET@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE_XLOCALE_H = @HAVE_XLOCALE_H@
+HAVE__EXIT = @HAVE__EXIT@
+HOSTENT_LIB = @HOSTENT_LIB@
+HOSTNAME = @HOSTNAME@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INET_NTOP_LIB = @INET_NTOP_LIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRBINCLUDE = @KRBINCLUDE@
+LD = @LD@
+LDAPINCLUDE = @LDAPINCLUDE@
+LDAPLIBS = @LDAPLIBS@
+LDFLAGS = @LDFLAGS@
+LIBCURL = @LIBCURL@
+LIBCURLCFLAGS = @LIBCURLCFLAGS@
+LIBCURLINCLUDE = @LIBCURLINCLUDE@
+LIBCURLLIBS = @LIBCURLLIBS@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@
+LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPMULTITHREAD = @LIBPMULTITHREAD@
+LIBPTHREAD = @LIBPTHREAD@
+# gettext docs say to use LDADD, but per module_LDADD override
+LIBS = @LTLIBINTL@ @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSTDTHREAD = @LIBSTDTHREAD@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIB_CRYPTO = @LIB_CRYPTO@
+LIB_HARD_LOCALE = @LIB_HARD_LOCALE@
+LIB_MBRTOWC = @LIB_MBRTOWC@
+LIB_NL_LANGINFO = @LIB_NL_LANGINFO@
+LIB_SCHED_YIELD = @LIB_SCHED_YIELD@
+LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@
+LIMITS_H = @LIMITS_H@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@
+LOCALE_FR = @LOCALE_FR@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATHLIBS = @MATHLIBS@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
+MYSQLCFLAGS = @MYSQLCFLAGS@
+MYSQLINCLUDE = @MYSQLINCLUDE@
+MYSQLLIBS = @MYSQLLIBS@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@
+NEXT_ASSERT_H = @NEXT_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_ASSERT_H = @NEXT_AS_FIRST_DIRECTIVE_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@
+NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@
+NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
+NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@
+NEXT_AS_FIRST_DIRECTIVE_MATH_H = @NEXT_AS_FIRST_DIRECTIVE_MATH_H@
+NEXT_AS_FIRST_DIRECTIVE_NETDB_H = @NEXT_AS_FIRST_DIRECTIVE_NETDB_H@
+NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_H@
+NEXT_LIMITS_H = @NEXT_LIMITS_H@
+NEXT_LOCALE_H = @NEXT_LOCALE_H@
+NEXT_MATH_H = @NEXT_MATH_H@
+NEXT_NETDB_H = @NEXT_NETDB_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRINGS_H = @NEXT_STRINGS_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@
+NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NEXT_WCTYPE_H = @NEXT_WCTYPE_H@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NP_RELEASE = @NP_RELEASE@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PATH_TO_APTGET = @PATH_TO_APTGET@
+PATH_TO_DIG = @PATH_TO_DIG@
+PATH_TO_ENV = @PATH_TO_ENV@
+PATH_TO_FPING = @PATH_TO_FPING@
+PATH_TO_FPING6 = @PATH_TO_FPING6@
+PATH_TO_LMSTAT = @PATH_TO_LMSTAT@
+PATH_TO_LSPS = @PATH_TO_LSPS@
+PATH_TO_MAILQ = @PATH_TO_MAILQ@
+PATH_TO_NSLOOKUP = @PATH_TO_NSLOOKUP@
+PATH_TO_PING = @PATH_TO_PING@
+PATH_TO_PING6 = @PATH_TO_PING6@
+PATH_TO_PS = @PATH_TO_PS@
+PATH_TO_QMAIL_QSTAT = @PATH_TO_QMAIL_QSTAT@
+PATH_TO_QSTAT = @PATH_TO_QSTAT@
+PATH_TO_QUAKESTAT = @PATH_TO_QUAKESTAT@
+PATH_TO_RPCINFO = @PATH_TO_RPCINFO@
+PATH_TO_SMBCLIENT = @PATH_TO_SMBCLIENT@
+PATH_TO_SNMPGET = @PATH_TO_SNMPGET@
+PATH_TO_SNMPGETNEXT = @PATH_TO_SNMPGETNEXT@
+PATH_TO_SSH = @PATH_TO_SSH@
+PATH_TO_SUDO = @PATH_TO_SUDO@
+PATH_TO_SWAP = @PATH_TO_SWAP@
+PATH_TO_SWAPINFO = @PATH_TO_SWAPINFO@
+PATH_TO_UPTIME = @PATH_TO_UPTIME@
+PATH_TO_WHO = @PATH_TO_WHO@
+PERL = @PERL@
+PERLMODS_DIR = @PERLMODS_DIR@
+PGINCLUDE = @PGINCLUDE@
+PGLIBS = @PGLIBS@
+PKGCONFIG = @PKGCONFIG@
+PKG_ARCH = @PKG_ARCH@
+PLUGIN_TEST = @PLUGIN_TEST@
+POSUB = @POSUB@
+POW_LIB = @POW_LIB@
+PRAGMA_COLUMNS = @PRAGMA_COLUMNS@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PST3CFLAGS = @PST3CFLAGS@
+PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RADIUSLIBS = @RADIUSLIBS@
+RANLIB = @RANLIB@
+RELEASE = @RELEASE@
+REPLACE_ACCESS = @REPLACE_ACCESS@
+REPLACE_ACOSF = @REPLACE_ACOSF@
+REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
+REPLACE_ASINF = @REPLACE_ASINF@
+REPLACE_ATAN2F = @REPLACE_ATAN2F@
+REPLACE_ATANF = @REPLACE_ATANF@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@
+REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CBRTF = @REPLACE_CBRTF@
+REPLACE_CBRTL = @REPLACE_CBRTL@
+REPLACE_CEIL = @REPLACE_CEIL@
+REPLACE_CEILF = @REPLACE_CEILF@
+REPLACE_CEILL = @REPLACE_CEILL@
+REPLACE_CHMOD = @REPLACE_CHMOD@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@
+REPLACE_COSF = @REPLACE_COSF@
+REPLACE_COSHF = @REPLACE_COSHF@
+REPLACE_CREAT = @REPLACE_CREAT@
+REPLACE_CTIME = @REPLACE_CTIME@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_EXECL = @REPLACE_EXECL@
+REPLACE_EXECLE = @REPLACE_EXECLE@
+REPLACE_EXECLP = @REPLACE_EXECLP@
+REPLACE_EXECV = @REPLACE_EXECV@
+REPLACE_EXECVE = @REPLACE_EXECVE@
+REPLACE_EXECVP = @REPLACE_EXECVP@
+REPLACE_EXECVPE = @REPLACE_EXECVPE@
+REPLACE_EXP2 = @REPLACE_EXP2@
+REPLACE_EXP2L = @REPLACE_EXP2L@
+REPLACE_EXPF = @REPLACE_EXPF@
+REPLACE_EXPL = @REPLACE_EXPL@
+REPLACE_EXPM1 = @REPLACE_EXPM1@
+REPLACE_EXPM1F = @REPLACE_EXPM1F@
+REPLACE_EXPM1L = @REPLACE_EXPM1L@
+REPLACE_FABSL = @REPLACE_FABSL@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
+REPLACE_FCHMODAT = @REPLACE_FCHMODAT@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FFSLL = @REPLACE_FFSLL@
+REPLACE_FLOOR = @REPLACE_FLOOR@
+REPLACE_FLOORF = @REPLACE_FLOORF@
+REPLACE_FLOORL = @REPLACE_FLOORL@
+REPLACE_FMA = @REPLACE_FMA@
+REPLACE_FMAF = @REPLACE_FMAF@
+REPLACE_FMAL = @REPLACE_FMAL@
+REPLACE_FMOD = @REPLACE_FMOD@
+REPLACE_FMODF = @REPLACE_FMODF@
+REPLACE_FMODL = @REPLACE_FMODL@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREE = @REPLACE_FREE@
+REPLACE_FREELOCALE = @REPLACE_FREELOCALE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FREXP = @REPLACE_FREXP@
+REPLACE_FREXPF = @REPLACE_FREXPF@
+REPLACE_FREXPL = @REPLACE_FREXPL@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GAI_STRERROR = @REPLACE_GAI_STRERROR@
+REPLACE_GETADDRINFO = @REPLACE_GETADDRINFO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@
+REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETPASS = @REPLACE_GETPASS@
+REPLACE_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@
+REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_HUGE_VAL = @REPLACE_HUGE_VAL@
+REPLACE_HYPOT = @REPLACE_HYPOT@
+REPLACE_HYPOTF = @REPLACE_HYPOTF@
+REPLACE_HYPOTL = @REPLACE_HYPOTL@
+REPLACE_ILOGB = @REPLACE_ILOGB@
+REPLACE_ILOGBF = @REPLACE_ILOGBF@
+REPLACE_ILOGBL = @REPLACE_ILOGBL@
+REPLACE_INET_NTOP = @REPLACE_INET_NTOP@
+REPLACE_INET_PTON = @REPLACE_INET_PTON@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ISFINITE = @REPLACE_ISFINITE@
+REPLACE_ISINF = @REPLACE_ISINF@
+REPLACE_ISNAN = @REPLACE_ISNAN@
+REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@
+REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@
+REPLACE_ITOLD = @REPLACE_ITOLD@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LDEXPL = @REPLACE_LDEXPL@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALECONV = @REPLACE_LOCALECONV@
+REPLACE_LOCALTIME = @REPLACE_LOCALTIME@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LOG = @REPLACE_LOG@
+REPLACE_LOG10 = @REPLACE_LOG10@
+REPLACE_LOG10F = @REPLACE_LOG10F@
+REPLACE_LOG10L = @REPLACE_LOG10L@
+REPLACE_LOG1P = @REPLACE_LOG1P@
+REPLACE_LOG1PF = @REPLACE_LOG1PF@
+REPLACE_LOG1PL = @REPLACE_LOG1PL@
+REPLACE_LOG2 = @REPLACE_LOG2@
+REPLACE_LOG2F = @REPLACE_LOG2F@
+REPLACE_LOG2L = @REPLACE_LOG2L@
+REPLACE_LOGB = @REPLACE_LOGB@
+REPLACE_LOGBF = @REPLACE_LOGBF@
+REPLACE_LOGBL = @REPLACE_LOGBL@
+REPLACE_LOGF = @REPLACE_LOGF@
+REPLACE_LOGL = @REPLACE_LOGL@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MALLOC_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@
+REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MBTOWC = @REPLACE_MBTOWC@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKNODAT = @REPLACE_MKNODAT@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_MODF = @REPLACE_MODF@
+REPLACE_MODFF = @REPLACE_MODFF@
+REPLACE_MODFL = @REPLACE_MODFL@
+REPLACE_NAN = @REPLACE_NAN@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@
+REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PTSNAME = @REPLACE_PTSNAME@
+REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_PWRITE = @REPLACE_PWRITE@
+REPLACE_QSORT_R = @REPLACE_QSORT_R@
+REPLACE_RANDOM = @REPLACE_RANDOM@
+REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
+REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@
+REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMAINDER = @REPLACE_REMAINDER@
+REPLACE_REMAINDERF = @REPLACE_REMAINDERF@
+REPLACE_REMAINDERL = @REPLACE_REMAINDERL@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RINTL = @REPLACE_RINTL@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_ROUND = @REPLACE_ROUND@
+REPLACE_ROUNDF = @REPLACE_ROUNDF@
+REPLACE_ROUNDL = @REPLACE_ROUNDL@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
+REPLACE_SIGNBIT = @REPLACE_SIGNBIT@
+REPLACE_SIGNBIT_USING_BUILTINS = @REPLACE_SIGNBIT_USING_BUILTINS@
+REPLACE_SINF = @REPLACE_SINF@
+REPLACE_SINHF = @REPLACE_SINHF@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_SQRTF = @REPLACE_SQRTF@
+REPLACE_SQRTL = @REPLACE_SQRTL@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STPNCPY = @REPLACE_STPNCPY@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@
+REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
+REPLACE_STRFTIME = @REPLACE_STRFTIME@
+REPLACE_STRNCAT = @REPLACE_STRNCAT@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRNLEN = @REPLACE_STRNLEN@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
+REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
+REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@
+REPLACE_TANF = @REPLACE_TANF@
+REPLACE_TANHF = @REPLACE_TANHF@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_TMPFILE = @REPLACE_TMPFILE@
+REPLACE_TOWLOWER = @REPLACE_TOWLOWER@
+REPLACE_TRUNC = @REPLACE_TRUNC@
+REPLACE_TRUNCATE = @REPLACE_TRUNCATE@
+REPLACE_TRUNCF = @REPLACE_TRUNCF@
+REPLACE_TRUNCL = @REPLACE_TRUNCL@
+REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_TZSET = @REPLACE_TZSET@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSFTIME = @REPLACE_WCSFTIME@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSTOK = @REPLACE_WCSTOK@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+REV_DATESTAMP = @REV_DATESTAMP@
+REV_TIMESTAMP = @REV_TIMESTAMP@
+SCRIPT_TEST = @SCRIPT_TEST@
+SED = @SED@
+SERVENT_LIB = @SERVENT_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SOCKETLIBS = @SOCKETLIBS@
+SSLINCLUDE = @SSLINCLUDE@
+SSLLIBS = @SSLLIBS@
+STDALIGN_H = @STDALIGN_H@
+STDCKDINT_H = @STDCKDINT_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SUPPORT = @SUPPORT@
+SYSTEMDINCLUDE = @SYSTEMDINCLUDE@
+SYSTEMDLIBS = @SYSTEMDLIBS@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@
+UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+URIPARSER = @URIPARSER@
+URIPARSERCFLAGS = @URIPARSERCFLAGS@
+URIPARSERINCLUDE = @URIPARSERINCLUDE@
+URIPARSERLIBS = @URIPARSERLIBS@
+URIPARSER_CPPFLAGS = @URIPARSER_CPPFLAGS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARRANTY = @WARRANTY@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@
+WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@
+WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@
+WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+WTSAPI32LIBS = @WTSAPI32LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+check_tcp_ssl = @check_tcp_ssl@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJDEPS = @gl_LIBOBJDEPS@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+gltests_WITNESS = @gltests_WITNESS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = $(datadir)/locale
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+np_mysql_config = @np_mysql_config@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+with_trusted_path = @with_trusted_path@
+@RELEASE_PRESENT_TRUE@NP_VERSION = @NP_RELEASE@
+AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"'
+AM_CPPFLAGS = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl \
+ @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@
+
+check_tcp_programs = check_ftp check_imap check_nntp check_pop \
+ check_udp check_clamd @check_tcp_ssl@
+
+SUBDIRS = picohttpparser
+EXTRA_DIST = t tests
+PLUGINHDRS = common.h
+noinst_LIBRARIES = libnpcommon.a
+libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
+ popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
+
+BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
+NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
+NETLIBS = $(NETOBJS) $(SOCKETLIBS)
+SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
+TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
+TESTS = @PLUGIN_TEST@
+
+##############################################################################
+# the actual targets
+check_apt_LDADD = $(BASEOBJS)
+check_cluster_LDADD = $(BASEOBJS)
+check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
+check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
+check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
+check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
+check_dig_LDADD = $(NETLIBS)
+check_disk_LDADD = $(BASEOBJS)
+check_dns_LDADD = $(NETLIBS)
+check_dummy_LDADD = $(BASEOBJS)
+check_fping_LDADD = $(NETLIBS)
+check_game_LDADD = $(BASEOBJS)
+check_http_LDADD = $(SSLOBJS)
+check_hpjd_LDADD = $(NETLIBS)
+check_ldap_LDADD = $(NETLIBS) $(LDAPLIBS)
+check_load_LDADD = $(BASEOBJS)
+check_mrtg_LDADD = $(BASEOBJS)
+check_mrtgtraf_LDADD = $(BASEOBJS)
+check_mysql_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
+check_mysql_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
+check_mysql_LDADD = $(NETLIBS) $(MYSQLLIBS)
+check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS)
+check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
+check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
+check_nagios_LDADD = $(BASEOBJS)
+check_nt_LDADD = $(NETLIBS)
+check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
+check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
+check_nwstat_LDADD = $(NETLIBS)
+check_overcr_LDADD = $(NETLIBS)
+check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
+check_ping_LDADD = $(NETLIBS)
+check_procs_LDADD = $(BASEOBJS)
+check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
+check_real_LDADD = $(NETLIBS)
+check_snmp_LDADD = $(BASEOBJS)
+check_smtp_LDADD = $(SSLOBJS)
+check_ssh_LDADD = $(NETLIBS)
+check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
+check_tcp_LDADD = $(SSLOBJS)
+check_time_LDADD = $(NETLIBS)
+check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS)
+check_ups_LDADD = $(NETLIBS)
+check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS) \
+ $(am__append_1)
+check_by_ssh_LDADD = $(NETLIBS)
+check_ide_smart_LDADD = $(BASEOBJS)
+negate_LDADD = $(BASEOBJS)
+urlize_LDADD = $(BASEOBJS)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libnpcommon.a: $(libnpcommon_a_OBJECTS) $(libnpcommon_a_DEPENDENCIES) $(EXTRA_libnpcommon_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libnpcommon.a
+ $(AM_V_AR)$(libnpcommon_a_AR) libnpcommon.a $(libnpcommon_a_OBJECTS) $(libnpcommon_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libnpcommon.a
+
+check_apt$(EXEEXT): $(check_apt_OBJECTS) $(check_apt_DEPENDENCIES) $(EXTRA_check_apt_DEPENDENCIES)
+ @rm -f check_apt$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_apt_OBJECTS) $(check_apt_LDADD) $(LIBS)
+
+check_by_ssh$(EXEEXT): $(check_by_ssh_OBJECTS) $(check_by_ssh_DEPENDENCIES) $(EXTRA_check_by_ssh_DEPENDENCIES)
+ @rm -f check_by_ssh$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_by_ssh_OBJECTS) $(check_by_ssh_LDADD) $(LIBS)
+
+check_cluster$(EXEEXT): $(check_cluster_OBJECTS) $(check_cluster_DEPENDENCIES) $(EXTRA_check_cluster_DEPENDENCIES)
+ @rm -f check_cluster$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_cluster_OBJECTS) $(check_cluster_LDADD) $(LIBS)
+
+check_curl$(EXEEXT): $(check_curl_OBJECTS) $(check_curl_DEPENDENCIES) $(EXTRA_check_curl_DEPENDENCIES)
+ @rm -f check_curl$(EXEEXT)
+ $(AM_V_CCLD)$(check_curl_LINK) $(check_curl_OBJECTS) $(check_curl_LDADD) $(LIBS)
+
+check_dbi$(EXEEXT): $(check_dbi_OBJECTS) $(check_dbi_DEPENDENCIES) $(EXTRA_check_dbi_DEPENDENCIES)
+ @rm -f check_dbi$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_dbi_OBJECTS) $(check_dbi_LDADD) $(LIBS)
+
+check_dig$(EXEEXT): $(check_dig_OBJECTS) $(check_dig_DEPENDENCIES) $(EXTRA_check_dig_DEPENDENCIES)
+ @rm -f check_dig$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_dig_OBJECTS) $(check_dig_LDADD) $(LIBS)
+
+check_disk$(EXEEXT): $(check_disk_OBJECTS) $(check_disk_DEPENDENCIES) $(EXTRA_check_disk_DEPENDENCIES)
+ @rm -f check_disk$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_disk_OBJECTS) $(check_disk_LDADD) $(LIBS)
+
+check_dns$(EXEEXT): $(check_dns_OBJECTS) $(check_dns_DEPENDENCIES) $(EXTRA_check_dns_DEPENDENCIES)
+ @rm -f check_dns$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_dns_OBJECTS) $(check_dns_LDADD) $(LIBS)
+
+check_dummy$(EXEEXT): $(check_dummy_OBJECTS) $(check_dummy_DEPENDENCIES) $(EXTRA_check_dummy_DEPENDENCIES)
+ @rm -f check_dummy$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_dummy_OBJECTS) $(check_dummy_LDADD) $(LIBS)
+
+check_fping$(EXEEXT): $(check_fping_OBJECTS) $(check_fping_DEPENDENCIES) $(EXTRA_check_fping_DEPENDENCIES)
+ @rm -f check_fping$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_fping_OBJECTS) $(check_fping_LDADD) $(LIBS)
+
+check_game$(EXEEXT): $(check_game_OBJECTS) $(check_game_DEPENDENCIES) $(EXTRA_check_game_DEPENDENCIES)
+ @rm -f check_game$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_game_OBJECTS) $(check_game_LDADD) $(LIBS)
+
+check_hpjd$(EXEEXT): $(check_hpjd_OBJECTS) $(check_hpjd_DEPENDENCIES) $(EXTRA_check_hpjd_DEPENDENCIES)
+ @rm -f check_hpjd$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_hpjd_OBJECTS) $(check_hpjd_LDADD) $(LIBS)
+
+check_http$(EXEEXT): $(check_http_OBJECTS) $(check_http_DEPENDENCIES) $(EXTRA_check_http_DEPENDENCIES)
+ @rm -f check_http$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_http_OBJECTS) $(check_http_LDADD) $(LIBS)
+
+check_ide_smart$(EXEEXT): $(check_ide_smart_OBJECTS) $(check_ide_smart_DEPENDENCIES) $(EXTRA_check_ide_smart_DEPENDENCIES)
+ @rm -f check_ide_smart$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ide_smart_OBJECTS) $(check_ide_smart_LDADD) $(LIBS)
+
+check_ldap$(EXEEXT): $(check_ldap_OBJECTS) $(check_ldap_DEPENDENCIES) $(EXTRA_check_ldap_DEPENDENCIES)
+ @rm -f check_ldap$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ldap_OBJECTS) $(check_ldap_LDADD) $(LIBS)
+
+check_load$(EXEEXT): $(check_load_OBJECTS) $(check_load_DEPENDENCIES) $(EXTRA_check_load_DEPENDENCIES)
+ @rm -f check_load$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_load_OBJECTS) $(check_load_LDADD) $(LIBS)
+
+check_mrtg$(EXEEXT): $(check_mrtg_OBJECTS) $(check_mrtg_DEPENDENCIES) $(EXTRA_check_mrtg_DEPENDENCIES)
+ @rm -f check_mrtg$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_mrtg_OBJECTS) $(check_mrtg_LDADD) $(LIBS)
+
+check_mrtgtraf$(EXEEXT): $(check_mrtgtraf_OBJECTS) $(check_mrtgtraf_DEPENDENCIES) $(EXTRA_check_mrtgtraf_DEPENDENCIES)
+ @rm -f check_mrtgtraf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_mrtgtraf_OBJECTS) $(check_mrtgtraf_LDADD) $(LIBS)
+
+check_mysql$(EXEEXT): $(check_mysql_OBJECTS) $(check_mysql_DEPENDENCIES) $(EXTRA_check_mysql_DEPENDENCIES)
+ @rm -f check_mysql$(EXEEXT)
+ $(AM_V_CCLD)$(check_mysql_LINK) $(check_mysql_OBJECTS) $(check_mysql_LDADD) $(LIBS)
+
+check_mysql_query$(EXEEXT): $(check_mysql_query_OBJECTS) $(check_mysql_query_DEPENDENCIES) $(EXTRA_check_mysql_query_DEPENDENCIES)
+ @rm -f check_mysql_query$(EXEEXT)
+ $(AM_V_CCLD)$(check_mysql_query_LINK) $(check_mysql_query_OBJECTS) $(check_mysql_query_LDADD) $(LIBS)
+
+check_nagios$(EXEEXT): $(check_nagios_OBJECTS) $(check_nagios_DEPENDENCIES) $(EXTRA_check_nagios_DEPENDENCIES)
+ @rm -f check_nagios$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_nagios_OBJECTS) $(check_nagios_LDADD) $(LIBS)
+
+check_nt$(EXEEXT): $(check_nt_OBJECTS) $(check_nt_DEPENDENCIES) $(EXTRA_check_nt_DEPENDENCIES)
+ @rm -f check_nt$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_nt_OBJECTS) $(check_nt_LDADD) $(LIBS)
+
+check_ntp$(EXEEXT): $(check_ntp_OBJECTS) $(check_ntp_DEPENDENCIES) $(EXTRA_check_ntp_DEPENDENCIES)
+ @rm -f check_ntp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ntp_OBJECTS) $(check_ntp_LDADD) $(LIBS)
+
+check_ntp_peer$(EXEEXT): $(check_ntp_peer_OBJECTS) $(check_ntp_peer_DEPENDENCIES) $(EXTRA_check_ntp_peer_DEPENDENCIES)
+ @rm -f check_ntp_peer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ntp_peer_OBJECTS) $(check_ntp_peer_LDADD) $(LIBS)
+
+check_ntp_time$(EXEEXT): $(check_ntp_time_OBJECTS) $(check_ntp_time_DEPENDENCIES) $(EXTRA_check_ntp_time_DEPENDENCIES)
+ @rm -f check_ntp_time$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ntp_time_OBJECTS) $(check_ntp_time_LDADD) $(LIBS)
+
+check_nwstat$(EXEEXT): $(check_nwstat_OBJECTS) $(check_nwstat_DEPENDENCIES) $(EXTRA_check_nwstat_DEPENDENCIES)
+ @rm -f check_nwstat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_nwstat_OBJECTS) $(check_nwstat_LDADD) $(LIBS)
+
+check_overcr$(EXEEXT): $(check_overcr_OBJECTS) $(check_overcr_DEPENDENCIES) $(EXTRA_check_overcr_DEPENDENCIES)
+ @rm -f check_overcr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_overcr_OBJECTS) $(check_overcr_LDADD) $(LIBS)
+
+check_pgsql$(EXEEXT): $(check_pgsql_OBJECTS) $(check_pgsql_DEPENDENCIES) $(EXTRA_check_pgsql_DEPENDENCIES)
+ @rm -f check_pgsql$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_pgsql_OBJECTS) $(check_pgsql_LDADD) $(LIBS)
+
+check_ping$(EXEEXT): $(check_ping_OBJECTS) $(check_ping_DEPENDENCIES) $(EXTRA_check_ping_DEPENDENCIES)
+ @rm -f check_ping$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ping_OBJECTS) $(check_ping_LDADD) $(LIBS)
+
+check_procs$(EXEEXT): $(check_procs_OBJECTS) $(check_procs_DEPENDENCIES) $(EXTRA_check_procs_DEPENDENCIES)
+ @rm -f check_procs$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_procs_OBJECTS) $(check_procs_LDADD) $(LIBS)
+
+check_radius$(EXEEXT): $(check_radius_OBJECTS) $(check_radius_DEPENDENCIES) $(EXTRA_check_radius_DEPENDENCIES)
+ @rm -f check_radius$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_radius_OBJECTS) $(check_radius_LDADD) $(LIBS)
+
+check_real$(EXEEXT): $(check_real_OBJECTS) $(check_real_DEPENDENCIES) $(EXTRA_check_real_DEPENDENCIES)
+ @rm -f check_real$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_real_OBJECTS) $(check_real_LDADD) $(LIBS)
+
+check_smtp$(EXEEXT): $(check_smtp_OBJECTS) $(check_smtp_DEPENDENCIES) $(EXTRA_check_smtp_DEPENDENCIES)
+ @rm -f check_smtp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_smtp_OBJECTS) $(check_smtp_LDADD) $(LIBS)
+
+check_snmp$(EXEEXT): $(check_snmp_OBJECTS) $(check_snmp_DEPENDENCIES) $(EXTRA_check_snmp_DEPENDENCIES)
+ @rm -f check_snmp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_snmp_OBJECTS) $(check_snmp_LDADD) $(LIBS)
+
+check_ssh$(EXEEXT): $(check_ssh_OBJECTS) $(check_ssh_DEPENDENCIES) $(EXTRA_check_ssh_DEPENDENCIES)
+ @rm -f check_ssh$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ssh_OBJECTS) $(check_ssh_LDADD) $(LIBS)
+
+check_swap$(EXEEXT): $(check_swap_OBJECTS) $(check_swap_DEPENDENCIES) $(EXTRA_check_swap_DEPENDENCIES)
+ @rm -f check_swap$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_swap_OBJECTS) $(check_swap_LDADD) $(LIBS)
+
+check_tcp$(EXEEXT): $(check_tcp_OBJECTS) $(check_tcp_DEPENDENCIES) $(EXTRA_check_tcp_DEPENDENCIES)
+ @rm -f check_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_tcp_OBJECTS) $(check_tcp_LDADD) $(LIBS)
+
+check_time$(EXEEXT): $(check_time_OBJECTS) $(check_time_DEPENDENCIES) $(EXTRA_check_time_DEPENDENCIES)
+ @rm -f check_time$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_time_OBJECTS) $(check_time_LDADD) $(LIBS)
+
+check_ups$(EXEEXT): $(check_ups_OBJECTS) $(check_ups_DEPENDENCIES) $(EXTRA_check_ups_DEPENDENCIES)
+ @rm -f check_ups$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_ups_OBJECTS) $(check_ups_LDADD) $(LIBS)
+
+check_users$(EXEEXT): $(check_users_OBJECTS) $(check_users_DEPENDENCIES) $(EXTRA_check_users_DEPENDENCIES)
+ @rm -f check_users$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(check_users_OBJECTS) $(check_users_LDADD) $(LIBS)
+
+negate$(EXEEXT): $(negate_OBJECTS) $(negate_DEPENDENCIES) $(EXTRA_negate_DEPENDENCIES)
+ @rm -f negate$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(negate_OBJECTS) $(negate_LDADD) $(LIBS)
+
+urlize$(EXEEXT): $(urlize_OBJECTS) $(urlize_DEPENDENCIES) $(EXTRA_urlize_DEPENDENCIES)
+ @rm -f urlize$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(urlize_OBJECTS) $(urlize_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_apt.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_by_ssh.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cluster.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_curl-check_curl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_dbi.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_dig.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_disk.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_dns.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_dummy.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_fping.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_game.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_hpjd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_http.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ide_smart.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ldap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_load.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_mrtg.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_mrtgtraf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_mysql-check_mysql.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_mysql_query-check_mysql_query.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_nagios.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_nt.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ntp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ntp_peer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ntp_time.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_nwstat.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_overcr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_pgsql.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ping.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_procs.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_radius.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_real.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_smtp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_snmp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ssh.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_swap.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_tcp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_time.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_ups.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_users.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/negate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netutils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/popen.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runcmd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sslutils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/urlize.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+check_curl-check_curl.o: check_curl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_curl_CPPFLAGS) $(CPPFLAGS) $(check_curl_CFLAGS) $(CFLAGS) -MT check_curl-check_curl.o -MD -MP -MF $(DEPDIR)/check_curl-check_curl.Tpo -c -o check_curl-check_curl.o `test -f 'check_curl.c' || echo '$(srcdir)/'`check_curl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_curl-check_curl.Tpo $(DEPDIR)/check_curl-check_curl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_curl.c' object='check_curl-check_curl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_curl_CPPFLAGS) $(CPPFLAGS) $(check_curl_CFLAGS) $(CFLAGS) -c -o check_curl-check_curl.o `test -f 'check_curl.c' || echo '$(srcdir)/'`check_curl.c
+
+check_curl-check_curl.obj: check_curl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_curl_CPPFLAGS) $(CPPFLAGS) $(check_curl_CFLAGS) $(CFLAGS) -MT check_curl-check_curl.obj -MD -MP -MF $(DEPDIR)/check_curl-check_curl.Tpo -c -o check_curl-check_curl.obj `if test -f 'check_curl.c'; then $(CYGPATH_W) 'check_curl.c'; else $(CYGPATH_W) '$(srcdir)/check_curl.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_curl-check_curl.Tpo $(DEPDIR)/check_curl-check_curl.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_curl.c' object='check_curl-check_curl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_curl_CPPFLAGS) $(CPPFLAGS) $(check_curl_CFLAGS) $(CFLAGS) -c -o check_curl-check_curl.obj `if test -f 'check_curl.c'; then $(CYGPATH_W) 'check_curl.c'; else $(CYGPATH_W) '$(srcdir)/check_curl.c'; fi`
+
+check_mysql-check_mysql.o: check_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_CPPFLAGS) $(CPPFLAGS) $(check_mysql_CFLAGS) $(CFLAGS) -MT check_mysql-check_mysql.o -MD -MP -MF $(DEPDIR)/check_mysql-check_mysql.Tpo -c -o check_mysql-check_mysql.o `test -f 'check_mysql.c' || echo '$(srcdir)/'`check_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_mysql-check_mysql.Tpo $(DEPDIR)/check_mysql-check_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_mysql.c' object='check_mysql-check_mysql.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_CPPFLAGS) $(CPPFLAGS) $(check_mysql_CFLAGS) $(CFLAGS) -c -o check_mysql-check_mysql.o `test -f 'check_mysql.c' || echo '$(srcdir)/'`check_mysql.c
+
+check_mysql-check_mysql.obj: check_mysql.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_CPPFLAGS) $(CPPFLAGS) $(check_mysql_CFLAGS) $(CFLAGS) -MT check_mysql-check_mysql.obj -MD -MP -MF $(DEPDIR)/check_mysql-check_mysql.Tpo -c -o check_mysql-check_mysql.obj `if test -f 'check_mysql.c'; then $(CYGPATH_W) 'check_mysql.c'; else $(CYGPATH_W) '$(srcdir)/check_mysql.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_mysql-check_mysql.Tpo $(DEPDIR)/check_mysql-check_mysql.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_mysql.c' object='check_mysql-check_mysql.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_CPPFLAGS) $(CPPFLAGS) $(check_mysql_CFLAGS) $(CFLAGS) -c -o check_mysql-check_mysql.obj `if test -f 'check_mysql.c'; then $(CYGPATH_W) 'check_mysql.c'; else $(CYGPATH_W) '$(srcdir)/check_mysql.c'; fi`
+
+check_mysql_query-check_mysql_query.o: check_mysql_query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_query_CPPFLAGS) $(CPPFLAGS) $(check_mysql_query_CFLAGS) $(CFLAGS) -MT check_mysql_query-check_mysql_query.o -MD -MP -MF $(DEPDIR)/check_mysql_query-check_mysql_query.Tpo -c -o check_mysql_query-check_mysql_query.o `test -f 'check_mysql_query.c' || echo '$(srcdir)/'`check_mysql_query.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_mysql_query-check_mysql_query.Tpo $(DEPDIR)/check_mysql_query-check_mysql_query.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_mysql_query.c' object='check_mysql_query-check_mysql_query.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_query_CPPFLAGS) $(CPPFLAGS) $(check_mysql_query_CFLAGS) $(CFLAGS) -c -o check_mysql_query-check_mysql_query.o `test -f 'check_mysql_query.c' || echo '$(srcdir)/'`check_mysql_query.c
+
+check_mysql_query-check_mysql_query.obj: check_mysql_query.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_query_CPPFLAGS) $(CPPFLAGS) $(check_mysql_query_CFLAGS) $(CFLAGS) -MT check_mysql_query-check_mysql_query.obj -MD -MP -MF $(DEPDIR)/check_mysql_query-check_mysql_query.Tpo -c -o check_mysql_query-check_mysql_query.obj `if test -f 'check_mysql_query.c'; then $(CYGPATH_W) 'check_mysql_query.c'; else $(CYGPATH_W) '$(srcdir)/check_mysql_query.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_mysql_query-check_mysql_query.Tpo $(DEPDIR)/check_mysql_query-check_mysql_query.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_mysql_query.c' object='check_mysql_query-check_mysql_query.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(check_mysql_query_CPPFLAGS) $(CPPFLAGS) $(check_mysql_query_CFLAGS) $(CFLAGS) -c -o check_mysql_query-check_mysql_query.obj `if test -f 'check_mysql_query.c'; then $(CYGPATH_W) 'check_mysql_query.c'; else $(CYGPATH_W) '$(srcdir)/check_mysql_query.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(PROGRAMS) $(LIBRARIES) all-local
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libexecdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
+ clean-local clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/check_apt.Po
+ -rm -f ./$(DEPDIR)/check_by_ssh.Po
+ -rm -f ./$(DEPDIR)/check_cluster.Po
+ -rm -f ./$(DEPDIR)/check_curl-check_curl.Po
+ -rm -f ./$(DEPDIR)/check_dbi.Po
+ -rm -f ./$(DEPDIR)/check_dig.Po
+ -rm -f ./$(DEPDIR)/check_disk.Po
+ -rm -f ./$(DEPDIR)/check_dns.Po
+ -rm -f ./$(DEPDIR)/check_dummy.Po
+ -rm -f ./$(DEPDIR)/check_fping.Po
+ -rm -f ./$(DEPDIR)/check_game.Po
+ -rm -f ./$(DEPDIR)/check_hpjd.Po
+ -rm -f ./$(DEPDIR)/check_http.Po
+ -rm -f ./$(DEPDIR)/check_ide_smart.Po
+ -rm -f ./$(DEPDIR)/check_ldap.Po
+ -rm -f ./$(DEPDIR)/check_load.Po
+ -rm -f ./$(DEPDIR)/check_mrtg.Po
+ -rm -f ./$(DEPDIR)/check_mrtgtraf.Po
+ -rm -f ./$(DEPDIR)/check_mysql-check_mysql.Po
+ -rm -f ./$(DEPDIR)/check_mysql_query-check_mysql_query.Po
+ -rm -f ./$(DEPDIR)/check_nagios.Po
+ -rm -f ./$(DEPDIR)/check_nt.Po
+ -rm -f ./$(DEPDIR)/check_ntp.Po
+ -rm -f ./$(DEPDIR)/check_ntp_peer.Po
+ -rm -f ./$(DEPDIR)/check_ntp_time.Po
+ -rm -f ./$(DEPDIR)/check_nwstat.Po
+ -rm -f ./$(DEPDIR)/check_overcr.Po
+ -rm -f ./$(DEPDIR)/check_pgsql.Po
+ -rm -f ./$(DEPDIR)/check_ping.Po
+ -rm -f ./$(DEPDIR)/check_procs.Po
+ -rm -f ./$(DEPDIR)/check_radius.Po
+ -rm -f ./$(DEPDIR)/check_real.Po
+ -rm -f ./$(DEPDIR)/check_smtp.Po
+ -rm -f ./$(DEPDIR)/check_snmp.Po
+ -rm -f ./$(DEPDIR)/check_ssh.Po
+ -rm -f ./$(DEPDIR)/check_swap.Po
+ -rm -f ./$(DEPDIR)/check_tcp.Po
+ -rm -f ./$(DEPDIR)/check_time.Po
+ -rm -f ./$(DEPDIR)/check_ups.Po
+ -rm -f ./$(DEPDIR)/check_users.Po
+ -rm -f ./$(DEPDIR)/negate.Po
+ -rm -f ./$(DEPDIR)/netutils.Po
+ -rm -f ./$(DEPDIR)/popen.Po
+ -rm -f ./$(DEPDIR)/runcmd.Po
+ -rm -f ./$(DEPDIR)/sslutils.Po
+ -rm -f ./$(DEPDIR)/urlize.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libexecPROGRAMS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/check_apt.Po
+ -rm -f ./$(DEPDIR)/check_by_ssh.Po
+ -rm -f ./$(DEPDIR)/check_cluster.Po
+ -rm -f ./$(DEPDIR)/check_curl-check_curl.Po
+ -rm -f ./$(DEPDIR)/check_dbi.Po
+ -rm -f ./$(DEPDIR)/check_dig.Po
+ -rm -f ./$(DEPDIR)/check_disk.Po
+ -rm -f ./$(DEPDIR)/check_dns.Po
+ -rm -f ./$(DEPDIR)/check_dummy.Po
+ -rm -f ./$(DEPDIR)/check_fping.Po
+ -rm -f ./$(DEPDIR)/check_game.Po
+ -rm -f ./$(DEPDIR)/check_hpjd.Po
+ -rm -f ./$(DEPDIR)/check_http.Po
+ -rm -f ./$(DEPDIR)/check_ide_smart.Po
+ -rm -f ./$(DEPDIR)/check_ldap.Po
+ -rm -f ./$(DEPDIR)/check_load.Po
+ -rm -f ./$(DEPDIR)/check_mrtg.Po
+ -rm -f ./$(DEPDIR)/check_mrtgtraf.Po
+ -rm -f ./$(DEPDIR)/check_mysql-check_mysql.Po
+ -rm -f ./$(DEPDIR)/check_mysql_query-check_mysql_query.Po
+ -rm -f ./$(DEPDIR)/check_nagios.Po
+ -rm -f ./$(DEPDIR)/check_nt.Po
+ -rm -f ./$(DEPDIR)/check_ntp.Po
+ -rm -f ./$(DEPDIR)/check_ntp_peer.Po
+ -rm -f ./$(DEPDIR)/check_ntp_time.Po
+ -rm -f ./$(DEPDIR)/check_nwstat.Po
+ -rm -f ./$(DEPDIR)/check_overcr.Po
+ -rm -f ./$(DEPDIR)/check_pgsql.Po
+ -rm -f ./$(DEPDIR)/check_ping.Po
+ -rm -f ./$(DEPDIR)/check_procs.Po
+ -rm -f ./$(DEPDIR)/check_radius.Po
+ -rm -f ./$(DEPDIR)/check_real.Po
+ -rm -f ./$(DEPDIR)/check_smtp.Po
+ -rm -f ./$(DEPDIR)/check_snmp.Po
+ -rm -f ./$(DEPDIR)/check_ssh.Po
+ -rm -f ./$(DEPDIR)/check_swap.Po
+ -rm -f ./$(DEPDIR)/check_tcp.Po
+ -rm -f ./$(DEPDIR)/check_time.Po
+ -rm -f ./$(DEPDIR)/check_ups.Po
+ -rm -f ./$(DEPDIR)/check_users.Po
+ -rm -f ./$(DEPDIR)/negate.Po
+ -rm -f ./$(DEPDIR)/netutils.Po
+ -rm -f ./$(DEPDIR)/popen.Po
+ -rm -f ./$(DEPDIR)/runcmd.Po
+ -rm -f ./$(DEPDIR)/sslutils.Po
+ -rm -f ./$(DEPDIR)/urlize.Po
+ -rm -f ./$(DEPDIR)/utils.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-libexecPROGRAMS uninstall-local
+
+.MAKE: $(am__recursive_targets) check-am install-am install-exec-am \
+ install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \
+ am--depfiles check check-TESTS check-am clean clean-generic \
+ clean-libexecPROGRAMS clean-libtool clean-local \
+ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-exec-hook \
+ install-html install-html-am install-info install-info-am \
+ install-libexecPROGRAMS install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am uninstall uninstall-am \
+ uninstall-libexecPROGRAMS uninstall-local
+
+.PRECIOUS: Makefile
+
+@RELEASE_PRESENT_FALSE@NP-VERSION-FILE: .FORCE-NP-VERSION-FILE
+@RELEASE_PRESENT_FALSE@ @$(SHELL_PATH) $(top_srcdir)/NP-VERSION-GEN
+@RELEASE_PRESENT_FALSE@.FORCE-NP-VERSION-FILE:
+@RELEASE_PRESENT_FALSE@-include NP-VERSION-FILE
+
+test:
+ perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
+
+test-debug:
+ NPTEST_DEBUG=1 HARNESS_VERBOSE=1 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
+
+##############################################################################
+# secondary dependencies
+
+all-local: $(check_tcp_programs)
+
+$(check_tcp_programs): check_tcp
+ rm -f $@
+ ln -s check_tcp $@
+
+install-exec-hook:
+ cd $(DESTDIR)$(libexecdir) && \
+ for i in $(check_tcp_programs) ; do rm -f $$i; ln -s check_tcp $$i ; done ;\
+ if [ -x check_ldap ] ; then rm -f check_ldaps ; ln -s check_ldap check_ldaps ; fi
+
+clean-local:
+ rm -f $(check_tcp_programs)
+ rm -f NP-VERSION-FILE
+
+uninstall-local:
+ cd $(DESTDIR)$(libexecdir) && rm -f $(check_tcp_programs)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
new file mode 100644
index 0000000..fa982ae
--- /dev/null
+++ b/plugins/check_apt.c
@@ -0,0 +1,561 @@
+/*****************************************************************************
+*
+* Monitoring check_apt plugin
+*
+* License: GPL
+* Copyright (c) 2006-2008 Monitoring Plugins Development Team
+*
+* Original author: Sean Finney
+*
+* Description:
+*
+* This file contains the check_apt plugin
+*
+* Check for available updates in apt package management systems
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*****************************************************************************/
+
+const char *progname = "check_apt";
+const char *copyright = "2006-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "runcmd.h"
+#include "utils.h"
+#include "regex.h"
+
+/* some constants */
+typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
+
+/* Character for hidden input file option (for testing). */
+#define INPUT_FILE_OPT CHAR_MAX+1
+/* the default opts can be overridden via the cmdline */
+#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq"
+#define UPDATE_DEFAULT_OPTS "-q"
+/* until i commit the configure.in patch which gets this, i'll define
+ * it here as well */
+#ifndef PATH_TO_APTGET
+# define PATH_TO_APTGET "/usr/bin/apt-get"
+#endif /* PATH_TO_APTGET */
+/* String found at the beginning of the apt output lines we're interested in */
+#define PKGINST_PREFIX "Inst "
+/* the RE that catches security updates */
+#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)"
+
+/* some standard functions */
+int process_arguments(int, char **);
+void print_help(void);
+void print_usage(void);
+
+/* construct the appropriate apt-get cmdline */
+char* construct_cmdline(upgrade_type u, const char *opts);
+/* run an apt-get update */
+int run_update(void);
+/* run an apt-get upgrade */
+int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist);
+/* add another clause to a regexp */
+char* add_to_regexp(char *expr, const char *next);
+/* extract package name from Inst line */
+char* pkg_name(char *line);
+/* string comparison function for qsort */
+int cmpstringp(const void *p1, const void *p2);
+
+/* configuration variables */
+static int verbose = 0; /* -v */
+static bool list = false; /* list packages available for upgrade */
+static bool do_update = false; /* whether to call apt-get update */
+static bool only_critical = false; /* whether to warn about non-critical updates */
+static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
+static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
+static char *update_opts = NULL; /* options to override defaults for update */
+static char *do_include = NULL; /* regexp to only include certain packages */
+static char *do_exclude = NULL; /* regexp to only exclude certain packages */
+static char *do_critical = NULL; /* regexp specifying critical packages */
+static char *input_filename = NULL; /* input filename for testing */
+/* number of packages available for upgrade to return WARNING status */
+static int packages_warning = 1;
+
+/* other global variables */
+static int stderr_warning = 0; /* if a cmd issued output on stderr */
+static int exec_warning = 0; /* if a cmd exited non-zero */
+
+int main (int argc, char **argv) {
+ int result=STATE_UNKNOWN, packages_available=0, sec_count=0, i=0;
+ char **packages_list=NULL, **secpackages_list=NULL;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts(&argc, argv, progname);
+
+ if (process_arguments(argc, argv) == ERROR)
+ usage_va(_("Could not parse arguments"));
+
+ /* Set signal handling and alarm timeout */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ usage_va(_("Cannot catch SIGALRM"));
+ }
+
+ /* handle timeouts gracefully... */
+ alarm (timeout_interval);
+
+ /* if they want to run apt-get update first... */
+ if(do_update) result = run_update();
+
+ /* apt-get upgrade */
+ result = max_state(result, run_upgrade(&packages_available, &sec_count, &packages_list, &secpackages_list));
+
+ if(sec_count > 0){
+ result = max_state(result, STATE_CRITICAL);
+ } else if(packages_available >= packages_warning && only_critical == false){
+ result = max_state(result, STATE_WARNING);
+ } else if(result > STATE_UNKNOWN){
+ result = STATE_UNKNOWN;
+ }
+
+ printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"),
+ state_text(result),
+ packages_available,
+ (upgrade==DIST_UPGRADE)?"dist-upgrade":"upgrade",
+ sec_count,
+ (stderr_warning)?" warnings detected":"",
+ (stderr_warning && exec_warning)?",":"",
+ (exec_warning)?" errors detected":"",
+ (stderr_warning||exec_warning)?".":"",
+ packages_available,
+ sec_count
+ );
+
+ if(list) {
+ qsort(secpackages_list, sec_count, sizeof(char*), cmpstringp);
+ qsort(packages_list, packages_available-sec_count, sizeof(char*), cmpstringp);
+
+ for(i = 0; i < sec_count; i++)
+ printf("%s (security)\n", secpackages_list[i]);
+ if (only_critical == false) {
+ for(i = 0; i < packages_available - sec_count; i++)
+ printf("%s\n", packages_list[i]);
+ }
+ }
+
+ return result;
+}
+
+/* process command-line arguments */
+int process_arguments (int argc, char **argv) {
+ int c;
+
+ static struct option longopts[] = {
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {"timeout", required_argument, 0, 't'},
+ {"update", optional_argument, 0, 'u'},
+ {"upgrade", optional_argument, 0, 'U'},
+ {"no-upgrade", no_argument, 0, 'n'},
+ {"dist-upgrade", optional_argument, 0, 'd'},
+ {"list", no_argument, false, 'l'},
+ {"include", required_argument, 0, 'i'},
+ {"exclude", required_argument, 0, 'e'},
+ {"critical", required_argument, 0, 'c'},
+ {"only-critical", no_argument, 0, 'o'},
+ {"input-file", required_argument, 0, INPUT_FILE_OPT},
+ {"packages-warning", required_argument, 0, 'w'},
+ {0, 0, 0, 0}
+ };
+
+ while(1) {
+ c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
+
+ if(c == -1 || c == EOF || c == 1) break;
+
+ switch(c) {
+ case 'h':
+ print_help();
+ exit(STATE_UNKNOWN);
+ case 'V':
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ case 'v':
+ verbose++;
+ break;
+ case 't':
+ timeout_interval=atoi(optarg);
+ break;
+ case 'd':
+ upgrade=DIST_UPGRADE;
+ if(optarg!=NULL){
+ upgrade_opts=strdup(optarg);
+ if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed");
+ }
+ break;
+ case 'U':
+ upgrade=UPGRADE;
+ if(optarg!=NULL){
+ upgrade_opts=strdup(optarg);
+ if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed");
+ }
+ break;
+ case 'n':
+ upgrade=NO_UPGRADE;
+ break;
+ case 'u':
+ do_update=true;
+ if(optarg!=NULL){
+ update_opts=strdup(optarg);
+ if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed");
+ }
+ break;
+ case 'l':
+ list=true;
+ break;
+ case 'i':
+ do_include=add_to_regexp(do_include, optarg);
+ break;
+ case 'e':
+ do_exclude=add_to_regexp(do_exclude, optarg);
+ break;
+ case 'c':
+ do_critical=add_to_regexp(do_critical, optarg);
+ break;
+ case 'o':
+ only_critical=true;
+ break;
+ case INPUT_FILE_OPT:
+ input_filename = optarg;
+ break;
+ case 'w':
+ packages_warning = atoi(optarg);
+ break;
+ default:
+ /* print short usage statement if args not parsable */
+ usage5();
+ }
+ }
+
+ return OK;
+}
+
+
+/* run an apt-get upgrade */
+int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist){
+ int i=0, result=STATE_UNKNOWN, regres=0, pc=0, spc=0;
+ struct output chld_out, chld_err;
+ regex_t ireg, ereg, sreg;
+ char *cmdline=NULL, rerrbuf[64];
+
+ /* initialize ereg as it is possible it is printed while uninitialized */
+ memset(&ereg, '\0', sizeof(ereg.buffer));
+
+ if(upgrade==NO_UPGRADE) return STATE_OK;
+
+ /* compile the regexps */
+ if (do_include != NULL) {
+ regres=regcomp(&ireg, do_include, REG_EXTENDED);
+ if (regres!=0) {
+ regerror(regres, &ireg, rerrbuf, 64);
+ die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
+ }
+ }
+
+ if(do_exclude!=NULL){
+ regres=regcomp(&ereg, do_exclude, REG_EXTENDED);
+ if(regres!=0) {
+ regerror(regres, &ereg, rerrbuf, 64);
+ die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"),
+ progname, rerrbuf);
+ }
+ }
+
+ const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
+ regres=regcomp(&sreg, crit_ptr, REG_EXTENDED);
+ if(regres!=0) {
+ regerror(regres, &ereg, rerrbuf, 64);
+ die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"),
+ progname, rerrbuf);
+ }
+
+ cmdline=construct_cmdline(upgrade, upgrade_opts);
+ if (input_filename != NULL) {
+ /* read input from a file for testing */
+ result = cmd_file_read(input_filename, &chld_out, 0);
+ } else {
+ /* run the upgrade */
+ result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
+ }
+
+ /* apt-get upgrade only changes exit status if there is an
+ * internal error when run in dry-run mode. therefore we will
+ * treat such an error as UNKNOWN */
+ if(result != 0){
+ exec_warning=1;
+ result = STATE_UNKNOWN;
+ fprintf(stderr, _("'%s' exited with non-zero status.\n"),
+ cmdline);
+ }
+
+ *pkglist=malloc(sizeof(char *) * chld_out.lines);
+ if(!pkglist) die(STATE_UNKNOWN, "malloc failed!\n");
+ *secpkglist=malloc(sizeof(char *) * chld_out.lines);
+ if(!secpkglist) die(STATE_UNKNOWN, "malloc failed!\n");
+
+ /* parse the output, which should only consist of lines like
+ *
+ * Inst package ....
+ * Conf package ....
+ *
+ * so we'll filter based on "Inst" for the time being. later
+ * we may need to switch to the --print-uris output format,
+ * in which case the logic here will slightly change.
+ */
+ for(i = 0; i < chld_out.lines; i++) {
+ if(verbose){
+ printf("%s\n", chld_out.line[i]);
+ }
+ /* if it is a package we care about */
+ if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 &&
+ (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) {
+ /* if we're not excluding, or it's not in the
+ * list of stuff to exclude */
+ if(do_exclude==NULL ||
+ regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){
+ pc++;
+ if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){
+ spc++;
+ if(verbose) printf("*");
+ (*secpkglist)[spc-1] = pkg_name(chld_out.line[i]);
+ } else {
+ (*pkglist)[pc-spc-1] = pkg_name(chld_out.line[i]);
+ }
+ if(verbose){
+ printf("*%s\n", chld_out.line[i]);
+ }
+ }
+ }
+ }
+ *pkgcount=pc;
+ *secpkgcount=spc;
+
+ /* If we get anything on stderr, at least set warning */
+ if (input_filename == NULL && chld_err.buflen) {
+ stderr_warning=1;
+ result = max_state(result, STATE_WARNING);
+ if(verbose){
+ for(i = 0; i < chld_err.lines; i++) {
+ fprintf(stderr, "%s\n", chld_err.line[i]);
+ }
+ }
+ }
+ if (do_include != NULL) regfree(&ireg);
+ regfree(&sreg);
+ if(do_exclude!=NULL) regfree(&ereg);
+ free(cmdline);
+ return result;
+}
+
+/* run an apt-get update (needs root) */
+int run_update(void){
+ int i=0, result=STATE_UNKNOWN;
+ struct output chld_out, chld_err;
+ char *cmdline;
+
+ /* run the update */
+ cmdline = construct_cmdline(NO_UPGRADE, update_opts);
+ result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
+ /* apt-get update changes exit status if it can't fetch packages.
+ * since we were explicitly asked to do so, this is treated as
+ * a critical error. */
+ if(result != 0){
+ exec_warning=1;
+ result = STATE_CRITICAL;
+ fprintf(stderr, _("'%s' exited with non-zero status.\n"),
+ cmdline);
+ }
+
+ if(verbose){
+ for(i = 0; i < chld_out.lines; i++) {
+ printf("%s\n", chld_out.line[i]);
+ }
+ }
+
+ /* If we get anything on stderr, at least set warning */
+ if(chld_err.buflen){
+ stderr_warning=1;
+ result = max_state(result, STATE_WARNING);
+ if(verbose){
+ for(i = 0; i < chld_err.lines; i++) {
+ fprintf(stderr, "%s\n", chld_err.line[i]);
+ }
+ }
+ }
+ free(cmdline);
+ return result;
+}
+
+char* pkg_name(char *line){
+ char *start=NULL, *space=NULL, *pkg=NULL;
+ int len=0;
+
+ start = line + strlen(PKGINST_PREFIX);
+ len = strlen(start);
+
+ space = index(start, ' ');
+ if(space!=NULL){
+ len = space - start;
+ }
+
+ pkg=malloc(sizeof(char)*(len+1));
+ if(!pkg) die(STATE_UNKNOWN, "malloc failed!\n");
+
+ strncpy(pkg, start, len);
+ pkg[len]='\0';
+
+ return pkg;
+}
+
+int cmpstringp(const void *p1, const void *p2){
+ return strcmp(* (char * const *) p1, * (char * const *) p2);
+}
+
+char* add_to_regexp(char *expr, const char *next){
+ char *re=NULL;
+
+ if(expr==NULL){
+ re=malloc(sizeof(char)*(strlen("()")+strlen(next)+1));
+ if(!re) die(STATE_UNKNOWN, "malloc failed!\n");
+ sprintf(re, "(%s)", next);
+ } else {
+ /* resize it, adding an extra char for the new '|' separator */
+ re=realloc(expr, sizeof(char)*(strlen(expr)+1+strlen(next)+1));
+ if(!re) die(STATE_UNKNOWN, "realloc failed!\n");
+ /* append it starting at ')' in the old re */
+ sprintf((char*)(re+strlen(re)-1), "|%s)", next);
+ }
+
+ return re;
+}
+
+char* construct_cmdline(upgrade_type u, const char *opts){
+ int len=0;
+ const char *opts_ptr=NULL, *aptcmd=NULL;
+ char *cmd=NULL;
+
+ switch(u){
+ case UPGRADE:
+ if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS;
+ else opts_ptr=opts;
+ aptcmd="upgrade";
+ break;
+ case DIST_UPGRADE:
+ if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS;
+ else opts_ptr=opts;
+ aptcmd="dist-upgrade";
+ break;
+ case NO_UPGRADE:
+ if(opts==NULL) opts_ptr=UPDATE_DEFAULT_OPTS;
+ else opts_ptr=opts;
+ aptcmd="update";
+ break;
+ }
+
+ len+=strlen(PATH_TO_APTGET)+1; /* "/usr/bin/apt-get " */
+ len+=strlen(opts_ptr)+1; /* "opts " */
+ len+=strlen(aptcmd)+1; /* "upgrade\0" */
+
+ cmd=(char*)malloc(sizeof(char)*len);
+ if(cmd==NULL) die(STATE_UNKNOWN, "malloc failed");
+ sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd);
+ return cmd;
+}
+
+/* informative help message */
+void
+print_help (void)
+{
+ print_revision(progname, NP_VERSION);
+
+ printf(_(COPYRIGHT), copyright, email);
+
+ printf("%s\n", _("This plugin checks for software updates on systems that use"));
+ printf("%s\n", _("package management systems based on the apt-get(8) command"));
+ printf("%s\n", _("found in Debian GNU/Linux"));
+
+ printf ("\n\n");
+
+ print_usage();
+
+ printf(UT_HELP_VRSN);
+ printf(UT_EXTRA_OPTS);
+
+ printf(UT_PLUG_TIMEOUT, timeout_interval);
+
+ printf (" %s\n", "-n, --no-upgrade");
+ printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least)."));
+ printf (" %s\n", "-l, --list");
+ printf (" %s\n", _("List packages available for upgrade. Packages are printed sorted by"));
+ printf (" %s\n", _("name with security packages listed first."));
+ printf (" %s\n", "-i, --include=REGEXP");
+ printf (" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times"));
+ printf (" %s\n", _("the values will be combined together. Any packages matching this list"));
+ printf (" %s\n", _("cause the plugin to return WARNING status. Others will be ignored."));
+ printf (" %s\n", _("Default is to include all packages."));
+ printf (" %s\n", "-e, --exclude=REGEXP");
+ printf (" %s\n", _("Exclude packages matching REGEXP from the list of packages that would"));
+ printf (" %s\n", _("otherwise be included. Can be specified multiple times; the values"));
+ printf (" %s\n", _("will be combined together. Default is to exclude no packages."));
+ printf (" %s\n", "-c, --critical=REGEXP");
+ printf (" %s\n", _("If the full package information of any of the upgradable packages match"));
+ printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
+ printf (" %s\n", _("multiple times like above. Default is a regexp matching security"));
+ printf (" %s\n", _("upgrades for Debian and Ubuntu:"));
+ printf (" \t%s\n", SECURITY_RE);
+ printf (" %s\n", _("Note that the package must first match the include list before its"));
+ printf (" %s\n", _("information is compared against the critical list."));
+ printf (" %s\n", "-o, --only-critical");
+ printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
+ printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause"));
+ printf (" %s\n", _("the plugin to return WARNING status."));
+ printf (" %s\n", "-w, --packages-warning");
+ printf (" %s\n", _("Minimum number of packages available for upgrade to return WARNING status."));
+ printf (" %s\n\n", _("Default is 1 package."));
+
+ printf ("%s\n\n", _("The following options require root privileges and should be used with care:"));
+ printf (" %s\n", "-u, --update=OPTS");
+ printf (" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides"));
+ printf (" %s\n", _("the default options. Note: you may also need to adjust the global"));
+ printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
+ printf (" %s\n", _("upgrade is expected to take longer than the default timeout."));
+ printf (" %s\n", "-U, --upgrade=OPTS");
+ printf (" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,"));
+ printf (" %s\n", _("apt-get will be run with these command line options instead of the"));
+ printf (" %s", _("default "));
+ printf ("(%s).\n", UPGRADE_DEFAULT_OPTS);
+ printf (" %s\n", _("Note that you may be required to have root privileges if you do not use"));
+ printf (" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade"));
+ printf (" %s\n", "-d, --dist-upgrade=OPTS");
+ printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
+ printf (" %s\n", _("can be provided to override the default options."));
+
+ printf(UT_SUPPORT);
+}
+
+
+/* simple usage heading */
+void
+print_usage(void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
+}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
new file mode 100644
index 0000000..1ad547e
--- /dev/null
+++ b/plugins/check_by_ssh.c
@@ -0,0 +1,496 @@
+/*****************************************************************************
+*
+* Monitoring check_by_ssh plugin
+*
+* License: GPL
+* Copyright (c) 2000-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_by_ssh plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_by_ssh";
+const char *copyright = "2000-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "netutils.h"
+#include "utils_cmd.h"
+
+#ifndef NP_MAXARGS
+#define NP_MAXARGS 1024
+#endif
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void comm_append (const char *);
+void print_help (void);
+void print_usage (void);
+
+unsigned int commands = 0;
+unsigned int services = 0;
+int skip_stdout = 0;
+int skip_stderr = 0;
+int warn_on_stderr = 0;
+bool unknown_timeout = FALSE;
+char *remotecmd = NULL;
+char **commargv = NULL;
+int commargc = 0;
+char *hostname = NULL;
+char *outputfile = NULL;
+char *host_shortname = NULL;
+char **service;
+int passive = FALSE;
+int verbose = FALSE;
+
+int
+main (int argc, char **argv)
+{
+
+ char *status_text;
+ int cresult;
+ int result = STATE_UNKNOWN;
+ int i;
+ time_t local_time;
+ FILE *fp = NULL;
+ output chld_out, chld_err;
+
+ remotecmd = "";
+ comm_append(SSH_COMMAND);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ /* process arguments */
+ if (process_arguments (argc, argv) == ERROR)
+ usage_va(_("Could not parse arguments"));
+
+ /* Set signal handling and alarm timeout */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ usage_va(_("Cannot catch SIGALRM"));
+ }
+ alarm (timeout_interval);
+
+ /* run the command */
+ if (verbose) {
+ printf ("Command: %s\n", commargv[0]);
+ for (i=1; i<commargc; i++)
+ printf ("Argument %i: %s\n", i, commargv[i]);
+ }
+
+ result = cmd_run_array (commargv, &chld_out, &chld_err, 0);
+
+ /* SSH returns 255 if connection attempt fails; include the first line of error output */
+ if (result == 255 && unknown_timeout) {
+ printf (_("SSH connection failed: %s\n"),
+ chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
+ return STATE_UNKNOWN;
+ }
+
+ if (verbose) {
+ for(i = 0; i < chld_out.lines; i++)
+ printf("stdout: %s\n", chld_out.line[i]);
+ for(i = 0; i < chld_err.lines; i++)
+ printf("stderr: %s\n", chld_err.line[i]);
+ }
+
+ if (skip_stdout == -1) /* --skip-stdout specified without argument */
+ skip_stdout = chld_out.lines;
+ if (skip_stderr == -1) /* --skip-stderr specified without argument */
+ skip_stderr = chld_err.lines;
+
+ /* UNKNOWN or worse if (non-skipped) output found on stderr */
+ if(chld_err.lines > skip_stderr) {
+ printf (_("Remote command execution failed: %s\n"),
+ chld_err.line[skip_stderr]);
+ if ( warn_on_stderr )
+ return max_state_alt(result, STATE_WARNING);
+ else
+ return max_state_alt(result, STATE_UNKNOWN);
+ }
+
+ /* this is simple if we're not supposed to be passive.
+ * Wrap up quickly and keep the tricks below */
+ if(!passive) {
+ if (chld_out.lines > skip_stdout)
+ for (i = skip_stdout; i < chld_out.lines; i++)
+ puts (chld_out.line[i]);
+ else
+ printf (_("%s - check_by_ssh: Remote command '%s' returned status %d\n"),
+ state_text(result), remotecmd, result);
+ return result; /* return error status from remote command */
+ }
+
+
+ /*
+ * Passive mode
+ */
+
+ /* process output */
+ if (!(fp = fopen (outputfile, "a"))) {
+ printf (_("SSH WARNING: could not open %s\n"), outputfile);
+ exit (STATE_UNKNOWN);
+ }
+
+ local_time = time (NULL);
+ commands = 0;
+ for(i = skip_stdout; i < chld_out.lines; i++) {
+ status_text = chld_out.line[i++];
+ if (i == chld_out.lines || strstr (chld_out.line[i], "STATUS CODE: ") == NULL)
+ die (STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
+
+ if (service[commands] && status_text
+ && sscanf (chld_out.line[i], "STATUS CODE: %d", &cresult) == 1)
+ {
+ fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
+ (int) local_time, host_shortname, service[commands++],
+ cresult, status_text);
+ }
+ }
+
+ /* Multiple commands and passive checking should always return OK */
+ return result;
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char *p1, *p2;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {"fork", no_argument, 0, 'f'},
+ {"timeout", required_argument, 0, 't'},
+ {"unknown-timeout", no_argument, 0, 'U'},
+ {"host", required_argument, 0, 'H'}, /* backward compatibility */
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument,0,'p'},
+ {"output", required_argument, 0, 'O'},
+ {"name", required_argument, 0, 'n'},
+ {"services", required_argument, 0, 's'},
+ {"identity", required_argument, 0, 'i'},
+ {"user", required_argument, 0, 'u'},
+ {"logname", required_argument, 0, 'l'},
+ {"command", required_argument, 0, 'C'},
+ {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
+ {"skip-stdout", optional_argument, 0, 'S'},
+ {"skip-stderr", optional_argument, 0, 'E'},
+ {"warn-on-stderr", no_argument, 0, 'W'},
+ {"proto1", no_argument, 0, '1'},
+ {"proto2", no_argument, 0, '2'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"ssh-option", required_argument, 0, 'o'},
+ {"quiet", no_argument, 0, 'q'},
+ {"configfile", optional_argument, 0, 'F'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'v': /* help */
+ verbose = TRUE;
+ break;
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage_va(_("Timeout interval must be a positive integer"));
+ else
+ timeout_interval = atoi (optarg);
+ break;
+ case 'U':
+ unknown_timeout = TRUE;
+ break;
+ case 'H': /* host */
+ hostname = optarg;
+ break;
+ case 'p': /* port number */
+ if (!is_integer (optarg))
+ usage_va(_("Port must be a positive integer"));
+ comm_append("-p");
+ comm_append(optarg);
+ break;
+ case 'O': /* output file */
+ outputfile = optarg;
+ passive = TRUE;
+ break;
+ case 's': /* description of service to check */
+ p1 = optarg;
+ service = realloc (service, (++services) * sizeof(char *));
+ while ((p2 = index (p1, ':'))) {
+ *p2 = '\0';
+ service[services - 1] = p1;
+ service = realloc (service, (++services) * sizeof(char *));
+ p1 = p2 + 1;
+ }
+ service[services - 1] = p1;
+ break;
+ case 'n': /* short name of host in the monitoring configuration */
+ host_shortname = optarg;
+ break;
+
+ case 'u':
+ comm_append("-l");
+ comm_append(optarg);
+ break;
+ case 'l': /* login name */
+ comm_append("-l");
+ comm_append(optarg);
+ break;
+ case 'i': /* identity */
+ comm_append("-i");
+ comm_append(optarg);
+ break;
+
+ case '1': /* Pass these switches directly to ssh */
+ comm_append("-1");
+ break;
+ case '2': /* 1 to force version 1, 2 to force version 2 */
+ comm_append("-2");
+ break;
+ case '4': /* -4 for IPv4 */
+ comm_append("-4");
+ break;
+ case '6': /* -6 for IPv6 */
+ comm_append("-6");
+ break;
+ case 'f': /* fork to background */
+ comm_append("-f");
+ break;
+ case 'C': /* Command for remote machine */
+ commands++;
+ if (commands > 1)
+ xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
+ xasprintf (&remotecmd, "%s%s", remotecmd, optarg);
+ break;
+ case 'S': /* skip n (or all) lines on stdout */
+ if (optarg == NULL)
+ skip_stdout = -1; /* skip all output on stdout */
+ else if (!is_integer (optarg))
+ usage_va(_("skip-stdout argument must be an integer"));
+ else
+ skip_stdout = atoi (optarg);
+ break;
+ case 'E': /* skip n (or all) lines on stderr */
+ if (optarg == NULL)
+ skip_stderr = -1; /* skip all output on stderr */
+ else if (!is_integer (optarg))
+ usage_va(_("skip-stderr argument must be an integer"));
+ else
+ skip_stderr = atoi (optarg);
+ break;
+ case 'W': /* exit with warning if there is an output on stderr */
+ warn_on_stderr = 1;
+ break;
+ case 'o': /* Extra options for the ssh command */
+ comm_append("-o");
+ comm_append(optarg);
+ break;
+ case 'q': /* Tell the ssh command to be quiet */
+ comm_append("-q");
+ break;
+ case 'F': /* ssh configfile */
+ comm_append("-F");
+ comm_append(optarg);
+ break;
+ default: /* help */
+ usage5();
+ }
+ }
+
+ c = optind;
+ if (hostname == NULL) {
+ if (c <= argc) {
+ die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
+ }
+ hostname = argv[c++];
+ }
+
+ if (strlen(remotecmd) == 0) {
+ for (; c < argc; c++)
+ if (strlen(remotecmd) > 0)
+ xasprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
+ else
+ xasprintf (&remotecmd, "%s", argv[c]);
+ }
+
+ if (commands > 1 || passive)
+ xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
+
+ if (remotecmd == NULL || strlen (remotecmd) <= 1)
+ usage_va(_("No remotecmd"));
+
+ comm_append(hostname);
+ comm_append(remotecmd);
+
+ return validate_arguments ();
+}
+
+
+void
+comm_append (const char *str)
+{
+
+ if (++commargc > NP_MAXARGS)
+ die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
+
+ if ((commargv = (char **)realloc(commargv, (commargc+1) * sizeof(char *))) == NULL)
+ die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
+
+ commargv[commargc-1] = strdup(str);
+ commargv[commargc] = NULL;
+
+}
+
+int
+validate_arguments (void)
+{
+ if (remotecmd == NULL || hostname == NULL)
+ return ERROR;
+
+ if (passive && commands != services)
+ die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
+
+ if (passive && host_shortname == NULL)
+ die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname);
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin uses SSH to execute commands on a remote host"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', "none");
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-1, --proto1");
+ printf (" %s\n", _("tell ssh to use Protocol 1 [optional]"));
+ printf (" %s\n", "-2, --proto2");
+ printf (" %s\n", _("tell ssh to use Protocol 2 [optional]"));
+ printf (" %s\n", "-S, --skip-stdout[=n]");
+ printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
+ printf (" %s\n", "-E, --skip-stderr[=n]");
+ printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
+ printf (" %s\n", "-W, --warn-on-stderr]");
+ printf (" %s\n", _("Exit with an warning, if there is an output on STDERR"));
+ printf (" %s\n", "-f");
+ printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed"));
+ printf (" %s\n","-C, --command='COMMAND STRING'");
+ printf (" %s\n", _("command to execute on the remote machine"));
+ printf (" %s\n","-l, --logname=USERNAME");
+ printf (" %s\n", _("SSH user name on remote host [optional]"));
+ printf (" %s\n","-i, --identity=KEYFILE");
+ printf (" %s\n", _("identity of an authorized key [optional]"));
+ printf (" %s\n","-O, --output=FILE");
+ printf (" %s\n", _("external command file for monitoring [optional]"));
+ printf (" %s\n","-s, --services=LIST");
+ printf (" %s\n", _("list of monitoring service names, separated by ':' [optional]"));
+ printf (" %s\n","-n, --name=NAME");
+ printf (" %s\n", _("short name of host in the monitoring configuration [optional]"));
+ printf (" %s\n","-o, --ssh-option=OPTION");
+ printf (" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]"));
+ printf (" %s\n","-F, --configfile");
+ printf (" %s\n", _("Tell ssh to use this configfile [optional]"));
+ printf (" %s\n","-q, --quiet");
+ printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
+ printf (UT_WARN_CRIT);
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (" %s\n","-U, --unknown-timeout");
+ printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
+ printf (UT_VERBOSE);
+ printf("\n");
+ printf (" %s\n", _("The most common mode of use is to refer to a local identity file with"));
+ printf (" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
+ printf (" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
+ printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
+ printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
+ printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
+ printf (" %s\n", _("execute additional commands as proxy"));
+ printf("\n");
+ printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide"));
+ printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
+ printf (" %s\n", "$ cat /tmp/foo");
+ printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
+ printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
+ printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
+
+ printf(UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
+ " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
+ " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
+ " [-p port] [-o ssh-option] [-F configfile]\n",
+ progname);
+}
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
new file mode 100644
index 0000000..e1ede9f
--- /dev/null
+++ b/plugins/check_cluster.c
@@ -0,0 +1,289 @@
+/*****************************************************************************
+*
+* check_cluster.c - Host and Service Cluster Plugin for Monitoring
+*
+* License: GPL
+* Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)
+* Copyright (c) 2007 Monitoring Plugins 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_cluster";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_base.h"
+
+#define CHECK_SERVICES 1
+#define CHECK_HOSTS 2
+
+void print_help (void);
+void print_usage (void);
+
+int total_services_ok=0;
+int total_services_warning=0;
+int total_services_unknown=0;
+int total_services_critical=0;
+
+int total_hosts_up=0;
+int total_hosts_down=0;
+int total_hosts_unreachable=0;
+
+char *warn_threshold;
+char *crit_threshold;
+
+int check_type=CHECK_SERVICES;
+
+char *data_vals=NULL;
+char *label=NULL;
+
+int verbose=0;
+
+int process_arguments(int,char **);
+
+
+
+int main(int argc, char **argv){
+ char *ptr;
+ int data_val;
+ int return_code=STATE_OK;
+ thresholds *thresholds = NULL;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts(&argc, argv, progname);
+
+ if(process_arguments(argc,argv)==ERROR)
+ usage(_("Could not parse arguments"));
+
+ /* Initialize the thresholds */
+ set_thresholds(&thresholds, warn_threshold, crit_threshold);
+ if(verbose)
+ print_thresholds("check_cluster", thresholds);
+
+ /* check the data values */
+ for(ptr=strtok(data_vals,",");ptr!=NULL;ptr=strtok(NULL,",")){
+
+ data_val=atoi(ptr);
+
+ if(check_type==CHECK_SERVICES){
+ switch(data_val){
+ case 0:
+ total_services_ok++;
+ break;
+ case 1:
+ total_services_warning++;
+ break;
+ case 2:
+ total_services_critical++;
+ break;
+ case 3:
+ total_services_unknown++;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ switch(data_val){
+ case 0:
+ total_hosts_up++;
+ break;
+ case 1:
+ total_hosts_down++;
+ break;
+ case 2:
+ total_hosts_unreachable++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ /* return the status of the cluster */
+ if(check_type==CHECK_SERVICES){
+ return_code=get_status(total_services_warning+total_services_unknown+total_services_critical, thresholds);
+ printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n",
+ state_text(return_code), (label==NULL)?"Service cluster":label,
+ total_services_ok,total_services_warning,
+ total_services_unknown,total_services_critical);
+ }
+ else{
+ return_code=get_status(total_hosts_down+total_hosts_unreachable, thresholds);
+ printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n",
+ state_text(return_code), (label==NULL)?"Host cluster":label,
+ total_hosts_up,total_hosts_down,total_hosts_unreachable);
+ }
+
+ return return_code;
+}
+
+
+
+int process_arguments(int argc, char **argv){
+ int c;
+ char *ptr;
+ int option=0;
+ static struct option longopts[]={
+ {"data", required_argument,0,'d'},
+ {"warning", required_argument,0,'w'},
+ {"critical", required_argument,0,'c'},
+ {"label", required_argument,0,'l'},
+ {"host", no_argument, 0,'h'},
+ {"service", no_argument, 0,'s'},
+ {"verbose", no_argument, 0,'v'},
+ {"version", no_argument, 0,'V'},
+ {"help", no_argument, 0,'H'},
+ {0,0,0,0}
+ };
+
+ /* no options were supplied */
+ if(argc<2)
+ return ERROR;
+
+ while(1){
+
+ c=getopt_long(argc,argv,"hHsvVw:c:d:l:",longopts,&option);
+
+ if(c==-1 || c==EOF || c==1)
+ break;
+
+ switch(c){
+
+ case 'h': /* host cluster */
+ check_type=CHECK_HOSTS;
+ break;
+
+ case 's': /* service cluster */
+ check_type=CHECK_SERVICES;
+ break;
+
+ case 'w': /* warning threshold */
+ warn_threshold = strdup(optarg);
+ break;
+
+ case 'c': /* warning threshold */
+ crit_threshold = strdup(optarg);
+ break;
+
+ case 'd': /* data values */
+ data_vals=(char *)strdup(optarg);
+ /* validate data */
+ for (ptr=data_vals;ptr!=NULL;ptr+=2){
+ if (ptr[0]<'0' || ptr[0]>'3')
+ return ERROR;
+ if (ptr[1]=='\0')
+ break;
+ if (ptr[1]!=',')
+ return ERROR;
+ }
+ break;
+
+ case 'l': /* text label */
+ label=(char *)strdup(optarg);
+ break;
+
+ case 'v': /* verbose */
+ verbose++;
+ break;
+
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ break;
+
+ case 'H': /* help */
+ print_help();
+ exit(STATE_UNKNOWN);
+ break;
+
+ default:
+ return ERROR;
+ break;
+ }
+ }
+
+ if(data_vals==NULL)
+ return ERROR;
+
+ return OK;
+}
+
+void
+print_help(void)
+{
+ print_revision(progname, NP_VERSION);
+ printf ("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n");
+ printf(COPYRIGHT, copyright, email);
+
+ printf(_("Host/Service Cluster Plugin for Monitoring"));
+ printf("\n\n");
+
+ print_usage();
+
+ printf("\n");
+ printf("%s\n", _("Options:"));
+ printf(UT_EXTRA_OPTS);
+ printf (" %s\n", "-s, --service");
+ printf (" %s\n", _("Check service cluster status"));
+ printf (" %s\n", "-h, --host");
+ printf (" %s\n", _("Check host cluster status"));
+ printf (" %s\n", "-l, --label=STRING");
+ printf (" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")"));
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
+ printf (" %s\n", _("non-OK state in order to return a WARNING status level"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
+ printf (" %s\n", _("non-OK state in order to return a CRITICAL status level"));
+ printf (" %s\n", "-d, --data=LIST");
+ printf (" %s\n", _("The status codes of the hosts or services in the cluster, separated by"));
+ printf (" %s\n", _("commas"));
+
+ printf(UT_VERBOSE);
+
+ printf("\n");
+ printf("%s\n", _("Notes:"));
+ printf(UT_THRESHOLDS_NOTES);
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:");
+ printf (" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK") );
+ printf (" %s\n", _("state.") );
+
+ printf(UT_SUPPORT);
+}
+
+
+void
+print_usage(void)
+{
+
+ printf("%s\n", _("Usage:"));
+ printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname);
+ printf("[-w threshold] [-c threshold] [-v] [--help]\n");
+
+}
+
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
new file mode 100644
index 0000000..153e492
--- /dev/null
+++ b/plugins/check_curl.c
@@ -0,0 +1,2704 @@
+/*****************************************************************************
+*
+* Monitoring check_curl plugin
+*
+* License: GPL
+* Copyright (c) 1999-2019 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_curl plugin
+*
+* This plugin tests the HTTP service on the specified host. It can test
+* normal (http) and secure (https) servers, follow redirects, search for
+* strings and regular expressions, check connection times, and report on
+* certificate expiration times.
+*
+* This plugin uses functions from the curl library, see
+* http://curl.haxx.se
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+const char *progname = "check_curl";
+
+const char *copyright = "2006-2019";
+const char *email = "devel@monitoring-plugins.org";
+
+#include <stdbool.h>
+#include <ctype.h>
+
+#include "common.h"
+#include "utils.h"
+
+#ifndef LIBCURL_PROTOCOL_HTTP
+#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
+#endif
+
+#include "curl/curl.h"
+#include "curl/easy.h"
+
+#include "picohttpparser.h"
+
+#include "uriparser/Uri.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#if defined(HAVE_SSL) && defined(USE_OPENSSL)
+#include <openssl/opensslv.h>
+#endif
+
+#include <netdb.h>
+
+#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
+
+#define DEFAULT_BUFFER_SIZE 2048
+#define DEFAULT_SERVER_URL "/"
+#define HTTP_EXPECT "HTTP/"
+#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
+enum {
+ MAX_IPV4_HOSTLENGTH = 255,
+ HTTP_PORT = 80,
+ HTTPS_PORT = 443,
+ MAX_PORT = 65535,
+ DEFAULT_MAX_REDIRS = 15
+};
+
+enum {
+ STICKY_NONE = 0,
+ STICKY_HOST = 1,
+ STICKY_PORT = 2
+};
+
+enum {
+ FOLLOW_HTTP_CURL = 0,
+ FOLLOW_LIBCURL = 1
+};
+
+/* for buffers for header and body */
+typedef struct {
+ char *buf;
+ size_t buflen;
+ size_t bufsize;
+} curlhelp_write_curlbuf;
+
+/* for buffering the data sent in PUT */
+typedef struct {
+ char *buf;
+ size_t buflen;
+ off_t pos;
+} curlhelp_read_curlbuf;
+
+/* for parsing the HTTP status line */
+typedef struct {
+ int http_major; /* major version of the protocol, always 1 (HTTP/0.9
+ * never reached the big internet most likely) */
+ int http_minor; /* minor version of the protocol, usually 0 or 1 */
+ int http_code; /* HTTP return code as in RFC 2145 */
+ int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
+ * http://support.microsoft.com/kb/318380/en-us */
+ const char *msg; /* the human readable message */
+ char *first_line; /* a copy of the first line */
+} curlhelp_statusline;
+
+/* to know the underlying SSL library used by libcurl */
+typedef enum curlhelp_ssl_library {
+ CURLHELP_SSL_LIBRARY_UNKNOWN,
+ CURLHELP_SSL_LIBRARY_OPENSSL,
+ CURLHELP_SSL_LIBRARY_LIBRESSL,
+ CURLHELP_SSL_LIBRARY_GNUTLS,
+ CURLHELP_SSL_LIBRARY_NSS
+} curlhelp_ssl_library;
+
+enum {
+ REGS = 2,
+ MAX_RE_SIZE = 1024
+};
+#include "regex.h"
+regex_t preg;
+regmatch_t pmatch[REGS];
+char regexp[MAX_RE_SIZE];
+int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
+int errcode;
+bool invert_regex = false;
+
+char *server_address = NULL;
+char *host_name = NULL;
+char *server_url = 0;
+char server_ip[DEFAULT_BUFFER_SIZE];
+struct curl_slist *server_ips = NULL;
+bool specify_port = false;
+unsigned short server_port = HTTP_PORT;
+unsigned short virtual_port = 0;
+int host_name_length;
+char output_header_search[30] = "";
+char output_string_search[30] = "";
+char *warning_thresholds = NULL;
+char *critical_thresholds = NULL;
+int days_till_exp_warn, days_till_exp_crit;
+thresholds *thlds;
+char user_agent[DEFAULT_BUFFER_SIZE];
+int verbose = 0;
+bool show_extended_perfdata = false;
+bool show_body = false;
+int min_page_len = 0;
+int max_page_len = 0;
+int redir_depth = 0;
+int max_depth = DEFAULT_MAX_REDIRS;
+char *http_method = NULL;
+char *http_post_data = NULL;
+char *http_content_type = NULL;
+CURL *curl;
+bool curl_global_initialized = false;
+bool curl_easy_initialized = false;
+struct curl_slist *header_list = NULL;
+bool body_buf_initialized = false;
+curlhelp_write_curlbuf body_buf;
+bool header_buf_initialized = false;
+curlhelp_write_curlbuf header_buf;
+bool status_line_initialized = false;
+curlhelp_statusline status_line;
+bool put_buf_initialized = false;
+curlhelp_read_curlbuf put_buf;
+char http_header[DEFAULT_BUFFER_SIZE];
+long code;
+long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
+double total_time;
+double time_connect;
+double time_appconnect;
+double time_headers;
+double time_firstbyte;
+char errbuf[MAX_INPUT_BUFFER];
+CURLcode res;
+char url[DEFAULT_BUFFER_SIZE];
+char msg[DEFAULT_BUFFER_SIZE];
+char perfstring[DEFAULT_BUFFER_SIZE];
+char header_expect[MAX_INPUT_BUFFER] = "";
+char string_expect[MAX_INPUT_BUFFER] = "";
+char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
+int server_expect_yn = 0;
+char user_auth[MAX_INPUT_BUFFER] = "";
+char proxy_auth[MAX_INPUT_BUFFER] = "";
+char **http_opt_headers;
+int http_opt_headers_count = 0;
+bool display_html = false;
+int onredirect = STATE_OK;
+int followmethod = FOLLOW_HTTP_CURL;
+int followsticky = STICKY_NONE;
+bool use_ssl = false;
+bool use_sni = true;
+bool check_cert = false;
+bool continue_after_check_cert = false;
+typedef union {
+ struct curl_slist* to_info;
+ struct curl_certinfo* to_certinfo;
+} cert_ptr_union;
+cert_ptr_union cert_ptr;
+int ssl_version = CURL_SSLVERSION_DEFAULT;
+char *client_cert = NULL;
+char *client_privkey = NULL;
+char *ca_cert = NULL;
+bool verify_peer_and_host = false;
+bool is_openssl_callback = false;
+#if defined(HAVE_SSL) && defined(USE_OPENSSL)
+X509 *cert = NULL;
+#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
+bool no_body = false;
+int maximum_age = -1;
+int address_family = AF_UNSPEC;
+curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
+int curl_http_version = CURL_HTTP_VERSION_NONE;
+bool automatic_decompression = false;
+char *cookie_jar_file = NULL;
+
+bool process_arguments (int, char**);
+void handle_curl_option_return_code (CURLcode res, const char* option);
+int check_http (void);
+void redir (curlhelp_write_curlbuf*);
+char *perfd_time (double microsec);
+char *perfd_time_connect (double microsec);
+char *perfd_time_ssl (double microsec);
+char *perfd_time_firstbyte (double microsec);
+char *perfd_time_headers (double microsec);
+char *perfd_time_transfer (double microsec);
+char *perfd_size (int page_len);
+void print_help (void);
+void print_usage (void);
+void print_curl_version (void);
+int curlhelp_initwritebuffer (curlhelp_write_curlbuf*);
+size_t curlhelp_buffer_write_callback(void*, size_t , size_t , void*);
+void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
+int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
+size_t curlhelp_buffer_read_callback(void *, size_t , size_t , void *);
+void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
+curlhelp_ssl_library curlhelp_get_ssl_library ();
+const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library);
+int net_noopenssl_check_certificate (cert_ptr_union*, int, int);
+
+int curlhelp_parse_statusline (const char*, curlhelp_statusline *);
+void curlhelp_free_statusline (curlhelp_statusline *);
+char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header);
+int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]);
+int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf);
+
+#if defined(HAVE_SSL) && defined(USE_OPENSSL)
+int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
+#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
+
+void remove_newlines (char *);
+void test_file (char *);
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts (&argc, argv, progname);
+
+ /* set defaults */
+ snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
+ progname, NP_VERSION, VERSION, curl_version());
+
+ /* parse arguments */
+ if (process_arguments (argc, argv) == false)
+ usage4 (_("Could not parse arguments"));
+
+ if (display_html)
+ printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
+ use_ssl ? "https" : "http",
+ host_name ? host_name : server_address,
+ virtual_port ? virtual_port : server_port,
+ server_url);
+
+ result = check_http ();
+ return result;
+}
+
+#ifdef HAVE_SSL
+#ifdef USE_OPENSSL
+
+int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ (void) preverify_ok;
+ /* TODO: we get all certificates of the chain, so which ones
+ * should we test?
+ * TODO: is the last certificate always the server certificate?
+ */
+ cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ X509_up_ref(cert);
+#endif
+ if (verbose>=2) {
+ puts("* SSL verify callback with certificate:");
+ X509_NAME *subject, *issuer;
+ printf("* issuer:\n");
+ issuer = X509_get_issuer_name( cert );
+ X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
+ printf("* curl verify_callback:\n* subject:\n");
+ subject = X509_get_subject_name( cert );
+ X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
+ puts("");
+ }
+ return 1;
+}
+
+CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm)
+{
+ (void) curl; // ignore unused parameter
+ (void) parm; // ignore unused parameter
+ SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
+
+ return CURLE_OK;
+}
+
+#endif /* USE_OPENSSL */
+#endif /* HAVE_SSL */
+
+/* returns a string "HTTP/1.x" or "HTTP/2" */
+static char *string_statuscode (int major, int minor)
+{
+ static char buf[10];
+
+ switch (major) {
+ case 1:
+ snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor);
+ break;
+ case 2:
+ case 3:
+ snprintf (buf, sizeof (buf), "HTTP/%d", major);
+ break;
+ default:
+ /* assuming here HTTP/N with N>=4 */
+ snprintf (buf, sizeof (buf), "HTTP/%d", major);
+ break;
+ }
+
+ return buf;
+}
+
+/* Checks if the server 'reply' is one of the expected 'statuscodes' */
+static int
+expected_statuscode (const char *reply, const char *statuscodes)
+{
+ char *expected, *code;
+ int result = 0;
+
+ if ((expected = strdup (statuscodes)) == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
+
+ for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
+ if (strstr (reply, code) != NULL) {
+ result = 1;
+ break;
+ }
+
+ free (expected);
+ return result;
+}
+
+void
+handle_curl_option_return_code (CURLcode res, const char* option)
+{
+ if (res != CURLE_OK) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Error while setting cURL option '%s': cURL returned %d - %s"),
+ option,
+ res,
+ curl_easy_strerror(res));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+}
+
+int
+lookup_host (const char *host, char *buf, size_t buflen)
+{
+ struct addrinfo hints, *res, *result;
+ char addrstr[100];
+ size_t addrstr_len;
+ int errcode;
+ void *ptr;
+ size_t buflen_remaining = buflen - 1;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = address_family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags |= AI_CANONNAME;
+
+ errcode = getaddrinfo (host, NULL, &hints, &result);
+ if (errcode != 0)
+ return errcode;
+
+ strcpy(buf, "");
+ res = result;
+
+ while (res) {
+ switch (res->ai_family) {
+ case AF_INET:
+ ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
+ break;
+ case AF_INET6:
+ ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+ break;
+ }
+
+ inet_ntop (res->ai_family, ptr, addrstr, 100);
+ if (verbose >= 1) {
+ printf ("* getaddrinfo IPv%d address: %s\n",
+ res->ai_family == PF_INET6 ? 6 : 4, addrstr);
+ }
+
+ // Append all IPs to buf as a comma-separated string
+ addrstr_len = strlen(addrstr);
+ if (buflen_remaining > addrstr_len + 1) {
+ if (buf[0] != '\0') {
+ strncat(buf, ",", buflen_remaining);
+ buflen_remaining -= 1;
+ }
+ strncat(buf, addrstr, buflen_remaining);
+ buflen_remaining -= addrstr_len;
+ }
+
+ res = res->ai_next;
+ }
+
+ freeaddrinfo(result);
+
+ return 0;
+}
+
+static void
+cleanup (void)
+{
+ if (status_line_initialized) curlhelp_free_statusline(&status_line);
+ status_line_initialized = false;
+ if (curl_easy_initialized) curl_easy_cleanup (curl);
+ curl_easy_initialized = false;
+ if (curl_global_initialized) curl_global_cleanup ();
+ curl_global_initialized = false;
+ if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf);
+ body_buf_initialized = false;
+ if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf);
+ header_buf_initialized = false;
+ if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf);
+ put_buf_initialized = false;
+}
+
+int
+check_http (void)
+{
+ int result = STATE_OK;
+ int page_len = 0;
+ int i;
+ char *force_host_header = NULL;
+ struct curl_slist *host = NULL;
+ char addrstr[DEFAULT_BUFFER_SIZE/2];
+ char dnscache[DEFAULT_BUFFER_SIZE];
+
+ /* initialize curl */
+ if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
+ die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
+ curl_global_initialized = true;
+
+ if ((curl = curl_easy_init()) == NULL) {
+ die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
+ }
+ curl_easy_initialized = true;
+
+ /* register cleanup function to shut down libcurl properly */
+ atexit (cleanup);
+
+ if (verbose >= 1)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
+
+ /* print everything on stdout like check_http would do */
+ handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
+
+ if (automatic_decompression)
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
+ handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
+#else
+ handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
+
+ /* initialize buffer for body of the answer */
+ if (curlhelp_initwritebuffer(&body_buf) < 0)
+ die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
+ body_buf_initialized = true;
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
+
+ /* initialize buffer for header of the answer */
+ if (curlhelp_initwritebuffer( &header_buf ) < 0)
+ die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
+ header_buf_initialized = true;
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
+
+ /* set the error buffer */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
+
+ /* set timeouts */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
+
+ // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy
+ if(use_ssl && host_name != NULL) {
+ if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
+ server_address,
+ res,
+ gai_strerror (res));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+ snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
+ host = curl_slist_append(NULL, dnscache);
+ curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
+ if (verbose>=1)
+ printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache);
+ }
+
+ // If server_address is an IPv6 address it must be surround by square brackets
+ struct in6_addr tmp_in_addr;
+ if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
+ char *new_server_address = malloc(strlen(server_address) + 3);
+ if (new_server_address == NULL) {
+ die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
+ }
+ snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address);
+ free(server_address);
+ server_address = new_server_address;
+ }
+
+ /* compose URL: use the address we want to connect to, set Host: header later */
+ snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s",
+ use_ssl ? "https" : "http",
+ ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address,
+ server_port,
+ server_url
+ );
+
+ if (verbose>=1)
+ printf ("* curl CURLOPT_URL: %s\n", url);
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL");
+
+ /* extract proxy information for legacy proxy https requests */
+ if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
+ if (verbose>=2)
+ printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
+ http_method = "GET";
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL");
+ }
+
+ /* disable body for HEAD request */
+ if (http_method && !strcmp (http_method, "HEAD" )) {
+ no_body = true;
+ }
+
+ /* set HTTP protocol version */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
+
+ /* set HTTP method */
+ if (http_method) {
+ if (!strcmp(http_method, "POST"))
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST");
+ else if (!strcmp(http_method, "PUT"))
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
+ else
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
+ }
+
+ /* check if Host header is explicitly set in options */
+ if (http_opt_headers_count) {
+ for (i = 0; i < http_opt_headers_count ; i++) {
+ if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
+ force_host_header = http_opt_headers[i];
+ }
+ }
+ }
+
+ /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
+ if(host_name != NULL && force_host_header == NULL) {
+ if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
+ snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
+ } else {
+ snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
+ }
+ header_list = curl_slist_append (header_list, http_header);
+ }
+
+ /* always close connection, be nice to servers */
+ snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
+ header_list = curl_slist_append (header_list, http_header);
+
+ /* attach additional headers supplied by the user */
+ /* optionally send any other header tag */
+ if (http_opt_headers_count) {
+ for (i = 0; i < http_opt_headers_count ; i++) {
+ header_list = curl_slist_append (header_list, http_opt_headers[i]);
+ }
+ /* This cannot be free'd here because a redirection will then try to access this and segfault */
+ /* Covered in a testcase in tests/check_http.t */
+ /* free(http_opt_headers); */
+ }
+
+ /* set HTTP headers */
+ handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
+
+#ifdef LIBCURL_FEATURE_SSL
+
+ /* set SSL version, warn about insecure or unsupported versions */
+ if (use_ssl) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
+ }
+
+ /* client certificate and key to present to server (SSL) */
+ if (client_cert)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
+ if (client_privkey)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
+ if (ca_cert) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
+ }
+ if (ca_cert || verify_peer_and_host) {
+ /* per default if we have a CA verify both the peer and the
+ * hostname in the certificate, can be switched off later */
+ handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
+ handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
+ } else {
+ /* backward-compatible behaviour, be tolerant in checks
+ * TODO: depending on more options have aspects we want
+ * to be less tolerant about ssl verfications
+ */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
+ }
+
+ /* detect SSL library used by libcurl */
+ ssl_library = curlhelp_get_ssl_library ();
+
+ /* try hard to get a stack of certificates to verify against */
+ if (check_cert) {
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
+ /* inform curl to report back certificates */
+ switch (ssl_library) {
+ case CURLHELP_SSL_LIBRARY_OPENSSL:
+ case CURLHELP_SSL_LIBRARY_LIBRESSL:
+ /* set callback to extract certificate with OpenSSL context function (works with
+ * OpenSSL-style libraries only!) */
+#ifdef USE_OPENSSL
+ /* libcurl and monitoring plugins built with OpenSSL, good */
+ handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
+ is_openssl_callback = true;
+#else /* USE_OPENSSL */
+#endif /* USE_OPENSSL */
+ /* libcurl is built with OpenSSL, monitoring plugins, so falling
+ * back to manually extracting certificate information */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+ break;
+
+ case CURLHELP_SSL_LIBRARY_NSS:
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
+ /* NSS: support for CERTINFO is implemented since 7.34.0 */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
+ die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
+ break;
+
+ case CURLHELP_SSL_LIBRARY_GNUTLS:
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
+ /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
+ die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library));
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
+ break;
+
+ case CURLHELP_SSL_LIBRARY_UNKNOWN:
+ default:
+ die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library));
+ break;
+ }
+#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
+ /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
+ if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
+ handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
+ else
+ die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n");
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
+ }
+
+#endif /* LIBCURL_FEATURE_SSL */
+
+ /* set default or user-given user agent identification */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
+
+ /* proxy-authentication */
+ if (strcmp(proxy_auth, ""))
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
+
+ /* authentication */
+ if (strcmp(user_auth, ""))
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
+
+ /* TODO: parameter auth method, bitfield of following methods:
+ * CURLAUTH_BASIC (default)
+ * CURLAUTH_DIGEST
+ * CURLAUTH_DIGEST_IE
+ * CURLAUTH_NEGOTIATE
+ * CURLAUTH_NTLM
+ * CURLAUTH_NTLM_WB
+ *
+ * convenience tokens for typical sets of methods:
+ * CURLAUTH_ANYSAFE: most secure, without BASIC
+ * or CURLAUTH_ANY: most secure, even BASIC if necessary
+ *
+ * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
+ */
+
+ /* handle redirections */
+ if (onredirect == STATE_DEPENDENT) {
+ if( followmethod == FOLLOW_LIBCURL ) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
+
+ /* default -1 is infinite, not good, could lead to zombie plugins!
+ Setting it to one bigger than maximal limit to handle errors nicely below
+ */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS");
+
+ /* for now allow only http and https (we are a http(s) check plugin in the end) */
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR");
+#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS");
+#endif
+
+ /* TODO: handle the following aspects of redirection, make them
+ * command line options too later:
+ CURLOPT_POSTREDIR: method switch
+ CURLINFO_REDIRECT_URL: custom redirect option
+ CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
+ CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
+ */
+ } else {
+ /* old style redirection is handled below */
+ }
+ }
+
+ /* no-body */
+ if (no_body)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
+
+ /* IPv4 or IPv6 forced DNS resolution */
+ if (address_family == AF_UNSPEC)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
+ else if (address_family == AF_INET)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
+#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
+ else if (address_family == AF_INET6)
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
+#endif
+
+ /* either send http POST data (any data, not only POST)*/
+ if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) {
+ /* set content of payload for POST and PUT */
+ if (http_content_type) {
+ snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
+ header_list = curl_slist_append (header_list, http_header);
+ }
+ /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
+ * in case of no POST/PUT data */
+ if (!http_post_data)
+ http_post_data = "";
+ if (!strcmp(http_method, "POST")) {
+ /* POST method, set payload with CURLOPT_POSTFIELDS */
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
+ } else if (!strcmp(http_method, "PUT")) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION");
+ if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0)
+ die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
+ put_buf_initialized = true;
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE");
+ }
+ }
+
+ /* cookie handling */
+ if (cookie_jar_file != NULL) {
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
+ handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
+ }
+
+ /* do the request */
+ res = curl_easy_perform(curl);
+
+ if (verbose>=2 && http_post_data)
+ printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data);
+
+ /* free header and server IP resolve lists, we don't need it anymore */
+ curl_slist_free_all (header_list); header_list = NULL;
+ curl_slist_free_all (server_ips); server_ips = NULL;
+ if (host) {
+ curl_slist_free_all (host); host = NULL;
+ }
+
+ /* Curl errors, result in critical Nagios state */
+ if (res != CURLE_OK) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
+ server_port,
+ res,
+ errbuf[0] ? errbuf : curl_easy_strerror(res));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+
+ /* certificate checks */
+#ifdef LIBCURL_FEATURE_SSL
+ if (use_ssl) {
+ if (check_cert) {
+ if (is_openssl_callback) {
+#ifdef USE_OPENSSL
+ /* check certificate with OpenSSL functions, curl has been built against OpenSSL
+ * and we actually have OpenSSL in the monitoring tools
+ */
+ result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
+ if (!continue_after_check_cert) {
+ return result;
+ }
+#else /* USE_OPENSSL */
+ die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
+#endif /* USE_OPENSSL */
+ } else {
+ int i;
+ struct curl_slist *slist;
+
+ cert_ptr.to_info = NULL;
+ res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
+ if (!res && cert_ptr.to_info) {
+#ifdef USE_OPENSSL
+ /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
+ * We only check the first certificate and assume it's the one of the server
+ */
+ const char* raw_cert = NULL;
+ for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
+ for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
+ if (verbose >= 2)
+ printf ("%d ** %s\n", i, slist->data);
+ if (strncmp (slist->data, "Cert:", 5) == 0) {
+ raw_cert = &slist->data[5];
+ goto GOT_FIRST_CERT;
+ }
+ }
+ }
+GOT_FIRST_CERT:
+ if (!raw_cert) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+ BIO* cert_BIO = BIO_new (BIO_s_mem());
+ BIO_write (cert_BIO, raw_cert, strlen(raw_cert));
+ cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL);
+ if (!cert) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Cannot read certificate from CERTINFO information - BIO error"));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+ BIO_free (cert_BIO);
+ result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
+ if (!continue_after_check_cert) {
+ return result;
+ }
+#else /* USE_OPENSSL */
+ /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
+ * so we use the libcurl CURLINFO data
+ */
+ result = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
+ if (!continue_after_check_cert) {
+ return result;
+ }
+#endif /* USE_OPENSSL */
+ } else {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Cannot retrieve certificates - cURL returned %d - %s"),
+ res,
+ curl_easy_strerror(res));
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+ }
+ }
+ }
+#endif /* LIBCURL_FEATURE_SSL */
+
+ /* we got the data and we executed the request in a given time, so we can append
+ * performance data to the answer always
+ */
+ handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
+ page_len = get_content_length(&header_buf, &body_buf);
+ if(show_extended_perfdata) {
+ handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
+ handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
+ handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
+ handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME");
+ snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
+ perfd_time(total_time),
+ perfd_size(page_len),
+ perfd_time_connect(time_connect),
+ use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "",
+ perfd_time_headers(time_headers - time_appconnect),
+ perfd_time_firstbyte(time_firstbyte - time_headers),
+ perfd_time_transfer(total_time-time_firstbyte)
+ );
+ } else {
+ snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
+ perfd_time(total_time),
+ perfd_size(page_len)
+ );
+ }
+
+ /* return a CRITICAL status if we couldn't read any data */
+ if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
+ die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
+
+ /* get status line of answer, check sanity of HTTP code */
+ if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
+ snprintf (msg,
+ DEFAULT_BUFFER_SIZE,
+ "Unparsable status line in %.3g seconds response time|%s\n",
+ total_time,
+ perfstring);
+ /* we cannot know the major/minor version here for sure as we cannot parse the first line */
+ die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
+ }
+ status_line_initialized = true;
+
+ /* get result code from cURL */
+ handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
+ if (verbose>=2)
+ printf ("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
+
+ /* print status line, header, body if verbose */
+ if (verbose >= 2) {
+ printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf,
+ (no_body ? " [[ skipped ]]" : body_buf.buf));
+ }
+
+ /* make sure the status line matches the response we are looking for */
+ if (!expected_statuscode(status_line.first_line, server_expect)) {
+ if (server_port == HTTP_PORT)
+ snprintf(msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Invalid HTTP response received from host: %s\n"),
+ status_line.first_line);
+ else
+ snprintf(msg,
+ DEFAULT_BUFFER_SIZE,
+ _("Invalid HTTP response received from host on port %d: %s\n"),
+ server_port,
+ status_line.first_line);
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
+ show_body ? "\n" : "",
+ show_body ? body_buf.buf : "");
+ }
+
+ if( server_expect_yn ) {
+ snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
+ if (verbose)
+ printf ("%s\n",msg);
+ result = STATE_OK;
+ }
+ else {
+ /* illegal return codes result in a critical state */
+ if (code >= 600 || code < 100) {
+ die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
+ /* server errors result in a critical state */
+ } else if (code >= 500) {
+ result = STATE_CRITICAL;
+ /* client errors result in a warning state */
+ } else if (code >= 400) {
+ result = STATE_WARNING;
+ /* check redirected page if specified */
+ } else if (code >= 300) {
+ if (onredirect == STATE_DEPENDENT) {
+ if( followmethod == FOLLOW_LIBCURL ) {
+ code = status_line.http_code;
+ } else {
+ /* old check_http style redirection, if we come
+ * back here, we are in the same status as with
+ * the libcurl method
+ */
+ redir (&header_buf);
+ }
+ } else {
+ /* this is a specific code in the command line to
+ * be returned when a redirection is encountered
+ */
+ }
+ result = max_state_alt (onredirect, result);
+ /* all other codes are considered ok */
+ } else {
+ result = STATE_OK;
+ }
+ }
+
+ /* libcurl redirection internally, handle error states here */
+ if( followmethod == FOLLOW_LIBCURL ) {
+ handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
+ if (verbose >= 2)
+ printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
+ if (redir_depth > max_depth) {
+ snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
+ max_depth);
+ die (STATE_WARNING, "HTTP WARNING - %s", msg);
+ }
+ }
+
+ /* check status codes, set exit status accordingly */
+ if( status_line.http_code != code ) {
+ die (STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
+ string_statuscode (status_line.http_major, status_line.http_minor),
+ status_line.http_code, status_line.msg, code);
+ }
+
+ if (maximum_age >= 0) {
+ result = max_state_alt(check_document_dates(&header_buf, &msg), result);
+ }
+
+ /* Page and Header content checks go here */
+
+ if (strlen (header_expect)) {
+ if (!strstr (header_buf.buf, header_expect)) {
+
+ strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
+
+ if(output_header_search[sizeof(output_header_search)-1]!='\0') {
+ bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
+ }
+
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp,
+ DEFAULT_BUFFER_SIZE,
+ _("%sheader '%s' not found on '%s://%s:%d%s', "),
+ msg,
+ output_header_search,
+ use_ssl ? "https" : "http",
+ host_name ? host_name : server_address,
+ server_port,
+ server_url);
+
+ strcpy(msg, tmp);
+
+ result = STATE_CRITICAL;
+ }
+ }
+
+ if (strlen (string_expect)) {
+ if (!strstr (body_buf.buf, string_expect)) {
+
+ strncpy(&output_string_search[0],string_expect,sizeof(output_string_search));
+
+ if(output_string_search[sizeof(output_string_search)-1]!='\0') {
+ bcopy("...",&output_string_search[sizeof(output_string_search)-4],4);
+ }
+
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp,
+ DEFAULT_BUFFER_SIZE,
+ _("%sstring '%s' not found on '%s://%s:%d%s', "),
+ msg,
+ output_string_search,
+ use_ssl ? "https" : "http",
+ host_name ? host_name : server_address,
+ server_port,
+ server_url);
+
+ strcpy(msg, tmp);
+
+ result = STATE_CRITICAL;
+ }
+ }
+
+ if (strlen (regexp)) {
+ errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0);
+ if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
+ /* OK - No-op to avoid changing the logic around it */
+ result = max_state_alt(STATE_OK, result);
+ }
+ else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
+ if (!invert_regex) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
+ strcpy(msg, tmp);
+
+ } else {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
+ strcpy(msg, tmp);
+
+ }
+ result = STATE_CRITICAL;
+ } else {
+ regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
+ strcpy(msg, tmp);
+ result = STATE_UNKNOWN;
+ }
+ }
+
+ /* make sure the page is of an appropriate size */
+ if ((max_page_len > 0) && (page_len > max_page_len)) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
+
+ strcpy(msg, tmp);
+
+ result = max_state_alt(STATE_WARNING, result);
+
+ } else if ((min_page_len > 0) && (page_len < min_page_len)) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
+ strcpy(msg, tmp);
+ result = max_state_alt(STATE_WARNING, result);
+ }
+
+ /* -w, -c: check warning and critical level */
+ result = max_state_alt(get_status(total_time, thlds), result);
+
+ /* Cut-off trailing characters */
+ if (strlen(msg) >= 2) {
+ if(msg[strlen(msg)-2] == ',')
+ msg[strlen(msg)-2] = '\0';
+ else
+ msg[strlen(msg)-3] = '\0';
+ }
+
+ /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
+ die (result, "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s",
+ state_text(result), string_statuscode (status_line.http_major, status_line.http_minor),
+ status_line.http_code, status_line.msg,
+ strlen(msg) > 0 ? " - " : "",
+ msg, page_len, total_time,
+ (display_html ? "</A>" : ""),
+ perfstring,
+ (show_body ? body_buf.buf : ""),
+ (show_body ? "\n" : "") );
+
+ return result;
+}
+
+int
+uri_strcmp (const UriTextRangeA range, const char* s)
+{
+ if (!range.first) return -1;
+ if (range.afterLast - range.first < strlen (s)) return -1;
+ return strncmp (s, range.first, min( range.afterLast - range.first, strlen (s)));
+}
+
+char*
+uri_string (const UriTextRangeA range, char* buf, size_t buflen)
+{
+ if (!range.first) return "(null)";
+ strncpy (buf, range.first, max (buflen-1, range.afterLast - range.first));
+ buf[max (buflen-1, range.afterLast - range.first)] = '\0';
+ buf[range.afterLast - range.first] = '\0';
+ return buf;
+}
+
+void
+redir (curlhelp_write_curlbuf* header_buf)
+{
+ char *location = NULL;
+ curlhelp_statusline status_line;
+ struct phr_header headers[255];
+ size_t nof_headers = 255;
+ size_t msglen;
+ char buf[DEFAULT_BUFFER_SIZE];
+ char ipstr[INET_ADDR_MAX_SIZE];
+ int new_port;
+ char *new_host;
+ char *new_url;
+
+ int res = phr_parse_response (header_buf->buf, header_buf->buflen,
+ &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
+ headers, &nof_headers, 0);
+
+ if (res == -1) {
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
+ }
+
+ location = get_header_value (headers, nof_headers, "location");
+
+ if (verbose >= 2)
+ printf(_("* Seen redirect location %s\n"), location);
+
+ if (++redir_depth > max_depth)
+ die (STATE_WARNING,
+ _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"),
+ max_depth, location, (display_html ? "</A>" : ""));
+
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+ if (uriParseUriA (&state, location) != URI_SUCCESS) {
+ if (state.errorCode == URI_ERROR_SYNTAX) {
+ die (STATE_UNKNOWN,
+ _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"),
+ location, (display_html ? "</A>" : ""));
+ } else if (state.errorCode == URI_ERROR_MALLOC) {
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
+ }
+ }
+
+ if (verbose >= 2) {
+ printf (_("** scheme: %s\n"),
+ uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE));
+ printf (_("** host: %s\n"),
+ uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
+ printf (_("** port: %s\n"),
+ uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
+ if (uri.hostData.ip4) {
+ inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr));
+ printf (_("** IPv4: %s\n"), ipstr);
+ }
+ if (uri.hostData.ip6) {
+ inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr));
+ printf (_("** IPv6: %s\n"), ipstr);
+ }
+ if (uri.pathHead) {
+ printf (_("** path: "));
+ const UriPathSegmentA* p = uri.pathHead;
+ for (; p; p = p->next) {
+ printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE));
+ }
+ puts ("");
+ }
+ if (uri.query.first) {
+ printf (_("** query: %s\n"),
+ uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE));
+ }
+ if (uri.fragment.first) {
+ printf (_("** fragment: %s\n"),
+ uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE));
+ }
+ }
+
+ if (!uri_strcmp (uri.scheme, "https"))
+ use_ssl = true;
+ else
+ use_ssl = false;
+
+ /* we do a sloppy test here only, because uriparser would have failed
+ * above, if the port would be invalid, we just check for MAX_PORT
+ */
+ if (uri.portText.first) {
+ new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
+ } else {
+ new_port = HTTP_PORT;
+ if (use_ssl)
+ new_port = HTTPS_PORT;
+ }
+ if (new_port > MAX_PORT)
+ die (STATE_UNKNOWN,
+ _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"),
+ MAX_PORT, location, display_html ? "</A>" : "");
+
+ /* by RFC 7231 relative URLs in Location should be taken relative to
+ * the original URL, so wy try to form a new absolute URL here
+ */
+ if (!uri.scheme.first && !uri.hostText.first) {
+ new_host = strdup (host_name ? host_name : server_address);
+ } else {
+ new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
+ }
+
+ /* compose new path */
+ /* TODO: handle fragments and query part of URL */
+ new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE);
+ if (uri.pathHead) {
+ const UriPathSegmentA* p = uri.pathHead;
+ for (; p; p = p->next) {
+ strncat (new_url, "/", DEFAULT_BUFFER_SIZE);
+ strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1);
+ }
+ }
+
+ if (server_port==new_port &&
+ !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
+ (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
+ !strcmp(server_url, new_url))
+ die (STATE_CRITICAL,
+ _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
+ use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : ""));
+
+ /* set new values for redirected request */
+
+ if (!(followsticky & STICKY_HOST)) {
+ free (server_address);
+ server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH);
+ }
+ if (!(followsticky & STICKY_PORT)) {
+ server_port = (unsigned short)new_port;
+ }
+
+ free (host_name);
+ host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH);
+
+ /* reset virtual port */
+ virtual_port = server_port;
+
+ free(new_host);
+ free (server_url);
+ server_url = new_url;
+
+ uriFreeUriMembersA (&uri);
+
+ if (verbose)
+ printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http",
+ host_name ? host_name : server_address, server_port, server_url);
+
+ /* TODO: the hash component MUST be taken from the original URL and
+ * attached to the URL in Location
+ */
+
+ cleanup ();
+ check_http ();
+}
+
+/* check whether a file exists */
+void
+test_file (char *path)
+{
+ if (access(path, R_OK) == 0)
+ return;
+ usage2 (_("file does not exist or is not readable"), path);
+}
+
+bool
+process_arguments (int argc, char **argv)
+{
+ char *p;
+ int c = 1;
+ char *temp;
+
+ enum {
+ INVERT_REGEX = CHAR_MAX + 1,
+ SNI_OPTION,
+ MAX_REDIRS_OPTION,
+ CONTINUE_AFTER_CHECK_CERT,
+ CA_CERT_OPTION,
+ HTTP_VERSION_OPTION,
+ AUTOMATIC_DECOMPRESSION,
+ COOKIE_JAR
+ };
+
+ int option = 0;
+ int got_plus = 0;
+ static struct option longopts[] = {
+ STD_LONG_OPTS,
+ {"link", no_argument, 0, 'L'},
+ {"nohtml", no_argument, 0, 'n'},
+ {"ssl", optional_argument, 0, 'S'},
+ {"sni", no_argument, 0, SNI_OPTION},
+ {"post", required_argument, 0, 'P'},
+ {"method", required_argument, 0, 'j'},
+ {"IP-address", required_argument, 0, 'I'},
+ {"url", required_argument, 0, 'u'},
+ {"port", required_argument, 0, 'p'},
+ {"authorization", required_argument, 0, 'a'},
+ {"proxy-authorization", required_argument, 0, 'b'},
+ {"header-string", required_argument, 0, 'd'},
+ {"string", required_argument, 0, 's'},
+ {"expect", required_argument, 0, 'e'},
+ {"regex", required_argument, 0, 'r'},
+ {"ereg", required_argument, 0, 'r'},
+ {"eregi", required_argument, 0, 'R'},
+ {"linespan", no_argument, 0, 'l'},
+ {"onredirect", required_argument, 0, 'f'},
+ {"certificate", required_argument, 0, 'C'},
+ {"client-cert", required_argument, 0, 'J'},
+ {"private-key", required_argument, 0, 'K'},
+ {"ca-cert", required_argument, 0, CA_CERT_OPTION},
+ {"verify-cert", no_argument, 0, 'D'},
+ {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
+ {"useragent", required_argument, 0, 'A'},
+ {"header", required_argument, 0, 'k'},
+ {"no-body", no_argument, 0, 'N'},
+ {"max-age", required_argument, 0, 'M'},
+ {"content-type", required_argument, 0, 'T'},
+ {"pagesize", required_argument, 0, 'm'},
+ {"invert-regex", no_argument, NULL, INVERT_REGEX},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"extended-perfdata", no_argument, 0, 'E'},
+ {"show-body", no_argument, 0, 'B'},
+ {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
+ {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
+ {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
+ {"cookie-jar", required_argument, 0, COOKIE_JAR},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return false;
+
+ /* support check_http compatible arguments */
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ if (strcmp ("-hn", argv[c]) == 0)
+ strcpy (argv[c], "-H");
+ if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ if (strcmp ("-nohtml", argv[c]) == 0)
+ strcpy (argv[c], "-n");
+ }
+
+ server_url = strdup(DEFAULT_SERVER_URL);
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option);
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(STATE_UNKNOWN);
+ break;
+ case 'V':
+ print_revision(progname, NP_VERSION);
+ print_curl_version();
+ exit(STATE_UNKNOWN);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 't': /* timeout period */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ socket_timeout = (int)strtol (optarg, NULL, 10);
+ break;
+ case 'c': /* critical time threshold */
+ critical_thresholds = optarg;
+ break;
+ case 'w': /* warning time threshold */
+ warning_thresholds = optarg;
+ break;
+ case 'H': /* virtual host */
+ host_name = strdup (optarg);
+ if (host_name[0] == '[') {
+ if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */
+ virtual_port = atoi (p + 2);
+ /* cut off the port */
+ host_name_length = strlen (host_name) - strlen (p) - 1;
+ free (host_name);
+ host_name = strndup (optarg, host_name_length);
+ }
+ } else if ((p = strchr (host_name, ':')) != NULL
+ && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */
+ virtual_port = atoi (p);
+ /* cut off the port */
+ host_name_length = strlen (host_name) - strlen (p) - 1;
+ free (host_name);
+ host_name = strndup (optarg, host_name_length);
+ }
+ break;
+ case 'I': /* internet address */
+ server_address = strdup (optarg);
+ break;
+ case 'u': /* URL path */
+ server_url = strdup (optarg);
+ break;
+ case 'p': /* Server port */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid port number, expecting a non-negative number"), optarg);
+ else {
+ if( strtol(optarg, NULL, 10) > MAX_PORT)
+ usage2 (_("Invalid port number, supplied port number is too big"), optarg);
+ server_port = (unsigned short)strtol(optarg, NULL, 10);
+ specify_port = true;
+ }
+ break;
+ case 'a': /* authorization info */
+ strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
+ user_auth[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'b': /* proxy-authorization info */
+ strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
+ proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
+ if (! http_post_data)
+ http_post_data = strdup (optarg);
+ if (! http_method)
+ http_method = strdup("POST");
+ break;
+ case 'j': /* Set HTTP method */
+ if (http_method)
+ free(http_method);
+ http_method = strdup (optarg);
+ break;
+ case 'A': /* useragent */
+ strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE);
+ user_agent[DEFAULT_BUFFER_SIZE-1] = '\0';
+ break;
+ case 'k': /* Additional headers */
+ if (http_opt_headers_count == 0)
+ http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
+ else
+ http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
+ http_opt_headers[http_opt_headers_count - 1] = optarg;
+ break;
+ case 'L': /* show html link */
+ display_html = true;
+ break;
+ case 'n': /* do not show html link */
+ display_html = false;
+ break;
+ case 'C': /* Check SSL cert validity */
+#ifdef LIBCURL_FEATURE_SSL
+ if ((temp=strchr(optarg,','))!=NULL) {
+ *temp='\0';
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi(optarg);
+ *temp=',';
+ temp++;
+ if (!is_intnonneg (temp))
+ usage2 (_("Invalid certificate expiration period"), temp);
+ days_till_exp_crit = atoi (temp);
+ }
+ else {
+ days_till_exp_crit=0;
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi (optarg);
+ }
+ check_cert = true;
+ goto enable_ssl;
+#endif
+ case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
+#ifdef HAVE_SSL
+ continue_after_check_cert = true;
+ break;
+#endif
+ case 'J': /* use client certificate */
+#ifdef LIBCURL_FEATURE_SSL
+ test_file(optarg);
+ client_cert = optarg;
+ goto enable_ssl;
+#endif
+ case 'K': /* use client private key */
+#ifdef LIBCURL_FEATURE_SSL
+ test_file(optarg);
+ client_privkey = optarg;
+ goto enable_ssl;
+#endif
+#ifdef LIBCURL_FEATURE_SSL
+ case CA_CERT_OPTION: /* use CA chain file */
+ test_file(optarg);
+ ca_cert = optarg;
+ goto enable_ssl;
+#endif
+#ifdef LIBCURL_FEATURE_SSL
+ case 'D': /* verify peer certificate & host */
+ verify_peer_and_host = true;
+ break;
+#endif
+ case 'S': /* use SSL */
+#ifdef LIBCURL_FEATURE_SSL
+ enable_ssl:
+ use_ssl = true;
+ /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
+ * Only set if it's non-zero. This helps when we include multiple
+ * parameters, like -S and -C combinations */
+ ssl_version = CURL_SSLVERSION_DEFAULT;
+ if (c=='S' && optarg != NULL) {
+ char *plus_ptr = strchr(optarg, '+');
+ if (plus_ptr) {
+ got_plus = 1;
+ *plus_ptr = '\0';
+ }
+
+ if (optarg[0] == '2')
+ ssl_version = CURL_SSLVERSION_SSLv2;
+ else if (optarg[0] == '3')
+ ssl_version = CURL_SSLVERSION_SSLv3;
+ else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0"))
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+#else
+ ssl_version = CURL_SSLVERSION_DEFAULT;
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
+ else if (!strcmp (optarg, "1.1"))
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
+ ssl_version = CURL_SSLVERSION_TLSv1_1;
+#else
+ ssl_version = CURL_SSLVERSION_DEFAULT;
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
+ else if (!strcmp (optarg, "1.2"))
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
+ ssl_version = CURL_SSLVERSION_TLSv1_2;
+#else
+ ssl_version = CURL_SSLVERSION_DEFAULT;
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
+ else if (!strcmp (optarg, "1.3"))
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
+ ssl_version = CURL_SSLVERSION_TLSv1_3;
+#else
+ ssl_version = CURL_SSLVERSION_DEFAULT;
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
+ else
+ usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
+ }
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
+ if (got_plus) {
+ switch (ssl_version) {
+ case CURL_SSLVERSION_TLSv1_3:
+ ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_0:
+ ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
+ break;
+ }
+ } else {
+ switch (ssl_version) {
+ case CURL_SSLVERSION_TLSv1_3:
+ ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
+ break;
+ }
+ }
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
+ if (verbose >= 2)
+ printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
+ if (!specify_port)
+ server_port = HTTPS_PORT;
+ break;
+#else /* LIBCURL_FEATURE_SSL */
+ /* -C -J and -K fall through to here without SSL */
+ usage4 (_("Invalid option - SSL is not available"));
+ break;
+ case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
+ use_sni = true;
+ break;
+#endif /* LIBCURL_FEATURE_SSL */
+ case MAX_REDIRS_OPTION:
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid max_redirs count"), optarg);
+ else {
+ max_depth = atoi (optarg);
+ }
+ break;
+ case 'f': /* onredirect */
+ if (!strcmp (optarg, "ok"))
+ onredirect = STATE_OK;
+ else if (!strcmp (optarg, "warning"))
+ onredirect = STATE_WARNING;
+ else if (!strcmp (optarg, "critical"))
+ onredirect = STATE_CRITICAL;
+ else if (!strcmp (optarg, "unknown"))
+ onredirect = STATE_UNKNOWN;
+ else if (!strcmp (optarg, "follow"))
+ onredirect = STATE_DEPENDENT;
+ else if (!strcmp (optarg, "stickyport"))
+ onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT;
+ else if (!strcmp (optarg, "sticky"))
+ onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
+ else if (!strcmp (optarg, "follow"))
+ onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
+ else if (!strcmp (optarg, "curl"))
+ onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
+ else usage2 (_("Invalid onredirect option"), optarg);
+ if (verbose >= 2)
+ printf(_("* Following redirects set to %s\n"), state_text(onredirect));
+ break;
+ case 'd': /* string or substring */
+ strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1);
+ header_expect[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 's': /* string or substring */
+ strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
+ string_expect[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'e': /* string or substring */
+ strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
+ server_expect[MAX_INPUT_BUFFER - 1] = 0;
+ server_expect_yn = 1;
+ break;
+ case 'T': /* Content-type */
+ http_content_type = strdup (optarg);
+ break;
+ case 'l': /* linespan */
+ cflags &= ~REG_NEWLINE;
+ break;
+ case 'R': /* regex */
+ cflags |= REG_ICASE;
+ // fall through
+ case 'r': /* regex */
+ strncpy (regexp, optarg, MAX_RE_SIZE - 1);
+ regexp[MAX_RE_SIZE - 1] = 0;
+ errcode = regcomp (&preg, regexp, cflags);
+ if (errcode != 0) {
+ (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Could Not Compile Regular Expression: %s"), errbuf);
+ return false;
+ }
+ break;
+ case INVERT_REGEX:
+ invert_regex = true;
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case 'm': /* min_page_length */
+ {
+ char *tmp;
+ if (strchr(optarg, ':') != (char *)NULL) {
+ /* range, so get two values, min:max */
+ tmp = strtok(optarg, ":");
+ if (tmp == NULL) {
+ printf("Bad format: try \"-m min:max\"\n");
+ exit (STATE_WARNING);
+ } else
+ min_page_len = atoi(tmp);
+
+ tmp = strtok(NULL, ":");
+ if (tmp == NULL) {
+ printf("Bad format: try \"-m min:max\"\n");
+ exit (STATE_WARNING);
+ } else
+ max_page_len = atoi(tmp);
+ } else
+ min_page_len = atoi (optarg);
+ break;
+ }
+ case 'N': /* no-body */
+ no_body = true;
+ break;
+ case 'M': /* max-age */
+ {
+ int L = strlen(optarg);
+ if (L && optarg[L-1] == 'm')
+ maximum_age = atoi (optarg) * 60;
+ else if (L && optarg[L-1] == 'h')
+ maximum_age = atoi (optarg) * 60 * 60;
+ else if (L && optarg[L-1] == 'd')
+ maximum_age = atoi (optarg) * 60 * 60 * 24;
+ else if (L && (optarg[L-1] == 's' ||
+ isdigit (optarg[L-1])))
+ maximum_age = atoi (optarg);
+ else {
+ fprintf (stderr, "unparsable max-age: %s\n", optarg);
+ exit (STATE_WARNING);
+ }
+ if (verbose >= 2)
+ printf ("* Maximal age of document set to %d seconds\n", maximum_age);
+ }
+ break;
+ case 'E': /* show extended perfdata */
+ show_extended_perfdata = true;
+ break;
+ case 'B': /* print body content after status line */
+ show_body = true;
+ break;
+ case HTTP_VERSION_OPTION:
+ curl_http_version = CURL_HTTP_VERSION_NONE;
+ if (strcmp (optarg, "1.0") == 0) {
+ curl_http_version = CURL_HTTP_VERSION_1_0;
+ } else if (strcmp (optarg, "1.1") == 0) {
+ curl_http_version = CURL_HTTP_VERSION_1_1;
+ } else if ((strcmp (optarg, "2.0") == 0) || (strcmp (optarg, "2") == 0)) {
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
+ curl_http_version = CURL_HTTP_VERSION_2_0;
+#else
+ curl_http_version = CURL_HTTP_VERSION_NONE;
+#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
+ } else {
+ fprintf (stderr, "unknown http-version parameter: %s\n", optarg);
+ exit (STATE_WARNING);
+ }
+ break;
+ case AUTOMATIC_DECOMPRESSION:
+ automatic_decompression = true;
+ break;
+ case COOKIE_JAR:
+ cookie_jar_file = optarg;
+ break;
+ case '?':
+ /* print short usage statement if args not parsable */
+ usage5 ();
+ break;
+ }
+ }
+
+ c = optind;
+
+ if (server_address == NULL && c < argc)
+ server_address = strdup (argv[c++]);
+
+ if (host_name == NULL && c < argc)
+ host_name = strdup (argv[c++]);
+
+ if (server_address == NULL) {
+ if (host_name == NULL)
+ usage4 (_("You must specify a server address or host name"));
+ else
+ server_address = strdup (host_name);
+ }
+
+ set_thresholds(&thlds, warning_thresholds, critical_thresholds);
+
+ if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
+ socket_timeout = (int)thlds->critical->end + 1;
+ if (verbose >= 2)
+ printf ("* Socket timeout set to %ld seconds\n", socket_timeout);
+
+ if (http_method == NULL)
+ http_method = strdup ("GET");
+
+ if (client_cert && !client_privkey)
+ usage4 (_("If you use a client certificate you must also specify a private key file"));
+
+ if (virtual_port == 0)
+ virtual_port = server_port;
+ else {
+ if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
+ if(!specify_port)
+ server_port = virtual_port;
+ }
+
+ return true;
+}
+
+char *perfd_time (double elapsed_time)
+{
+ return fperfdata ("time", elapsed_time, "s",
+ thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
+ thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
+ true, 0, true, socket_timeout);
+}
+
+char *perfd_time_connect (double elapsed_time_connect)
+{
+ return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_ssl (double elapsed_time_ssl)
+{
+ return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_headers (double elapsed_time_headers)
+{
+ return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_firstbyte (double elapsed_time_firstbyte)
+{
+ return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_transfer (double elapsed_time_transfer)
+{
+ return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_size (int page_len)
+{
+ return perfdata ("size", page_len, "B",
+ (min_page_len>0?true:false), min_page_len,
+ (min_page_len>0?true:false), 0,
+ true, 0, false, 0);
+}
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
+ printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
+ printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
+ printf ("%s\n", _("certificate expiration times."));
+ printf ("\n");
+ printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
+ printf ("%s\n", _("as possible."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (_("NOTE: One or both of -H and -I must be specified"));
+
+ printf ("\n");
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-H, --hostname=ADDRESS");
+ printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
+ printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
+ printf (" %s\n", "-I, --IP-address=ADDRESS");
+ printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
+ printf (" %s\n", "-p, --port=INTEGER");
+ printf (" %s", _("Port number (default: "));
+ printf ("%d)\n", HTTP_PORT);
+
+ printf (UT_IPv46);
+
+#ifdef LIBCURL_FEATURE_SSL
+ printf (" %s\n", "-S, --ssl=VERSION[+]");
+ printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
+ printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
+ printf (" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted."));
+ printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl"));
+ printf (" %s\n", "--sni");
+ printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
+#if LIBCURL_VERSION_NUM >= 0x071801
+ printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
+ printf (" %s\n", _(" SNI only really works since TLSv1.0"));
+#else
+ printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
+#endif
+ printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
+ printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
+ printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
+ printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
+ printf (" %s\n", "--continue-after-certificate");
+ printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
+ printf (" %s\n", _("Does nothing unless -C is used."));
+ printf (" %s\n", "-J, --client-cert=FILE");
+ printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
+ printf (" %s\n", _("to be used in establishing the SSL session"));
+ printf (" %s\n", "-K, --private-key=FILE");
+ printf (" %s\n", _("Name of file containing the private key (PEM format)"));
+ printf (" %s\n", _("matching the client certificate"));
+ printf (" %s\n", "--ca-cert=FILE");
+ printf (" %s\n", _("CA certificate file to verify peer against"));
+ printf (" %s\n", "-D, --verify-cert");
+ printf (" %s\n", _("Verify the peer's SSL certificate and hostname"));
+#endif
+
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
+ printf (" %s", _("the first (status) line of the server response (default: "));
+ printf ("%s)\n", HTTP_EXPECT);
+ printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
+ printf (" %s\n", "-d, --header-string=STRING");
+ printf (" %s\n", _("String to expect in the response headers"));
+ printf (" %s\n", "-s, --string=STRING");
+ printf (" %s\n", _("String to expect in the content"));
+ printf (" %s\n", "-u, --url=PATH");
+ printf (" %s\n", _("URL to GET or POST (default: /)"));
+ printf (" %s\n", "-P, --post=STRING");
+ printf (" %s\n", _("URL encoded http POST data"));
+ printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
+ printf (" %s\n", _("Set HTTP method."));
+ printf (" %s\n", "-N, --no-body");
+ printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
+ printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
+ printf (" %s\n", "-M, --max-age=SECONDS");
+ printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
+ printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
+ printf (" %s\n", "-T, --content-type=STRING");
+ printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
+ printf (" %s\n", "-l, --linespan");
+ printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
+ printf (" %s\n", "-r, --regex, --ereg=STRING");
+ printf (" %s\n", _("Search page for regex STRING"));
+ printf (" %s\n", "-R, --eregi=STRING");
+ printf (" %s\n", _("Search page for case-insensitive regex STRING"));
+ printf (" %s\n", "--invert-regex");
+ printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
+ printf (" %s\n", "-a, --authorization=AUTH_PAIR");
+ printf (" %s\n", _("Username:password on sites with basic authentication"));
+ printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
+ printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
+ printf (" %s\n", "-A, --useragent=STRING");
+ printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
+ printf (" %s\n", "-k, --header=STRING");
+ printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
+ printf (" %s\n", "-E, --extended-perfdata");
+ printf (" %s\n", _("Print additional performance data"));
+ printf (" %s\n", "-B, --show-body");
+ printf (" %s\n", _("Print body content below status line"));
+ printf (" %s\n", "-L, --link");
+ printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
+ printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
+ printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
+ printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
+ printf (" %s\n", _("follow uses the old redirection algorithm of check_http."));
+ printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
+ printf (" %s\n", "--max-redirs=INTEGER");
+ printf (" %s", _("Maximal number of redirects (default: "));
+ printf ("%d)\n", DEFAULT_MAX_REDIRS);
+ printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
+ printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
+ printf ("\n");
+ printf (" %s\n", "--http-version=VERSION");
+ printf (" %s\n", _("Connect via specific HTTP protocol."));
+ printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
+ printf (" %s\n", "--enable-automatic-decompression");
+ printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
+ printf (" %s\n", "---cookie-jar=FILE");
+ printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
+ printf ("\n");
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
+ printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
+ printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
+ printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
+ printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
+ printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
+
+#ifdef LIBCURL_FEATURE_SSL
+ printf ("\n");
+ printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
+ printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
+ printf (" %s\n", _("certificate is still valid for the specified number of days."));
+ printf ("\n");
+ printf (" %s\n", _("Please note that this plugin does not check if the presented server"));
+ printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
+ printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
+ printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
+ printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
+ printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
+ printf (" %s\n", _("a STATE_CRITICAL will be returned."));
+ printf ("\n");
+ printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
+ printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
+ printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
+ printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
+ printf (" %s\n\n", _("the certificate is expired."));
+ printf ("\n");
+ printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
+ printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
+ printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
+ printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
+ printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
+#endif
+
+ printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
+ printf (" %s\n", _("It is recommended to use an environment proxy like:"));
+ printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
+ printf (" %s\n", _("legacy proxy requests in check_http style still work:"));
+ printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
+
+#ifdef LIBCURL_FEATURE_SSL
+ printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
+ printf (" %s\n", _("It is recommended to use an environment proxy like:"));
+ printf (" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
+ printf (" %s\n", _("legacy proxy requests in check_http style still work:"));
+ printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com "));
+ printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
+ printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
+ printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
+ printf (" %s\n", _("a STATE_CRITICAL will be returned."));
+
+#endif
+
+ printf (UT_SUPPORT);
+
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
+ printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
+ printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
+ printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
+ printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
+ printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
+ printf (" [-A string] [-k string] [-S <version>] [--sni]\n");
+ printf (" [-T <content-type>] [-j method]\n");
+ printf (" [--http-version=<version>] [--enable-automatic-decompression]\n");
+ printf (" [--cookie-jar=<cookie jar file>\n");
+ printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
+ printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
+ printf ("\n");
+#ifdef LIBCURL_FEATURE_SSL
+ printf ("%s\n", _("In the first form, make an HTTP request."));
+ printf ("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
+#endif
+ printf ("%s\n", _("WARNING: check_curl is experimental. Please use"));
+ printf ("%s\n\n", _("check_http if you need a stable version."));
+}
+
+void
+print_curl_version (void)
+{
+ printf( "%s\n", curl_version());
+}
+
+int
+curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf)
+{
+ buf->bufsize = DEFAULT_BUFFER_SIZE;
+ buf->buflen = 0;
+ buf->buf = (char *)malloc ((size_t)buf->bufsize);
+ if (buf->buf == NULL) return -1;
+ return 0;
+}
+
+size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream)
+{
+ curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
+
+ while (buf->bufsize < buf->buflen + size * nmemb + 1) {
+ buf->bufsize = buf->bufsize * 2;
+ buf->buf = (char *)realloc (buf->buf, buf->bufsize);
+ if (buf->buf == NULL) {
+ fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
+ return -1;
+ }
+ }
+
+ memcpy (buf->buf + buf->buflen, buffer, size * nmemb);
+ buf->buflen += size * nmemb;
+ buf->buf[buf->buflen] = '\0';
+
+ return (int)(size * nmemb);
+}
+
+size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream)
+{
+ curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
+
+ size_t n = min (nmemb * size, buf->buflen - buf->pos);
+
+ memcpy (buffer, buf->buf + buf->pos, n);
+ buf->pos += n;
+
+ return (int)n;
+}
+
+void
+curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf)
+{
+ free (buf->buf);
+ buf->buf = NULL;
+}
+
+int
+curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen)
+{
+ buf->buflen = datalen;
+ buf->buf = (char *)malloc ((size_t)buf->buflen);
+ if (buf->buf == NULL) return -1;
+ memcpy (buf->buf, data, datalen);
+ buf->pos = 0;
+ return 0;
+}
+
+void
+curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf)
+{
+ free (buf->buf);
+ buf->buf = NULL;
+}
+
+/* TODO: where to put this, it's actually part of sstrings2 (logically)?
+ */
+const char*
+strrstr2(const char *haystack, const char *needle)
+{
+ int counter;
+ size_t len;
+ const char *prev_pos;
+ const char *pos;
+
+ if (haystack == NULL || needle == NULL)
+ return NULL;
+
+ if (haystack[0] == '\0' || needle[0] == '\0')
+ return NULL;
+
+ counter = 0;
+ prev_pos = NULL;
+ pos = haystack;
+ len = strlen (needle);
+ for (;;) {
+ pos = strstr (pos, needle);
+ if (pos == NULL) {
+ if (counter == 0)
+ return NULL;
+ else
+ return prev_pos;
+ }
+ counter++;
+ prev_pos = pos;
+ pos += len;
+ if (*pos == '\0') return prev_pos;
+ }
+}
+
+int
+curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
+{
+ char *first_line_end;
+ char *p;
+ size_t first_line_len;
+ char *pp;
+ const char *start;
+ char *first_line_buf;
+
+ /* find last start of a new header */
+ start = strrstr2 (buf, "\r\nHTTP/");
+ if (start != NULL) {
+ start += 2;
+ buf = start;
+ }
+
+ first_line_end = strstr(buf, "\r\n");
+ if (first_line_end == NULL) return -1;
+
+ first_line_len = (size_t)(first_line_end - buf);
+ status_line->first_line = (char *)malloc (first_line_len + 1);
+ if (status_line->first_line == NULL) return -1;
+ memcpy (status_line->first_line, buf, first_line_len);
+ status_line->first_line[first_line_len] = '\0';
+ first_line_buf = strdup( status_line->first_line );
+
+ /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
+
+ p = strtok(first_line_buf, "/");
+ if( p == NULL ) { free( first_line_buf ); return -1; }
+ if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
+
+ p = strtok( NULL, " " );
+ if( p == NULL ) { free( first_line_buf ); return -1; }
+ if( strchr( p, '.' ) != NULL ) {
+
+ /* HTTP 1.x case */
+ strtok( p, "." );
+ status_line->http_major = (int)strtol( p, &pp, 10 );
+ if( *pp != '\0' ) { free( first_line_buf ); return -1; }
+ strtok( NULL, " " );
+ status_line->http_minor = (int)strtol( p, &pp, 10 );
+ if( *pp != '\0' ) { free( first_line_buf ); return -1; }
+ p += 4; /* 1.x SP */
+ } else {
+ /* HTTP 2 case */
+ status_line->http_major = (int)strtol( p, &pp, 10 );
+ status_line->http_minor = 0;
+ p += 2; /* 2 SP */
+ }
+
+ /* status code: "404" or "404.1", then SP */
+
+ p = strtok( p, " " );
+ if( p == NULL ) { free( first_line_buf ); return -1; }
+ if( strchr( p, '.' ) != NULL ) {
+ char *ppp;
+ ppp = strtok( p, "." );
+ status_line->http_code = (int)strtol( ppp, &pp, 10 );
+ if( *pp != '\0' ) { free( first_line_buf ); return -1; }
+ ppp = strtok( NULL, "" );
+ status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
+ if( *pp != '\0' ) { free( first_line_buf ); return -1; }
+ p += 6; /* 400.1 SP */
+ } else {
+ status_line->http_code = (int)strtol( p, &pp, 10 );
+ status_line->http_subcode = -1;
+ if( *pp != '\0' ) { free( first_line_buf ); return -1; }
+ p += 4; /* 400 SP */
+ }
+
+ /* Human readable message: "Not Found" CRLF */
+
+ p = strtok( p, "" );
+ if( p == NULL ) { status_line->msg = ""; return 0; }
+ status_line->msg = status_line->first_line + ( p - first_line_buf );
+ free( first_line_buf );
+
+ return 0;
+}
+
+void
+curlhelp_free_statusline (curlhelp_statusline *status_line)
+{
+ free (status_line->first_line);
+}
+
+void
+remove_newlines (char *s)
+{
+ char *p;
+
+ for (p = s; *p != '\0'; p++)
+ if (*p == '\r' || *p == '\n')
+ *p = ' ';
+}
+
+char *
+get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header)
+{
+ int i;
+ for( i = 0; i < nof_headers; i++ ) {
+ if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) {
+ return strndup( headers[i].value, headers[i].value_len );
+ }
+ }
+ return NULL;
+}
+
+int
+check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE])
+{
+ char *server_date = NULL;
+ char *document_date = NULL;
+ int date_result = STATE_OK;
+ curlhelp_statusline status_line;
+ struct phr_header headers[255];
+ size_t nof_headers = 255;
+ size_t msglen;
+
+ int res = phr_parse_response (header_buf->buf, header_buf->buflen,
+ &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
+ headers, &nof_headers, 0);
+
+ if (res == -1) {
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
+ }
+
+ server_date = get_header_value (headers, nof_headers, "date");
+ document_date = get_header_value (headers, nof_headers, "last-modified");
+
+ if (!server_date || !*server_date) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_UNKNOWN, date_result);
+
+ } else if (!document_date || !*document_date) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+
+ } else {
+ time_t srv_data = curl_getdate (server_date, NULL);
+ time_t doc_data = curl_getdate (document_date, NULL);
+ if (verbose >= 2)
+ printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
+ if (srv_data <= 0) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data <= 0) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data > srv_data + 30) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data < srv_data - maximum_age) {
+ int n = (srv_data - doc_data);
+ if (n > (60 * 60 * 24 * 2)) {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else {
+ char tmp[DEFAULT_BUFFER_SIZE];
+
+ snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
+ strcpy(*msg, tmp);
+
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ }
+ }
+ }
+
+ if (server_date) free (server_date);
+ if (document_date) free (document_date);
+
+ return date_result;
+}
+
+
+int
+get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf)
+{
+ int content_length = 0;
+ struct phr_header headers[255];
+ size_t nof_headers = 255;
+ size_t msglen;
+ char *content_length_s = NULL;
+ curlhelp_statusline status_line;
+
+ int res = phr_parse_response (header_buf->buf, header_buf->buflen,
+ &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
+ headers, &nof_headers, 0);
+
+ if (res == -1) {
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
+ }
+
+ content_length_s = get_header_value (headers, nof_headers, "content-length");
+ if (!content_length_s) {
+ return header_buf->buflen + body_buf->buflen;
+ }
+ content_length_s += strspn (content_length_s, " \t");
+ content_length = atoi (content_length_s);
+ if (content_length != body_buf->buflen) {
+ /* TODO: should we warn if the actual and the reported body length don't match? */
+ }
+
+ if (content_length_s) free (content_length_s);
+
+ return header_buf->buflen + body_buf->buflen;
+}
+
+/* TODO: is there a better way in libcurl to check for the SSL library? */
+curlhelp_ssl_library
+curlhelp_get_ssl_library ()
+{
+ curl_version_info_data* version_data;
+ char *ssl_version;
+ char *library;
+ curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
+
+ version_data = curl_version_info (CURLVERSION_NOW);
+ if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
+
+ ssl_version = strdup (version_data->ssl_version);
+ if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN;
+
+ library = strtok (ssl_version, "/");
+ if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN;
+
+ if (strcmp (library, "OpenSSL") == 0)
+ ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
+ else if (strcmp (library, "LibreSSL") == 0)
+ ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
+ else if (strcmp (library, "GnuTLS") == 0)
+ ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
+ else if (strcmp (library, "NSS") == 0)
+ ssl_library = CURLHELP_SSL_LIBRARY_NSS;
+
+ if (verbose >= 2)
+ printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
+
+ free (ssl_version);
+
+ return ssl_library;
+}
+
+const char*
+curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library)
+{
+ switch (ssl_library) {
+ case CURLHELP_SSL_LIBRARY_OPENSSL:
+ return "OpenSSL";
+ case CURLHELP_SSL_LIBRARY_LIBRESSL:
+ return "LibreSSL";
+ case CURLHELP_SSL_LIBRARY_GNUTLS:
+ return "GnuTLS";
+ case CURLHELP_SSL_LIBRARY_NSS:
+ return "NSS";
+ case CURLHELP_SSL_LIBRARY_UNKNOWN:
+ default:
+ return "unknown";
+ }
+}
+
+#ifdef LIBCURL_FEATURE_SSL
+#ifndef USE_OPENSSL
+time_t
+parse_cert_date (const char *s)
+{
+ struct tm tm;
+ time_t date;
+ char *res;
+
+ if (!s) return -1;
+
+ /* Jan 17 14:25:12 2020 GMT */
+ res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm);
+ /* Sep 11 12:00:00 2020 GMT */
+ if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm);
+ date = mktime (&tm);
+
+ return date;
+}
+
+/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
+ * OpenSSL could be this function
+ */
+int
+net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit)
+{
+ int i;
+ struct curl_slist* slist;
+ int cname_found = 0;
+ char* start_date_str = NULL;
+ char* end_date_str = NULL;
+ time_t start_date;
+ time_t end_date;
+ char *tz;
+ float time_left;
+ int days_left;
+ int time_remaining;
+ char timestamp[50] = "";
+ int status = STATE_UNKNOWN;
+
+ if (verbose >= 2)
+ printf ("**** REQUEST CERTIFICATES ****\n");
+
+ for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
+ for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
+ /* find first common name in subject,
+ * TODO: check alternative subjects for
+ * TODO: have a decent parser here and not a hack
+ * multi-host certificate, check wildcards
+ */
+ if (strncasecmp (slist->data, "Subject:", 8) == 0) {
+ int d = 3;
+ char* p = strstr (slist->data, "CN=");
+ if (p == NULL) {
+ d = 5;
+ p = strstr (slist->data, "CN = ");
+ }
+ if (p != NULL) {
+ if (strncmp (host_name, p+d, strlen (host_name)) == 0) {
+ cname_found = 1;
+ }
+ }
+ } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) {
+ start_date_str = &slist->data[11];
+ } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) {
+ end_date_str = &slist->data[12];
+ } else if (strncasecmp (slist->data, "Cert:", 5) == 0) {
+ goto HAVE_FIRST_CERT;
+ }
+ if (verbose >= 2)
+ printf ("%d ** %s\n", i, slist->data);
+ }
+ }
+HAVE_FIRST_CERT:
+
+ if (verbose >= 2)
+ printf ("**** REQUEST CERTIFICATES ****\n");
+
+ if (!cname_found) {
+ printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject."));
+ return STATE_CRITICAL;
+ }
+
+ start_date = parse_cert_date (start_date_str);
+ if (start_date <= 0) {
+ snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"),
+ start_date_str);
+ puts (msg);
+ return STATE_WARNING;
+ }
+
+ end_date = parse_cert_date (end_date_str);
+ if (end_date <= 0) {
+ snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"),
+ start_date_str);
+ puts (msg);
+ return STATE_WARNING;
+ }
+
+ time_left = difftime (end_date, time(NULL));
+ days_left = time_left / 86400;
+ tz = getenv("TZ");
+ setenv("TZ", "GMT", 1);
+ tzset();
+ strftime(timestamp, 50, "%c %z", localtime(&end_date));
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+
+ if (days_left > 0 && days_left <= days_till_exp_warn) {
+ printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp);
+ if (days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else if (days_left == 0 && time_left > 0) {
+ if (time_left >= 3600)
+ time_remaining = (int) time_left / 3600;
+ else
+ time_remaining = (int) time_left / 60;
+
+ printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"),
+ (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining,
+ time_left >= 3600 ? "hours" : "minutes", timestamp);
+
+ if ( days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else if (time_left < 0) {
+ printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
+ status=STATE_CRITICAL;
+ } else if (days_left == 0) {
+ printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp);
+ if (days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else {
+ printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
+ status = STATE_OK;
+ }
+ return status;
+}
+#endif /* USE_OPENSSL */
+#endif /* LIBCURL_FEATURE_SSL */
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
new file mode 100644
index 0000000..c24ca24
--- /dev/null
+++ b/plugins/check_dbi.c
@@ -0,0 +1,826 @@
+/*****************************************************************************
+*
+* Monitoring check_dbi plugin
+*
+* License: GPL
+* Copyright (c) 2011 Monitoring Plugins Development Team
+* Author: Sebastian 'tokkee' Harl <sh@teamix.net>
+*
+* Description:
+*
+* This file contains the check_dbi plugin
+*
+* Runs an arbitrary (SQL) command and checks the result.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_dbi";
+const char *copyright = "2011";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_cmd.h"
+
+#include "netutils.h"
+
+#include "regex.h"
+
+/* required for NAN */
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE
+#endif
+
+#include <assert.h>
+#include <math.h>
+
+#include <dbi/dbi.h>
+
+#include <stdarg.h>
+
+typedef enum {
+ METRIC_CONN_TIME,
+ METRIC_SERVER_VERSION,
+ METRIC_QUERY_RESULT,
+ METRIC_QUERY_TIME,
+} np_dbi_metric_t;
+
+typedef enum {
+ TYPE_NUMERIC,
+ TYPE_STRING,
+} np_dbi_type_t;
+
+typedef struct {
+ char *key;
+ char *value;
+} driver_option_t;
+
+char *host = NULL;
+int verbose = 0;
+
+char *warning_range = NULL;
+char *critical_range = NULL;
+thresholds *dbi_thresholds = NULL;
+
+char *expect = NULL;
+
+regex_t expect_re;
+char *expect_re_str = NULL;
+int expect_re_cflags = 0;
+
+np_dbi_metric_t metric = METRIC_QUERY_RESULT;
+np_dbi_type_t type = TYPE_NUMERIC;
+
+char *np_dbi_driver = NULL;
+driver_option_t *np_dbi_options = NULL;
+int np_dbi_options_num = 0;
+char *np_dbi_database = NULL;
+char *np_dbi_query = NULL;
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_usage (void);
+void print_help (void);
+
+double timediff (struct timeval, struct timeval);
+
+void np_dbi_print_error (dbi_conn, char *, ...);
+
+int do_query (dbi_conn, const char **, double *, double *);
+
+int
+main (int argc, char **argv)
+{
+ int status = STATE_UNKNOWN;
+
+ dbi_driver driver;
+ dbi_conn conn;
+
+ unsigned int server_version;
+
+ struct timeval start_timeval, end_timeval;
+ double conn_time = 0.0;
+ double query_time = 0.0;
+
+ const char *query_val_str = NULL;
+ double query_val = 0.0;
+
+ int i;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ usage4 (_("Cannot catch SIGALRM"));
+ }
+ alarm (timeout_interval);
+
+ if (verbose > 2)
+ printf ("Initializing DBI\n");
+
+ dbi_inst *instance_p;
+
+ if (dbi_initialize_r(NULL, instance_p) < 0) {
+ printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
+ return STATE_UNKNOWN;
+ }
+
+ if (instance_p == NULL) {
+ printf ("UNKNOWN - failed to initialize DBI.\n");
+ return STATE_UNKNOWN;
+ }
+
+ if (verbose)
+ printf ("Opening DBI driver '%s'\n", np_dbi_driver);
+
+ driver = dbi_driver_open_r(np_dbi_driver, instance_p);
+ if (! driver) {
+ printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
+ np_dbi_driver);
+
+ printf ("Known drivers:\n");
+ for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
+ printf (" - %s\n", dbi_driver_get_name (driver));
+ }
+ return STATE_UNKNOWN;
+ }
+
+ /* make a connection to the database */
+ gettimeofday (&start_timeval, NULL);
+
+ conn = dbi_conn_open (driver);
+ if (! conn) {
+ printf ("UNKNOWN - failed top open connection object.\n");
+ dbi_conn_close (conn);
+ return STATE_UNKNOWN;
+ }
+
+ for (i = 0; i < np_dbi_options_num; ++i) {
+ const char *opt;
+
+ if (verbose > 1)
+ printf ("Setting DBI driver option '%s' to '%s'\n",
+ np_dbi_options[i].key, np_dbi_options[i].value);
+
+ if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value))
+ continue;
+ /* else: status != 0 */
+
+ np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'",
+ np_dbi_options[i].key, np_dbi_options[i].value);
+ printf ("Known driver options:\n");
+
+ for (opt = dbi_conn_get_option_list (conn, NULL); opt;
+ opt = dbi_conn_get_option_list (conn, opt)) {
+ printf (" - %s\n", opt);
+ }
+ dbi_conn_close (conn);
+ return STATE_UNKNOWN;
+ }
+
+ if (host) {
+ if (verbose > 1)
+ printf ("Setting DBI driver option 'host' to '%s'\n", host);
+ dbi_conn_set_option (conn, "host", host);
+ }
+
+ if (verbose) {
+ const char *dbname, *host;
+
+ dbname = dbi_conn_get_option (conn, "dbname");
+ host = dbi_conn_get_option (conn, "host");
+
+ if (! dbname)
+ dbname = "<unspecified>";
+ if (! host)
+ host = "<unspecified>";
+
+ printf ("Connecting to database '%s' at host '%s'\n",
+ dbname, host);
+ }
+
+ if (dbi_conn_connect (conn) < 0) {
+ np_dbi_print_error (conn, "UNKNOWN - failed to connect to database");
+ return STATE_UNKNOWN;
+ }
+
+ gettimeofday (&end_timeval, NULL);
+ conn_time = timediff (start_timeval, end_timeval);
+
+ server_version = dbi_conn_get_engine_version (conn);
+ if (verbose)
+ printf ("Connected to server version %u\n", server_version);
+
+ if (metric == METRIC_SERVER_VERSION)
+ status = get_status (server_version, dbi_thresholds);
+
+ if (verbose)
+ printf ("Time elapsed: %f\n", conn_time);
+
+ if (metric == METRIC_CONN_TIME)
+ status = get_status (conn_time, dbi_thresholds);
+
+ /* select a database */
+ if (np_dbi_database) {
+ if (verbose > 1)
+ printf ("Selecting database '%s'\n", np_dbi_database);
+
+ if (dbi_conn_select_db (conn, np_dbi_database)) {
+ np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'",
+ np_dbi_database);
+ return STATE_UNKNOWN;
+ }
+ }
+
+ if (np_dbi_query) {
+ /* execute query */
+ status = do_query (conn, &query_val_str, &query_val, &query_time);
+ if (status != STATE_OK)
+ /* do_query prints an error message in this case */
+ return status;
+
+ if (metric == METRIC_QUERY_RESULT) {
+ if (expect) {
+ if ((! query_val_str) || strcmp (query_val_str, expect))
+ status = STATE_CRITICAL;
+ else
+ status = STATE_OK;
+ }
+ else if (expect_re_str) {
+ int err;
+
+ err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
+ if (! err)
+ status = STATE_OK;
+ else if (err == REG_NOMATCH)
+ status = STATE_CRITICAL;
+ else {
+ char errmsg[1024];
+ regerror (err, &expect_re, errmsg, sizeof (errmsg));
+ printf ("ERROR - failed to execute regular expression: %s\n",
+ errmsg);
+ status = STATE_CRITICAL;
+ }
+ }
+ else
+ status = get_status (query_val, dbi_thresholds);
+ }
+ else if (metric == METRIC_QUERY_TIME)
+ status = get_status (query_time, dbi_thresholds);
+ }
+
+ if (verbose)
+ printf("Closing connection\n");
+ dbi_conn_close (conn);
+
+ /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
+ * which should have been reported and handled (abort) before
+ * ... unless we expected a string to be returned */
+ assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val))
+ || (type == TYPE_STRING));
+
+ assert ((type != TYPE_STRING) || (expect || expect_re_str));
+
+ printf ("%s - connection time: %fs", state_text (status), conn_time);
+ if (np_dbi_query) {
+ if (type == TYPE_STRING) {
+ assert (expect || expect_re_str);
+ printf (", '%s' returned '%s' in %fs", np_dbi_query,
+ query_val_str ? query_val_str : "<nothing>", query_time);
+ if (status != STATE_OK) {
+ if (expect)
+ printf (" (expected '%s')", expect);
+ else if (expect_re_str)
+ printf (" (expected regex /%s/%s)", expect_re_str,
+ ((expect_re_cflags & REG_ICASE) ? "i" : ""));
+ }
+ }
+ else if (isnan (query_val))
+ printf (", '%s' query execution time: %fs", np_dbi_query, query_time);
+ else
+ printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time);
+ }
+
+ printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
+ ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "",
+ ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "",
+ server_version,
+ ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "",
+ ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : "");
+ if (np_dbi_query) {
+ if (! isnan (query_val)) /* this is also true when -e is used */
+ printf (" query=%f;%s;%s;;", query_val,
+ ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "",
+ ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
+ printf (" querytime=%fs;%s;%s;0;", query_time,
+ ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
+ ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
+ }
+ printf ("\n");
+ return status;
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ STD_LONG_OPTS,
+
+ {"expect", required_argument, 0, 'e'},
+ {"regex", required_argument, 0, 'r'},
+ {"regexi", required_argument, 0, 'R'},
+ {"metric", required_argument, 0, 'm'},
+ {"driver", required_argument, 0, 'd'},
+ {"option", required_argument, 0, 'o'},
+ {"query", required_argument, 0, 'q'},
+ {"database", required_argument, 0, 'D'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
+ longopts, &option);
+
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* usage */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+
+ case 'c': /* critical range */
+ critical_range = optarg;
+ type = TYPE_NUMERIC;
+ break;
+ case 'w': /* warning range */
+ warning_range = optarg;
+ type = TYPE_NUMERIC;
+ break;
+ case 'e':
+ expect = optarg;
+ type = TYPE_STRING;
+ break;
+ case 'R':
+ expect_re_cflags = REG_ICASE;
+ /* fall through */
+ case 'r':
+ {
+ int err;
+
+ expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+ expect_re_str = optarg;
+ type = TYPE_STRING;
+
+ err = regcomp (&expect_re, expect_re_str, expect_re_cflags);
+ if (err) {
+ char errmsg[1024];
+ regerror (err, &expect_re, errmsg, sizeof (errmsg));
+ printf ("ERROR - failed to compile regular expression: %s\n",
+ errmsg);
+ return ERROR;
+ }
+ break;
+ }
+
+ case 'm':
+ if (! strcasecmp (optarg, "CONN_TIME"))
+ metric = METRIC_CONN_TIME;
+ else if (! strcasecmp (optarg, "SERVER_VERSION"))
+ metric = METRIC_SERVER_VERSION;
+ else if (! strcasecmp (optarg, "QUERY_RESULT"))
+ metric = METRIC_QUERY_RESULT;
+ else if (! strcasecmp (optarg, "QUERY_TIME"))
+ metric = METRIC_QUERY_TIME;
+ else
+ usage2 (_("Invalid metric"), optarg);
+ break;
+ case 't': /* timeout */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ timeout_interval = atoi (optarg);
+
+ break;
+ case 'H': /* host */
+ if (!is_host (optarg))
+ usage2 (_("Invalid hostname/address"), optarg);
+ else
+ host = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+
+ case 'd':
+ np_dbi_driver = optarg;
+ break;
+ case 'o':
+ {
+ driver_option_t *new;
+
+ char *k, *v;
+
+ k = optarg;
+ v = strchr (k, (int)'=');
+
+ if (! v)
+ usage2 (_("Option must be '<key>=<value>'"), optarg);
+
+ *v = '\0';
+ ++v;
+
+ new = realloc (np_dbi_options,
+ (np_dbi_options_num + 1) * sizeof (*new));
+ if (! new) {
+ printf ("UNKNOWN - failed to reallocate memory\n");
+ exit (STATE_UNKNOWN);
+ }
+
+ np_dbi_options = new;
+ new = np_dbi_options + np_dbi_options_num;
+ ++np_dbi_options_num;
+
+ new->key = k;
+ new->value = v;
+ }
+ break;
+ case 'q':
+ np_dbi_query = optarg;
+ break;
+ case 'D':
+ np_dbi_database = optarg;
+ break;
+ }
+ }
+
+ set_thresholds (&dbi_thresholds, warning_range, critical_range);
+
+ return validate_arguments ();
+}
+
+int
+validate_arguments ()
+{
+ if (! np_dbi_driver)
+ usage ("Must specify a DBI driver");
+
+ if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME))
+ && (! np_dbi_query))
+ usage ("Must specify a query to execute (metric == QUERY_RESULT)");
+
+ if ((metric != METRIC_CONN_TIME)
+ && (metric != METRIC_SERVER_VERSION)
+ && (metric != METRIC_QUERY_RESULT)
+ && (metric != METRIC_QUERY_TIME))
+ usage ("Invalid metric specified");
+
+ if (expect && (warning_range || critical_range || expect_re_str))
+ usage ("Do not mix -e and -w/-c/-r/-R");
+
+ if (expect_re_str && (warning_range || critical_range || expect))
+ usage ("Do not mix -r/-R and -w/-c/-e");
+
+ if (expect && (metric != METRIC_QUERY_RESULT))
+ usage ("Option -e requires metric QUERY_RESULT");
+
+ if (expect_re_str && (metric != METRIC_QUERY_RESULT))
+ usage ("Options -r/-R require metric QUERY_RESULT");
+
+ return OK;
+}
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This program connects to an (SQL) database using DBI and checks the\n"
+ "specified metric against threshold levels. The default metric is\n"
+ "the result of the specified query.\n"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+/* include this conditionally to avoid 'zero-length printf format string'
+ * compiler warnings */
+#ifdef NP_EXTRA_OPTS
+ printf (UT_EXTRA_OPTS);
+#endif
+ printf ("\n");
+
+ printf (" %s\n", "-d, --driver=STRING");
+ printf (" %s\n", _("DBI driver to use"));
+ printf (" %s\n", "-o, --option=STRING");
+ printf (" %s\n", _("DBI driver options"));
+ printf (" %s\n", "-q, --query=STRING");
+ printf (" %s\n", _("query to execute"));
+ printf ("\n");
+
+ printf (UT_WARN_CRIT_RANGE);
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (" %s\n", _("String to expect as query result"));
+ printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
+ printf (" %s\n", "-r, --regex=REGEX");
+ printf (" %s\n", _("Extended POSIX regular expression to check query result against"));
+ printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
+ printf (" %s\n", "-R, --regexi=REGEX");
+ printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
+ printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
+ printf (" %s\n", "-m, --metric=METRIC");
+ printf (" %s\n", _("Metric to check thresholds against. Available metrics:"));
+ printf (" CONN_TIME - %s\n", _("time used for setting up the database connection"));
+ printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
+ printf (" QUERY_TIME - %s\n", _("time used to execute the query"));
+ printf (" %s\n", _("(ignore the query result)"));
+ printf ("\n");
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
+ printf (" %s\n\n", _("on a query, one has to be specified (-q option)."));
+
+ printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
+ printf (" %s\n", _("executes the specified query. The first column of the first row of the"));
+ printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
+ printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
+ printf (" %s\n\n", _("(strings representing numbers are fine)."));
+
+ printf (" %s\n", _("The number and type of required DBI driver options depends on the actual"));
+ printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
+ printf (" %s\n\n", _("for details."));
+
+ printf (" %s\n", _("Examples:"));
+ printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
+ printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
+ printf (" Warning if more than five connections; critical if more than ten.\n\n");
+
+ printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
+ printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
+ printf (" Warning if less than 5 or more than 20 users are logged in; critical\n");
+ printf (" if more than 50 users.\n\n");
+
+ printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
+ printf (" -m CONN_TIME -w 0.5 -c 2\n");
+ printf (" Warning if connecting to the database takes more than half of a second;\n");
+ printf (" critical if it takes more than 2 seconds.\n\n");
+
+ printf (" check_dbi -d mysql -H localhost -o username=user \\\n");
+ printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
+ printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n");
+ printf (" Critical if the database server is not a MySQL enterprise server in either\n");
+ printf (" version 5.0.x or 5.1.x.\n\n");
+
+ printf (" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n");
+ printf (" -w 090000:090099 -c 090000:090199\n");
+ printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
+ printf (" is less than 9.x or higher than 9.1.x.\n");
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
+ printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
+ printf (" [-e <string>] [-r|-R <regex>]\n");
+}
+
+#define CHECK_IGNORE_ERROR(s) \
+ do { \
+ if (metric != METRIC_QUERY_RESULT) \
+ return (s); \
+ } while (0)
+
+const char *
+get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
+{
+ const char *str;
+
+ if (field_type != DBI_TYPE_STRING) {
+ printf ("CRITICAL - result value is not a string\n");
+ return NULL;
+ }
+
+ str = dbi_result_get_string_idx (res, 1);
+ if ((! str) || (strcmp (str, "ERROR") == 0)) {
+ CHECK_IGNORE_ERROR (NULL);
+ np_dbi_print_error (conn, "CRITICAL - failed to fetch string value");
+ return NULL;
+ }
+
+ if ((verbose && (type == TYPE_STRING)) || (verbose > 2))
+ printf ("Query returned string '%s'\n", str);
+ return str;
+}
+
+double
+get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
+{
+ double val = NAN;
+
+ if (*field_type == DBI_TYPE_INTEGER) {
+ val = (double)dbi_result_get_longlong_idx (res, 1);
+ }
+ else if (*field_type == DBI_TYPE_DECIMAL) {
+ val = dbi_result_get_double_idx (res, 1);
+ }
+ else if (*field_type == DBI_TYPE_STRING) {
+ const char *val_str;
+ char *endptr = NULL;
+
+ val_str = get_field_str (conn, res, *field_type);
+ if (! val_str) {
+ CHECK_IGNORE_ERROR (NAN);
+ *field_type = DBI_TYPE_ERROR;
+ return NAN;
+ }
+
+ val = strtod (val_str, &endptr);
+ if (endptr == val_str) {
+ CHECK_IGNORE_ERROR (NAN);
+ printf ("CRITICAL - result value is not a numeric: %s\n", val_str);
+ *field_type = DBI_TYPE_ERROR;
+ return NAN;
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ if (verbose)
+ printf ("Garbage after value: %s\n", endptr);
+ }
+ }
+ else {
+ CHECK_IGNORE_ERROR (NAN);
+ printf ("CRITICAL - cannot parse value of type %s (%i)\n",
+ (*field_type == DBI_TYPE_BINARY)
+ ? "BINARY"
+ : (*field_type == DBI_TYPE_DATETIME)
+ ? "DATETIME"
+ : "<unknown>",
+ *field_type);
+ *field_type = DBI_TYPE_ERROR;
+ return NAN;
+ }
+ return val;
+}
+
+double
+get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
+{
+ unsigned short field_type;
+ double val = NAN;
+
+ if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ np_dbi_print_error (conn, "CRITICAL - failed to fetch rows");
+ return STATE_CRITICAL;
+ }
+
+ if (dbi_result_get_numrows (res) < 1) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ printf ("WARNING - no rows returned\n");
+ return STATE_WARNING;
+ }
+
+ if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ np_dbi_print_error (conn, "CRITICAL - failed to fetch fields");
+ return STATE_CRITICAL;
+ }
+
+ if (dbi_result_get_numfields (res) < 1) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ printf ("WARNING - no fields returned\n");
+ return STATE_WARNING;
+ }
+
+ if (dbi_result_first_row (res) != 1) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ np_dbi_print_error (conn, "CRITICAL - failed to fetch first row");
+ return STATE_CRITICAL;
+ }
+
+ field_type = dbi_result_get_field_type_idx (res, 1);
+ if (field_type != DBI_TYPE_ERROR) {
+ if (type == TYPE_STRING)
+ /* the value will be freed in dbi_result_free */
+ *res_val_str = strdup (get_field_str (conn, res, field_type));
+ else
+ val = get_field (conn, res, &field_type);
+ }
+
+ *res_val = val;
+
+ if (field_type == DBI_TYPE_ERROR) {
+ CHECK_IGNORE_ERROR (STATE_OK);
+ np_dbi_print_error (conn, "CRITICAL - failed to fetch data");
+ return STATE_CRITICAL;
+ }
+
+ dbi_result_free (res);
+ return STATE_OK;
+}
+
+#undef CHECK_IGNORE_ERROR
+
+int
+do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
+{
+ dbi_result res;
+
+ struct timeval timeval_start, timeval_end;
+ int status = STATE_OK;
+
+ assert (np_dbi_query);
+
+ if (verbose)
+ printf ("Executing query '%s'\n", np_dbi_query);
+
+ gettimeofday (&timeval_start, NULL);
+
+ res = dbi_conn_query (conn, np_dbi_query);
+ if (! res) {
+ np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
+ return STATE_CRITICAL;
+ }
+
+ status = get_query_result (conn, res, res_val_str, res_val);
+
+ gettimeofday (&timeval_end, NULL);
+ *res_time = timediff (timeval_start, timeval_end);
+
+ if (verbose)
+ printf ("Time elapsed: %f\n", *res_time);
+
+ return status;
+}
+
+double
+timediff (struct timeval start, struct timeval end)
+{
+ double diff;
+
+ while (start.tv_usec > end.tv_usec) {
+ --end.tv_sec;
+ end.tv_usec += 1000000;
+ }
+ diff = (double)(end.tv_sec - start.tv_sec)
+ + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
+ return diff;
+}
+
+void
+np_dbi_print_error (dbi_conn conn, char *fmt, ...)
+{
+ const char *errmsg = NULL;
+ va_list ap;
+
+ va_start (ap, fmt);
+
+ dbi_conn_error (conn, &errmsg);
+ vprintf (fmt, ap);
+ printf (": %s\n", errmsg);
+
+ va_end (ap);
+}
+
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
new file mode 100644
index 0000000..5d85ae2
--- /dev/null
+++ b/plugins/check_dig.c
@@ -0,0 +1,380 @@
+/*****************************************************************************
+*
+* Monitoring check_dig plugin
+*
+* License: GPL
+* Copyright (c) 2002-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_dig plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+/* Hackers note:
+ * There are typecasts to (char *) from _("foo bar") in this file.
+ * They prevent compiler warnings. Never (ever), permute strings obtained
+ * that are typecast from (const char *) (which happens when --disable-nls)
+ * because on some architectures those strings are in non-writable memory */
+
+const char *progname = "check_dig";
+const char *copyright = "2002-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+#include "runcmd.h"
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+#define UNDEFINED 0
+#define DEFAULT_PORT 53
+#define DEFAULT_TRIES 2
+
+char *query_address = NULL;
+char *record_type = "A";
+char *expected_address = NULL;
+char *dns_server = NULL;
+char *dig_args = "";
+char *query_transport = "";
+int verbose = FALSE;
+int server_port = DEFAULT_PORT;
+int number_tries = DEFAULT_TRIES;
+double warning_interval = UNDEFINED;
+double critical_interval = UNDEFINED;
+struct timeval tv;
+
+int
+main (int argc, char **argv)
+{
+ char *command_line;
+ output chld_out, chld_err;
+ char *msg = NULL;
+ size_t i;
+ char *t;
+ long microsec;
+ double elapsed_time;
+ int result = STATE_UNKNOWN;
+ int timeout_interval_dig;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR)
+ usage_va(_("Cannot catch SIGALRM"));
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage_va(_("Could not parse arguments"));
+
+ /* dig applies the timeout to each try, so we need to work around this */
+ timeout_interval_dig = timeout_interval / number_tries + number_tries;
+
+ /* get the command to run */
+ xasprintf (&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d",
+ PATH_TO_DIG, dig_args, query_transport, server_port, dns_server, query_address, record_type, number_tries, timeout_interval_dig);
+
+ alarm (timeout_interval);
+ gettimeofday (&tv, NULL);
+
+ if (verbose) {
+ printf ("%s\n", command_line);
+ if(expected_address != NULL) {
+ printf (_("Looking for: '%s'\n"), expected_address);
+ } else {
+ printf (_("Looking for: '%s'\n"), query_address);
+ }
+ }
+
+ /* run the command */
+ if(np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
+ result = STATE_WARNING;
+ msg = (char *)_("dig returned an error status");
+ }
+
+ for(i = 0; i < chld_out.lines; i++) {
+ /* the server is responding, we just got the host name... */
+ if (strstr (chld_out.line[i], ";; ANSWER SECTION:")) {
+
+ /* loop through the whole 'ANSWER SECTION' */
+ for(; i < chld_out.lines; i++) {
+ /* get the host address */
+ if (verbose)
+ printf ("%s\n", chld_out.line[i]);
+
+ if (strcasestr (chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) {
+ msg = chld_out.line[i];
+ result = STATE_OK;
+
+ /* Translate output TAB -> SPACE */
+ t = msg;
+ while ((t = strchr(t, '\t')) != NULL) *t = ' ';
+ break;
+ }
+ }
+
+ if (result == STATE_UNKNOWN) {
+ msg = (char *)_("Server not found in ANSWER SECTION");
+ result = STATE_WARNING;
+ }
+
+ /* we found the answer section, so break out of the loop */
+ break;
+ }
+ }
+
+ if (result == STATE_UNKNOWN) {
+ msg = (char *)_("No ANSWER SECTION found");
+ result = STATE_CRITICAL;
+ }
+
+ /* If we get anything on STDERR, at least set warning */
+ if(chld_err.buflen > 0) {
+ result = max_state(result, STATE_WARNING);
+ if(!msg) for(i = 0; i < chld_err.lines; i++) {
+ msg = strchr(chld_err.line[0], ':');
+ if(msg) {
+ msg++;
+ break;
+ }
+ }
+ }
+
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ if (critical_interval > UNDEFINED && elapsed_time > critical_interval)
+ result = STATE_CRITICAL;
+
+ else if (warning_interval > UNDEFINED && elapsed_time > warning_interval)
+ result = STATE_WARNING;
+
+ printf ("DNS %s - %.3f seconds response time (%s)|%s\n",
+ state_text (result), elapsed_time,
+ msg ? msg : _("Probably a non-existent host/domain"),
+ fperfdata("time", elapsed_time, "s",
+ (warning_interval>UNDEFINED?TRUE:FALSE),
+ warning_interval,
+ (critical_interval>UNDEFINED?TRUE:FALSE),
+ critical_interval,
+ TRUE, 0, FALSE, 0));
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"query_address", required_argument, 0, 'l'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"timeout", required_argument, 0, 't'},
+ {"dig-arguments", required_argument, 0, 'A'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"record_type", required_argument, 0, 'T'},
+ {"expected_address", required_argument, 0, 'a'},
+ {"port", required_argument, 0, 'p'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'H': /* hostname */
+ host_or_die(optarg);
+ dns_server = optarg;
+ break;
+ case 'p': /* server port */
+ if (is_intpos (optarg)) {
+ server_port = atoi (optarg);
+ }
+ else {
+ usage_va(_("Port must be a positive integer - %s"), optarg);
+ }
+ break;
+ case 'l': /* address to lookup */
+ query_address = optarg;
+ break;
+ case 'w': /* warning */
+ if (is_nonnegative (optarg)) {
+ warning_interval = strtod (optarg, NULL);
+ }
+ else {
+ usage_va(_("Warning interval must be a positive integer - %s"), optarg);
+ }
+ break;
+ case 'c': /* critical */
+ if (is_nonnegative (optarg)) {
+ critical_interval = strtod (optarg, NULL);
+ }
+ else {
+ usage_va(_("Critical interval must be a positive integer - %s"), optarg);
+ }
+ break;
+ case 't': /* timeout */
+ if (is_intnonneg (optarg)) {
+ timeout_interval = atoi (optarg);
+ }
+ else {
+ usage_va(_("Timeout interval must be a positive integer - %s"), optarg);
+ }
+ break;
+ case 'A': /* dig arguments */
+ dig_args = strdup(optarg);
+ break;
+ case 'v': /* verbose */
+ verbose = TRUE;
+ break;
+ case 'T':
+ record_type = optarg;
+ break;
+ case 'a':
+ expected_address = optarg;
+ break;
+ case '4':
+ query_transport = "-4";
+ break;
+ case '6':
+ query_transport = "-6";
+ break;
+ default: /* usage5 */
+ usage5();
+ }
+ }
+
+ c = optind;
+ if (dns_server == NULL) {
+ if (c < argc) {
+ host_or_die(argv[c]);
+ dns_server = argv[c];
+ }
+ else {
+ if (strcmp(query_transport,"-6") == 0)
+ dns_server = strdup("::1");
+ else
+ dns_server = strdup ("127.0.0.1");
+ }
+ }
+
+ return validate_arguments ();
+}
+
+
+
+int
+validate_arguments (void)
+{
+ if (query_address != NULL)
+ return OK;
+ else
+ return ERROR;
+}
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+
+ xasprintf (&myport, "%d", DEFAULT_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin tests the DNS service on the specified host using dig"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n","-4, --use-ipv4");
+ printf (" %s\n",_("Force dig to only use IPv4 query transport"));
+ printf (" %s\n","-6, --use-ipv6");
+ printf (" %s\n",_("Force dig to only use IPv6 query transport"));
+ printf (" %s\n","-l, --query_address=STRING");
+ printf (" %s\n",_("Machine name to lookup"));
+ printf (" %s\n","-T, --record_type=STRING");
+ printf (" %s\n",_("Record type to lookup (default: A)"));
+ printf (" %s\n","-a, --expected_address=STRING");
+ printf (" %s\n",_("An address expected to be in the answer section. If not set, uses whatever"));
+ printf (" %s\n",_("was in -l"));
+ printf (" %s\n","-A, --dig-arguments=STRING");
+ printf (" %s\n",_("Pass STRING as argument(s) to dig"));
+ printf (UT_WARN_CRIT);
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
+ printf (" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
+ printf (" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
+ printf (" [-t <timeout>] [-a <expected answer address>] [-v]\n");
+}
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
new file mode 100644
index 0000000..2f066c7
--- /dev/null
+++ b/plugins/check_disk.c
@@ -0,0 +1,1170 @@
+/*****************************************************************************
+*
+* Monitoring check_disk plugin
+*
+* License: GPL
+* Copyright (c) 1999-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_disk plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_disk";
+const char *program_name = "check_disk"; /* Required for coreutils libs */
+const char *copyright = "1999-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+
+#include "common.h"
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <assert.h>
+#include "popen.h"
+#include "utils.h"
+#include "utils_disk.h"
+#include <stdarg.h>
+#include "fsusage.h"
+#include "mountlist.h"
+#include "intprops.h" /* necessary for TYPE_MAXIMUM */
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#include "regex.h"
+
+#ifdef __CYGWIN__
+# include <windows.h>
+# undef ERROR
+# define ERROR -1
+#endif
+
+/* If nonzero, show even filesystems with zero size or
+ uninteresting types. */
+static int show_all_fs = 1;
+
+/* If nonzero, show only local filesystems. */
+static int show_local_fs = 0;
+
+/* If nonzero, show only local filesystems but call stat() on remote ones. */
+static int stat_remote_fs = 0;
+
+/* If positive, the units to use when printing sizes;
+ if negative, the human-readable base. */
+/* static int output_block_size; */
+
+/* If nonzero, invoke the `sync' system call before getting any usage data.
+ Using this option can make df very slow, especially with many or very
+ busy disks. Note that this may make a difference on some systems --
+ SunOs4.1.3, for one. It is *not* necessary on Linux. */
+/* static int require_sync = 0; */
+
+/* Linked list of filesystem types to display.
+ If `fs_select_list' is NULL, list all types.
+ This table is generated dynamically from command-line options,
+ rather than hardcoding into the program what it thinks are the
+ valid filesystem types; let the user specify any filesystem type
+ they want to, and if there are any filesystems of that type, they
+ will be shown.
+
+ Some filesystem types:
+ 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
+
+/* static struct parameter_list *fs_select_list; */
+
+/* Linked list of filesystem types to omit.
+ If the list is empty, don't exclude any types. */
+static struct regex_list *fs_exclude_list = NULL;
+
+/* Linked list of filesystem types to check.
+ If the list is empty, include all types. */
+static struct regex_list *fs_include_list;
+
+static struct name_list *dp_exclude_list;
+
+static struct parameter_list *path_select_list = NULL;
+
+/* Linked list of mounted filesystems. */
+static struct mount_entry *mount_list;
+
+/* For long options that have no equivalent short option, use a
+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */
+enum
+{
+ SYNC_OPTION = CHAR_MAX + 1,
+ NO_SYNC_OPTION,
+ BLOCK_SIZE_OPTION,
+ IGNORE_MISSING
+};
+
+#ifdef _AIX
+#pragma alloca
+#endif
+
+int process_arguments (int, char **);
+void print_path (const char *mypath);
+void set_all_thresholds (struct parameter_list *path);
+int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
+void print_help (void);
+void print_usage (void);
+double calculate_percent(uintmax_t, uintmax_t);
+bool stat_path (struct parameter_list *p);
+void get_stats (struct parameter_list *p, struct fs_usage *fsp);
+void get_path_stats (struct parameter_list *p, struct fs_usage *fsp);
+
+char *exclude_device;
+char *units;
+uintmax_t mult = 1024 * 1024;
+int verbose = 0;
+int erronly = FALSE;
+int display_mntp = FALSE;
+int exact_match = FALSE;
+bool ignore_missing = false;
+int freespace_ignore_reserved = FALSE;
+int display_inodes_perfdata = FALSE;
+char *warn_freespace_units = NULL;
+char *crit_freespace_units = NULL;
+char *warn_freespace_percent = NULL;
+char *crit_freespace_percent = NULL;
+char *warn_usedspace_units = NULL;
+char *crit_usedspace_units = NULL;
+char *warn_usedspace_percent = NULL;
+char *crit_usedspace_percent = NULL;
+char *warn_usedinodes_percent = NULL;
+char *crit_usedinodes_percent = NULL;
+char *warn_freeinodes_percent = NULL;
+char *crit_freeinodes_percent = NULL;
+int path_selected = FALSE;
+bool path_ignored = false;
+char *group = NULL;
+struct stat *stat_buf;
+struct name_list *seen = NULL;
+
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ int disk_result = STATE_UNKNOWN;
+ char *output;
+ char *ignored;
+ char *details;
+ char *perf;
+ char *perf_ilabel;
+ char *preamble = " - free space:";
+ char *ignored_preamble = " - ignored paths:";
+ char *flag_header;
+ int temp_result;
+
+ struct mount_entry *me;
+ struct fs_usage fsp;
+ struct parameter_list *temp_list, *path;
+
+#ifdef __CYGWIN__
+ char mountdir[32];
+#endif
+
+ output = strdup ("");
+ ignored = strdup ("");
+ details = strdup ("");
+ perf = strdup ("");
+ perf_ilabel = strdup ("");
+ stat_buf = malloc(sizeof *stat_buf);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ mount_list = read_file_system_list (0);
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* If a list of paths has not been selected, find entire
+ mount list and create list of paths
+ */
+ if (path_selected == FALSE && path_ignored == false) {
+ for (me = mount_list; me; me = me->me_next) {
+ if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
+ path = np_add_parameter(&path_select_list, me->me_mountdir);
+ }
+ path->best_match = me;
+ path->group = group;
+ set_all_thresholds(path);
+ }
+ }
+
+ if (path_ignored == false) {
+ np_set_best_match(path_select_list, mount_list, exact_match);
+ }
+
+ /* Error if no match found for specified paths */
+ temp_list = path_select_list;
+
+ while (path_select_list) {
+ if (! path_select_list->best_match && ignore_missing == true) {
+ /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
+ if (path_select_list == temp_list) {
+ temp_list = path_select_list->name_next;
+ }
+ /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
+ xasprintf (&ignored, "%s %s;", ignored, path_select_list->name);
+ /* Delete the path from the list so that it is not stat-checked later in the code. */
+ path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
+ } else if (! path_select_list->best_match) {
+ /* Without --ignore-missing option, exit with Critical state. */
+ die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
+ } else {
+ /* Continue jumping through the list */
+ path_select_list = path_select_list->name_next;
+ }
+ }
+
+ path_select_list = temp_list;
+
+ if (! path_select_list && ignore_missing == true) {
+ result = STATE_OK;
+ if (verbose >= 2) {
+ printf ("None of the provided paths were found\n");
+ }
+ }
+
+ /* Process for every path in list */
+ for (path = path_select_list; path; path=path->name_next) {
+ if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
+ printf("Thresholds(pct) for %s warn: %f crit %f\n",
+ path->name,
+ path->freespace_percent->warning->end,
+ path->freespace_percent->critical->end);
+
+ if (verbose >= 3 && path->group != NULL)
+ printf("Group of %s: %s\n",path->name,path->group);
+
+ /* reset disk result */
+ disk_result = STATE_UNKNOWN;
+
+ me = path->best_match;
+
+ if (!me) {
+ continue;
+ }
+
+#ifdef __CYGWIN__
+ if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11)
+ continue;
+ snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
+ if (GetDriveType(mountdir) != DRIVE_FIXED)
+ me->me_remote = 1;
+#endif
+ /* Filters */
+
+ /* Remove filesystems already seen */
+ if (np_seen_name(seen, me->me_mountdir)) {
+ continue;
+ }
+ np_add_name(&seen, me->me_mountdir);
+
+ if (path->group == NULL) {
+ /* Skip remote filesystems if we're not interested in them */
+ if (me->me_remote && show_local_fs) {
+ if (stat_remote_fs) {
+ if (!stat_path(path) && ignore_missing == true) {
+ result = STATE_OK;
+ xasprintf (&ignored, "%s %s;", ignored, path->name);
+ }
+ }
+ continue;
+ /* Skip pseudo fs's if we haven't asked for all fs's */
+ } else if (me->me_dummy && !show_all_fs) {
+ continue;
+ /* Skip excluded fstypes */
+ } else if (fs_exclude_list && np_find_regmatch (fs_exclude_list, me->me_type)) {
+ continue;
+ /* Skip excluded fs's */
+ } else if (dp_exclude_list &&
+ (np_find_name (dp_exclude_list, me->me_devname) ||
+ np_find_name (dp_exclude_list, me->me_mountdir))) {
+ continue;
+ /* Skip not included fstypes */
+ } else if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
+ continue;
+ }
+ }
+
+ if (!stat_path(path)) {
+ if (ignore_missing == true) {
+ result = STATE_OK;
+ xasprintf (&ignored, "%s %s;", ignored, path->name);
+ }
+ continue;
+ }
+ get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
+
+ if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
+ get_stats (path, &fsp);
+
+ if (verbose >= 3) {
+ printf ("For %s, used_pct=%g free_pct=%g used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%g free_inodes_pct=%g fsp.fsu_blocksize=%lu mult=%lu\n",
+ me->me_mountdir,
+ path->dused_pct,
+ path->dfree_pct,
+ path->dused_units,
+ path->dfree_units,
+ path->dtotal_units,
+ path->dused_inodes_percent,
+ path->dfree_inodes_percent,
+ fsp.fsu_blocksize,
+ mult);
+ }
+
+ /* Threshold comparisons */
+
+ temp_result = get_status(path->dfree_units, path->freespace_units);
+ if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ temp_result = get_status(path->dfree_pct, path->freespace_percent);
+ if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ temp_result = get_status(path->dused_units, path->usedspace_units);
+ if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ temp_result = get_status(path->dused_pct, path->usedspace_percent);
+ if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
+ if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
+ if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
+ disk_result = max_state( disk_result, temp_result );
+
+ result = max_state(result, disk_result);
+
+ /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
+ Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
+ data. Assumption that start=0. Roll on new syntax...
+ */
+
+ /* *_high_tide must be reinitialized at each run */
+ uint64_t warning_high_tide = UINT64_MAX;
+
+ if (path->freespace_units->warning != NULL) {
+ warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
+ }
+ if (path->freespace_percent->warning != NULL) {
+ warning_high_tide = min( warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end/100) * (path->dtotal_units * mult)) );
+ }
+
+ uint64_t critical_high_tide = UINT64_MAX;
+
+ if (path->freespace_units->critical != NULL) {
+ critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
+ }
+ if (path->freespace_percent->critical != NULL) {
+ critical_high_tide = min( critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end/100) * (path->dtotal_units * mult)) );
+ }
+
+ /* Nb: *_high_tide are unset when == UINT64_MAX */
+ xasprintf (&perf, "%s %s", perf,
+ perfdata_uint64 (
+ (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
+ path->dused_units * mult, "B",
+ (warning_high_tide == UINT64_MAX ? FALSE : TRUE), warning_high_tide,
+ (critical_high_tide == UINT64_MAX ? FALSE : TRUE), critical_high_tide,
+ TRUE, 0,
+ TRUE, path->dtotal_units * mult));
+
+ if (display_inodes_perfdata) {
+ /* *_high_tide must be reinitialized at each run */
+ warning_high_tide = UINT64_MAX;
+ critical_high_tide = UINT64_MAX;
+
+ if (path->freeinodes_percent->warning != NULL) {
+ warning_high_tide = (uint64_t) fabs( min( (double) warning_high_tide, (double) (1.0 - path->freeinodes_percent->warning->end/100)*path->inodes_total ));
+ }
+ if (path->freeinodes_percent->critical != NULL) {
+ critical_high_tide = (uint64_t) fabs( min( (double) critical_high_tide, (double) (1.0 - path->freeinodes_percent->critical->end/100)*path->inodes_total ));
+ }
+
+ xasprintf (&perf_ilabel, "%s (inodes)", (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
+ /* Nb: *_high_tide are unset when == UINT64_MAX */
+ xasprintf (&perf, "%s %s", perf,
+ perfdata_uint64 (perf_ilabel,
+ path->inodes_used, "",
+ (warning_high_tide != UINT64_MAX ? TRUE : FALSE), warning_high_tide,
+ (critical_high_tide != UINT64_MAX ? TRUE : FALSE), critical_high_tide,
+ TRUE, 0,
+ TRUE, path->inodes_total));
+ }
+
+ if (disk_result==STATE_OK && erronly && !verbose)
+ continue;
+
+ if(disk_result && verbose >= 1) {
+ xasprintf(&flag_header, " %s [", state_text (disk_result));
+ } else {
+ xasprintf(&flag_header, "");
+ }
+ xasprintf (&output, "%s%s %s %llu%s (%.0f%%",
+ output, flag_header,
+ (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
+ path->dfree_units,
+ units,
+ path->dfree_pct);
+ if (path->dused_inodes_percent < 0) {
+ xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
+ } else {
+ xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
+ }
+ free(flag_header);
+ }
+ }
+
+ if (verbose >= 2)
+ xasprintf (&output, "%s%s", output, details);
+
+ if (strcmp(output, "") == 0 && ! erronly) {
+ preamble = "";
+ xasprintf (&output, " - No disks were found for provided parameters;");
+ }
+
+ printf ("DISK %s%s%s%s%s|%s\n", state_text (result), ((erronly && result==STATE_OK)) ? "" : preamble, output, (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
+ return result;
+}
+
+
+double calculate_percent(uintmax_t value, uintmax_t total) {
+ double pct = -1;
+ /* I don't understand the below, but it is taken from coreutils' df */
+ /* Seems to be calculating pct, in the best possible way */
+ if (value <= TYPE_MAXIMUM(uintmax_t) / 100
+ && total != 0) {
+ uintmax_t u100 = value * 100;
+ pct = u100 / total + (u100 % total != 0);
+ } else {
+ /* Possible rounding errors - see coreutils' df for more explanation */
+ double u = value;
+ double t = total;
+ if (t) {
+ long int lipct = pct = u * 100 / t;
+ double ipct = lipct;
+
+ /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
+ if (ipct - 1 < pct && pct <= ipct + 1)
+ pct = ipct + (ipct < pct);
+ }
+ }
+ return pct;
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c, err;
+ struct parameter_list *se;
+ struct parameter_list *temp_list = NULL, *previous = NULL;
+ struct mount_entry *me;
+ regex_t re;
+ int cflags = REG_NOSUB | REG_EXTENDED;
+ int default_cflags = cflags;
+ char errbuf[MAX_INPUT_BUFFER];
+ int fnd = 0;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"timeout", required_argument, 0, 't'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"iwarning", required_argument, 0, 'W'},
+ /* Dang, -C is taken. We might want to reshuffle this. */
+ {"icritical", required_argument, 0, 'K'},
+ {"kilobytes", no_argument, 0, 'k'},
+ {"megabytes", no_argument, 0, 'm'},
+ {"units", required_argument, 0, 'u'},
+ {"path", required_argument, 0, 'p'},
+ {"partition", required_argument, 0, 'p'},
+ {"exclude_device", required_argument, 0, 'x'},
+ {"exclude-type", required_argument, 0, 'X'},
+ {"include-type", required_argument, 0, 'N'},
+ {"group", required_argument, 0, 'g'},
+ {"eregi-path", required_argument, 0, 'R'},
+ {"eregi-partition", required_argument, 0, 'R'},
+ {"ereg-path", required_argument, 0, 'r'},
+ {"ereg-partition", required_argument, 0, 'r'},
+ {"freespace-ignore-reserved", no_argument, 0, 'f'},
+ {"ignore-ereg-path", required_argument, 0, 'i'},
+ {"ignore-ereg-partition", required_argument, 0, 'i'},
+ {"ignore-eregi-path", required_argument, 0, 'I'},
+ {"ignore-eregi-partition", required_argument, 0, 'I'},
+ {"ignore-missing", no_argument, 0, IGNORE_MISSING},
+ {"local", no_argument, 0, 'l'},
+ {"stat-remote-fs", no_argument, 0, 'L'},
+ {"iperfdata", no_argument, 0, 'P'},
+ {"mountpoint", no_argument, 0, 'M'},
+ {"errors-only", no_argument, 0, 'e'},
+ {"exact-match", no_argument, 0, 'E'},
+ {"all", no_argument, 0, 'A'},
+ {"verbose", no_argument, 0, 'v'},
+ {"quiet", no_argument, 0, 'q'},
+ {"clear", no_argument, 0, 'C'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED);
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ while (1) {
+ c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEA", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 't': /* timeout period */
+ if (is_integer (optarg)) {
+ timeout_interval = atoi (optarg);
+ break;
+ }
+ else {
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ }
+
+ /* See comments for 'c' */
+ case 'w': /* warning threshold */
+ if (strstr(optarg, "%")) {
+ if (*optarg == '@') {
+ warn_freespace_percent = optarg;
+ } else {
+ xasprintf(&warn_freespace_percent, "@%s", optarg);
+ }
+ } else {
+ if (*optarg == '@') {
+ warn_freespace_units = optarg;
+ } else {
+ xasprintf(&warn_freespace_units, "@%s", optarg);
+ }
+ }
+ break;
+
+ /* Awful mistake where the range values do not make sense. Normally,
+ you alert if the value is within the range, but since we are using
+ freespace, we have to alert if outside the range. Thus we artificially
+ force @ at the beginning of the range, so that it is backwards compatible
+ */
+ case 'c': /* critical threshold */
+ if (strstr(optarg, "%")) {
+ if (*optarg == '@') {
+ crit_freespace_percent = optarg;
+ } else {
+ xasprintf(&crit_freespace_percent, "@%s", optarg);
+ }
+ } else {
+ if (*optarg == '@') {
+ crit_freespace_units = optarg;
+ } else {
+ xasprintf(&crit_freespace_units, "@%s", optarg);
+ }
+ }
+ break;
+
+ case 'W': /* warning inode threshold */
+ if (*optarg == '@') {
+ warn_freeinodes_percent = optarg;
+ } else {
+ xasprintf(&warn_freeinodes_percent, "@%s", optarg);
+ }
+ break;
+ case 'K': /* critical inode threshold */
+ if (*optarg == '@') {
+ crit_freeinodes_percent = optarg;
+ } else {
+ xasprintf(&crit_freeinodes_percent, "@%s", optarg);
+ }
+ break;
+ case 'u':
+ if (units)
+ free(units);
+ if (! strcasecmp (optarg, "bytes")) {
+ mult = (uintmax_t)1;
+ units = strdup ("B");
+ } else if (!strcmp(optarg, "KiB")) {
+ mult = (uintmax_t)1024;
+ units = strdup ("KiB");
+ } else if (! strcmp (optarg, "kB")) {
+ mult = (uintmax_t)1000;
+ units = strdup ("kB");
+ } else if (!strcmp(optarg, "MiB")) {
+ mult = (uintmax_t)1024 * 1024;
+ units = strdup ("MiB");
+ } else if (! strcmp (optarg, "MB")) {
+ mult = (uintmax_t)1000 * 1000;
+ units = strdup ("MB");
+ } else if (!strcmp(optarg, "GiB")) {
+ mult = (uintmax_t)1024 * 1024 * 1024;
+ units = strdup ("GiB");
+ } else if (! strcmp (optarg, "GB")){
+ mult = (uintmax_t)1000 * 1000 * 1000;
+ units = strdup ("GB");
+ } else if (!strcmp(optarg, "TiB")) {
+ mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
+ units = strdup ("TiB");
+ } else if (! strcmp (optarg, "TB")) {
+ mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
+ units = strdup ("TB");
+ } else if (!strcmp(optarg, "PiB")) {
+ mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
+ units = strdup ("PiB");
+ } else if (! strcmp (optarg, "PB")){
+ mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
+ units = strdup ("PB");
+ } else {
+ die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
+ }
+ if (units == NULL)
+ die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
+ break;
+ case 'k': /* display mountpoint */
+ mult = 1024;
+ if (units)
+ free(units);
+ units = strdup ("kiB");
+ break;
+ case 'm': /* display mountpoint */
+ mult = 1024 * 1024;
+ if (units)
+ free(units);
+ units = strdup ("MiB");
+ break;
+ case 'L':
+ stat_remote_fs = 1;
+ /* fallthrough */
+ case 'l':
+ show_local_fs = 1;
+ break;
+ case 'P':
+ display_inodes_perfdata = 1;
+ break;
+ case 'p': /* select path */
+ if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
+ crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
+ warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
+ crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
+ die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
+ }
+
+ /* add parameter if not found. overwrite thresholds if path has already been added */
+ if (! (se = np_find_parameter(path_select_list, optarg))) {
+ se = np_add_parameter(&path_select_list, optarg);
+
+ if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
+ path_ignored = true;
+ break;
+ }
+ }
+ se->group = group;
+ set_all_thresholds(se);
+
+ /* With autofs, it is required to stat() the path before re-populating the mount_list */
+ if (!stat_path(se)) {
+ break;
+ }
+ /* NB: We can't free the old mount_list "just like that": both list pointers and struct
+ * pointers are copied around. One of the reason it wasn't done yet is that other parts
+ * of check_disk need the same kind of cleanup so it'd better be done as a whole */
+ mount_list = read_file_system_list (0);
+ np_set_best_match(se, mount_list, exact_match);
+
+ path_selected = TRUE;
+ break;
+ case 'x': /* exclude path or partition */
+ np_add_name(&dp_exclude_list, optarg);
+ break;
+ case 'X': /* exclude file system type */
+ err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
+ if (err != 0) {
+ regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
+ die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
+ }
+ break;
+ case 'N': /* include file system type */
+ err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
+ if (err != 0) {
+ regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
+ die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
+ }
+ break;
+ case 'v': /* verbose */
+ verbose++;
+ break;
+ case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
+ /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
+ erronly = TRUE;
+ break;
+ case 'e':
+ erronly = TRUE;
+ break;
+ case 'E':
+ if (path_selected)
+ die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
+ exact_match = TRUE;
+ break;
+ case 'f':
+ freespace_ignore_reserved = TRUE;
+ break;
+ case 'g':
+ if (path_selected)
+ die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
+ group = optarg;
+ break;
+ case 'I':
+ cflags |= REG_ICASE;
+ // Intentional fallthrough
+ case 'i':
+ if (!path_selected)
+ die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
+ err = regcomp(&re, optarg, cflags);
+ if (err != 0) {
+ regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
+ die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
+ }
+
+ temp_list = path_select_list;
+
+ previous = NULL;
+ while (temp_list) {
+ if (temp_list->best_match) {
+ if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
+
+ if (verbose >=3)
+ printf("ignoring %s matching regex\n", temp_list->name);
+
+ temp_list = np_del_parameter(temp_list, previous);
+ /* pointer to first element needs to be updated if first item gets deleted */
+ if (previous == NULL)
+ path_select_list = temp_list;
+ } else {
+ previous = temp_list;
+ temp_list = temp_list->name_next;
+ }
+ } else {
+ previous = temp_list;
+ temp_list = temp_list->name_next;
+ }
+ }
+
+
+ cflags = default_cflags;
+ break;
+
+ case IGNORE_MISSING:
+ ignore_missing = true;
+ break;
+ case 'A':
+ optarg = strdup(".*");
+ // Intentional fallthrough
+ case 'R':
+ cflags |= REG_ICASE;
+ // Intentional fallthrough
+ case 'r':
+ if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
+ crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
+ warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
+ crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
+ die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
+ }
+
+ err = regcomp(&re, optarg, cflags);
+ if (err != 0) {
+ regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
+ die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
+ }
+
+ for (me = mount_list; me; me = me->me_next) {
+ if (np_regex_match_mount_entry(me, &re)) {
+ fnd = TRUE;
+ if (verbose >= 3)
+ printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
+
+ /* add parameter if not found. overwrite thresholds if path has already been added */
+ if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
+ se = np_add_parameter(&path_select_list, me->me_mountdir);
+ }
+ se->group = group;
+ set_all_thresholds(se);
+ }
+ }
+
+ if (!fnd && ignore_missing == true) {
+ path_ignored = true;
+ /* path_selected = TRUE;*/
+ break;
+ } else if (!fnd)
+ die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
+ _("Regular expression did not match any path or disk"), optarg);
+
+ fnd = FALSE;
+ path_selected = TRUE;
+ np_set_best_match(path_select_list, mount_list, exact_match);
+ cflags = default_cflags;
+
+ break;
+ case 'M': /* display mountpoint */
+ display_mntp = TRUE;
+ break;
+ case 'C':
+ /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
+ if (path_selected == FALSE) {
+ struct parameter_list *path;
+ for (me = mount_list; me; me = me->me_next) {
+ if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
+ path = np_add_parameter(&path_select_list, me->me_mountdir);
+ path->best_match = me;
+ path->group = group;
+ set_all_thresholds(path);
+ }
+ }
+ warn_freespace_units = NULL;
+ crit_freespace_units = NULL;
+ warn_usedspace_units = NULL;
+ crit_usedspace_units = NULL;
+ warn_freespace_percent = NULL;
+ crit_freespace_percent = NULL;
+ warn_usedspace_percent = NULL;
+ crit_usedspace_percent = NULL;
+ warn_usedinodes_percent = NULL;
+ crit_usedinodes_percent = NULL;
+ warn_freeinodes_percent = NULL;
+ crit_freeinodes_percent = NULL;
+
+ path_selected = FALSE;
+ group = NULL;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* help */
+ usage (_("Unknown argument"));
+ }
+ }
+
+ /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
+ c = optind;
+ if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
+ warn_usedspace_percent = argv[c++];
+
+ if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
+ crit_usedspace_percent = argv[c++];
+
+ if (argc > c) {
+ se = np_add_parameter(&path_select_list, strdup(argv[c++]));
+ path_selected = TRUE;
+ set_all_thresholds(se);
+ }
+
+ if (units == NULL) {
+ units = strdup ("MiB");
+ mult = (uintmax_t)1024 * 1024;
+ }
+
+ return TRUE;
+}
+
+
+
+void
+print_path (const char *mypath)
+{
+ if (mypath == NULL)
+ printf ("\n");
+ else
+ printf (_(" for %s\n"), mypath);
+}
+
+
+void
+set_all_thresholds (struct parameter_list *path)
+{
+ if (path->freespace_units != NULL) free(path->freespace_units);
+ set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
+ if (path->freespace_percent != NULL) free (path->freespace_percent);
+ set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
+ if (path->usedspace_units != NULL) free (path->usedspace_units);
+ set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
+ if (path->usedspace_percent != NULL) free (path->usedspace_percent);
+ set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
+ if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
+ set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
+ if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
+ set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
+}
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
+ printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
+ printf (" %s\n", "-w, --warning=PERCENT%");
+ printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
+ printf (" %s\n", "-c, --critical=PERCENT%");
+ printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
+ printf (" %s\n", "-W, --iwarning=PERCENT%");
+ printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
+ printf (" %s\n", "-K, --icritical=PERCENT%");
+ printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
+ printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
+ printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
+ printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
+ printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
+ printf (" %s\n", "-C, --clear");
+ printf (" %s\n", _("Clear thresholds"));
+ printf (" %s\n", "-E, --exact-match");
+ printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
+ printf (" %s\n", "-e, --errors-only");
+ printf (" %s\n", _("Display only devices/mountpoints with errors"));
+ printf (" %s\n", "-f, --freespace-ignore-reserved");
+ printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
+ printf (" %s\n", "-P, --iperfdata");
+ printf (" %s\n", _("Display inode usage in perfdata"));
+ printf (" %s\n", "-g, --group=NAME");
+ printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
+ printf (" %s\n", "-k, --kilobytes");
+ printf (" %s\n", _("Same as '--units kB'"));
+ printf (" %s\n", "-l, --local");
+ printf (" %s\n", _("Only check local filesystems"));
+ printf (" %s\n", "-L, --stat-remote-fs");
+ printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
+ printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
+ printf (" %s\n", "-M, --mountpoint");
+ printf (" %s\n", _("Display the (block) device instead of the mount point"));
+ printf (" %s\n", "-m, --megabytes");
+ printf (" %s\n", _("Same as '--units MB'"));
+ printf (" %s\n", "-A, --all");
+ printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
+ printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
+ printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
+ printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
+ printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
+ printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
+ printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
+ printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
+ printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
+ printf (" %s\n", "--ignore-missing");
+ printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
+ printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
+ printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (" %s\n", "-u, --units=STRING");
+ printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
+ printf (UT_VERBOSE);
+ printf (" %s\n", "-X, --exclude-type=TYPE_REGEX");
+ printf (" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
+ printf (" %s\n", "-N, --include-type=TYPE_REGEX");
+ printf (" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
+
+ printf ("\n");
+ printf ("%s\n", _("General usage hints:"));
+ printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
+ printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
+ printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
+
+
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
+ printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
+ printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
+ printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
+ printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
+ printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
+ printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K inode_percentage_limit } {-p path | -x device}\n", progname);
+ printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
+ printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
+}
+
+bool
+stat_path (struct parameter_list *p)
+{
+ /* Stat entry to check that dir exists and is accessible */
+ if (verbose >= 3)
+ printf("calling stat on %s\n", p->name);
+ if (stat (p->name, &stat_buf[0])) {
+ if (verbose >= 3)
+ printf("stat failed on %s\n", p->name);
+ if (ignore_missing == true) {
+ return false;
+ } else {
+ printf("DISK %s - ", _("CRITICAL"));
+ die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
+ }
+ }
+ return true;
+}
+
+
+void
+get_stats (struct parameter_list *p, struct fs_usage *fsp) {
+ struct parameter_list *p_list;
+ struct fs_usage tmpfsp;
+ int first = 1;
+
+ if (p->group == NULL) {
+ get_path_stats(p,fsp);
+ } else {
+ /* find all group members */
+ for (p_list = path_select_list; p_list; p_list=p_list->name_next) {
+#ifdef __CYGWIN__
+ if (strncmp(p_list->name, "/cygdrive/", 10) != 0)
+ continue;
+#endif
+ if (p_list->group && ! (strcmp(p_list->group, p->group))) {
+ if (! stat_path(p_list))
+ continue;
+ get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
+ get_path_stats(p_list, &tmpfsp);
+ if (verbose >= 3)
+ printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
+ p_list->group,
+ tmpfsp.fsu_blocks,
+ tmpfsp.fsu_blocksize,
+ p_list->best_match->me_mountdir,
+ p_list->dused_units,
+ p_list->dfree_units,
+ p_list->dtotal_units,
+ mult);
+
+ /* prevent counting the first FS of a group twice since its parameter_list entry
+ * is used to carry the information of all file systems of the entire group */
+ if (! first) {
+ p->total += p_list->total;
+ p->available += p_list->available;
+ p->available_to_root += p_list->available_to_root;
+ p->used += p_list->used;
+
+ p->dused_units += p_list->dused_units;
+ p->dfree_units += p_list->dfree_units;
+ p->dtotal_units += p_list->dtotal_units;
+ p->inodes_total += p_list->inodes_total;
+ p->inodes_free += p_list->inodes_free;
+ p->inodes_free_to_root += p_list->inodes_free_to_root;
+ p->inodes_used += p_list->inodes_used;
+ }
+ first = 0;
+ }
+ if (verbose >= 3)
+ printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n",
+ p->group,
+ p->dused_units,
+ p->dfree_units,
+ p->dtotal_units,
+ tmpfsp.fsu_blocksize,
+ mult);
+ }
+ /* modify devname and mountdir for output */
+ p->best_match->me_mountdir = p->best_match->me_devname = p->group;
+ }
+ /* finally calculate percentages for either plain FS or summed up group */
+ p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */
+ p->dfree_pct = 100 - p->dused_pct;
+ p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
+ p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
+
+}
+
+void
+get_path_stats (struct parameter_list *p, struct fs_usage *fsp) {
+ p->available = fsp->fsu_bavail;
+ p->available_to_root = fsp->fsu_bfree;
+ p->used = fsp->fsu_blocks - fsp->fsu_bfree;
+ if (freespace_ignore_reserved) {
+ /* option activated : we subtract the root-reserved space from the total */
+ p->total = fsp->fsu_blocks - p->available_to_root + p->available;
+ } else {
+ /* default behaviour : take all the blocks into account */
+ p->total = fsp->fsu_blocks;
+ }
+
+ p->dused_units = p->used*fsp->fsu_blocksize/mult;
+ p->dfree_units = p->available*fsp->fsu_blocksize/mult;
+ p->dtotal_units = p->total*fsp->fsu_blocksize/mult;
+ /* Free file nodes. Not sure the workaround is required, but in case...*/
+ p->inodes_free = fsp->fsu_ffree;
+ p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */
+ p->inodes_used = fsp->fsu_files - fsp->fsu_ffree;
+ if (freespace_ignore_reserved) {
+ /* option activated : we subtract the root-reserved inodes from the total */
+ /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
+ /* for others, fsp->fsu_ffree == fsp->fsu_favail */
+ p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free;
+ } else {
+ /* default behaviour : take all the inodes into account */
+ p->inodes_total = fsp->fsu_files;
+ }
+ np_add_name(&seen, p->best_match->me_mountdir);
+}
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
new file mode 100644
index 0000000..7ffce98
--- /dev/null
+++ b/plugins/check_dns.c
@@ -0,0 +1,619 @@
+/*****************************************************************************
+*
+* Monitoring check_dns plugin
+*
+* License: GPL
+* Copyright (c) 2000-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_dns plugin
+*
+* LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which
+* will not be picked up by this plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_dns";
+const char *copyright = "2000-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_base.h"
+#include "netutils.h"
+#include "runcmd.h"
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+int error_scan (char *, int *);
+int ip_match_cidr(const char *, const char *);
+unsigned long ip2long(const char *);
+void print_help (void);
+void print_usage (void);
+
+#define ADDRESS_LENGTH 256
+char query_address[ADDRESS_LENGTH] = "";
+char dns_server[ADDRESS_LENGTH] = "";
+char ptr_server[ADDRESS_LENGTH] = "";
+int verbose = FALSE;
+char **expected_address = NULL;
+int expected_address_cnt = 0;
+int expect_nxdomain = FALSE;
+
+int expect_authority = FALSE;
+int all_match = FALSE;
+thresholds *time_thresholds = NULL;
+
+static int
+qstrcmp(const void *p1, const void *p2)
+{
+ /* The actual arguments to this function are "pointers to
+ pointers to char", but strcmp() arguments are "pointers
+ to char", hence the following cast plus dereference */
+ return strcmp(* (char * const *) p1, * (char * const *) p2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ char *command_line = NULL;
+ char input_buffer[MAX_INPUT_BUFFER];
+ char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
+ char **addresses = NULL;
+ int n_addresses = 0;
+ char *msg = NULL;
+ char *temp_buffer = NULL;
+ int non_authoritative = FALSE;
+ int result = STATE_UNKNOWN;
+ double elapsed_time;
+ long microsec;
+ struct timeval tv;
+ int parse_address = FALSE; /* This flag scans for Address: but only after Name: */
+ output chld_out, chld_err;
+ size_t i;
+ int is_nxdomain = FALSE;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
+ usage_va(_("Cannot catch SIGALRM"));
+ }
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR) {
+ usage_va(_("Could not parse arguments"));
+ }
+
+ /* get the command to run */
+ xasprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
+
+ alarm (timeout_interval);
+ gettimeofday (&tv, NULL);
+
+ if (verbose)
+ printf ("%s\n", command_line);
+
+ /* run the command */
+ if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
+ msg = (char *)_("nslookup returned an error status");
+ result = STATE_WARNING;
+ }
+
+ /* scan stdout */
+ for(i = 0; i < chld_out.lines; i++) {
+ if (addresses == NULL)
+ addresses = malloc(sizeof(*addresses)*10);
+ else if (!(n_addresses % 10))
+ addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10));
+
+ if (verbose)
+ puts(chld_out.line[i]);
+
+ if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) {
+ if ((temp_buffer = strstr (chld_out.line[i], "name = ")))
+ addresses[n_addresses++] = strdup (temp_buffer + 7);
+ else {
+ msg = (char *)_("Warning plugin error");
+ result = STATE_WARNING;
+ }
+ }
+
+ /* bug ID: 2946553 - Older versions of bind will use all available dns
+ servers, we have to match the one specified */
+ if (strstr (chld_out.line[i], "Server:") && strlen(dns_server) > 0) {
+ temp_buffer = strchr (chld_out.line[i], ':');
+ temp_buffer++;
+
+ /* Strip leading tabs */
+ for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++)
+ /* NOOP */;
+
+ strip(temp_buffer);
+ if (temp_buffer==NULL || strlen(temp_buffer)==0) {
+ die (STATE_CRITICAL,
+ _("DNS CRITICAL - '%s' returned empty server string\n"),
+ NSLOOKUP_COMMAND);
+ }
+
+ if (strcmp(temp_buffer, dns_server) != 0) {
+ die (STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server);
+ }
+ }
+
+ /* the server is responding, we just got the host name... */
+ if (strstr (chld_out.line[i], "Name:"))
+ parse_address = TRUE;
+ else if (parse_address == TRUE && (strstr (chld_out.line[i], "Address:") ||
+ strstr (chld_out.line[i], "Addresses:"))) {
+ temp_buffer = index (chld_out.line[i], ':');
+ temp_buffer++;
+
+ /* Strip leading spaces */
+ while (*temp_buffer == ' ')
+ temp_buffer++;
+
+ strip(temp_buffer);
+ if (temp_buffer==NULL || strlen(temp_buffer)==0) {
+ die (STATE_CRITICAL,
+ _("DNS CRITICAL - '%s' returned empty host name string\n"),
+ NSLOOKUP_COMMAND);
+ }
+
+ addresses[n_addresses++] = strdup(temp_buffer);
+ }
+ else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) {
+ non_authoritative = TRUE;
+ }
+
+
+ result = error_scan (chld_out.line[i], &is_nxdomain);
+ if (result != STATE_OK) {
+ msg = strchr (chld_out.line[i], ':');
+ if(msg) msg++;
+ break;
+ }
+ }
+
+ /* scan stderr */
+ for(i = 0; i < chld_err.lines; i++) {
+ if (verbose)
+ puts(chld_err.line[i]);
+
+ if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) {
+ result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain));
+ msg = strchr(input_buffer, ':');
+ if(msg)
+ msg++;
+ else
+ msg = input_buffer;
+ }
+ }
+
+ if (is_nxdomain && !expect_nxdomain) {
+ die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
+ }
+
+ if (addresses) {
+ int i,slen;
+ char *adrp;
+ qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
+ for(i=0, slen=1; i < n_addresses; i++) {
+ slen += strlen(addresses[i])+1;
+ }
+ adrp = address = malloc(slen);
+ for(i=0; i < n_addresses; i++) {
+ if (i) *adrp++ = ',';
+ strcpy(adrp, addresses[i]);
+ adrp += strlen(addresses[i]);
+ }
+ *adrp = 0;
+ } else
+ die (STATE_CRITICAL,
+ _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
+ NSLOOKUP_COMMAND);
+
+ /* compare to expected address */
+ if (result == STATE_OK && expected_address_cnt > 0) {
+ result = STATE_CRITICAL;
+ temp_buffer = "";
+ unsigned long expect_match = (1 << expected_address_cnt) - 1;
+ unsigned long addr_match = (1 << n_addresses) - 1;
+
+ for (i=0; i<expected_address_cnt; i++) {
+ int j;
+ /* check if we get a match on 'raw' ip or cidr */
+ for (j=0; j<n_addresses; j++) {
+ if ( strcmp(addresses[j], expected_address[i]) == 0
+ || ip_match_cidr(addresses[j], expected_address[i]) ) {
+ result = STATE_OK;
+ addr_match &= ~(1 << j);
+ expect_match &= ~(1 << i);
+ }
+ }
+
+ /* prepare an error string */
+ xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
+ }
+ /* check if expected_address must cover all in addresses and none may be missing */
+ if (all_match && (expect_match != 0 || addr_match != 0))
+ result = STATE_CRITICAL;
+ if (result == STATE_CRITICAL) {
+ /* Strip off last semicolon... */
+ temp_buffer[strlen(temp_buffer)-2] = '\0';
+ xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
+ }
+ }
+
+ if (expect_nxdomain) {
+ if (!is_nxdomain) {
+ result = STATE_CRITICAL;
+ xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
+ } else {
+ if (address != NULL) free(address);
+ address = "NXDOMAIN";
+ }
+ }
+
+ /* check if authoritative */
+ if (result == STATE_OK && expect_authority && non_authoritative) {
+ result = STATE_CRITICAL;
+ xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
+ }
+
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ if (result == STATE_OK) {
+ result = get_status(elapsed_time, time_thresholds);
+ if (result == STATE_OK) {
+ printf ("DNS %s: ", _("OK"));
+ } else if (result == STATE_WARNING) {
+ printf ("DNS %s: ", _("WARNING"));
+ } else if (result == STATE_CRITICAL) {
+ printf ("DNS %s: ", _("CRITICAL"));
+ }
+ printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
+ printf (_(". %s returns %s"), query_address, address);
+ if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
+ printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+ TRUE, time_thresholds->warning->end,
+ TRUE, time_thresholds->critical->end,
+ TRUE, 0, FALSE, 0));
+ } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
+ printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+ FALSE, 0,
+ TRUE, time_thresholds->critical->end,
+ TRUE, 0, FALSE, 0));
+ } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
+ printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
+ TRUE, time_thresholds->warning->end,
+ FALSE, 0,
+ TRUE, 0, FALSE, 0));
+ } else
+ printf ("|%s\n", fperfdata ("time", elapsed_time, "s", FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
+ }
+ else if (result == STATE_WARNING)
+ printf (_("DNS WARNING - %s\n"),
+ !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
+ else if (result == STATE_CRITICAL)
+ printf (_("DNS CRITICAL - %s\n"),
+ !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
+ else
+ printf (_("DNS UNKNOWN - %s\n"),
+ !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
+
+ return result;
+}
+
+int
+ip_match_cidr(const char *addr, const char *cidr_ro)
+{
+ char *subnet, *mask_c, *cidr = strdup(cidr_ro);
+ int mask;
+ subnet = strtok(cidr, "/");
+ mask_c = strtok(NULL, "\0");
+ if (!subnet || !mask_c)
+ return FALSE;
+ mask = atoi(mask_c);
+
+ /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */
+ return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask);
+}
+
+unsigned long
+ip2long(const char* src) {
+ unsigned long ip[4];
+ /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
+ return (sscanf(src, "%3lu.%3lu.%3lu.%3lu",
+ &ip[0], &ip[1], &ip[2], &ip[3]) == 4 &&
+ ip[0] < 256 && ip[1] < 256 &&
+ ip[2] < 256 && ip[3] < 256)
+ ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
+ : 0;
+}
+
+int
+error_scan (char *input_buffer, int *is_nxdomain)
+{
+
+ const int nxdomain = strstr (input_buffer, "Non-existent") ||
+ strstr (input_buffer, "** server can't find") ||
+ strstr (input_buffer, "** Can't find") ||
+ strstr (input_buffer, "NXDOMAIN");
+ if (nxdomain) *is_nxdomain = TRUE;
+
+ /* the DNS lookup timed out */
+ if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
+ strstr (input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
+ strstr (input_buffer, _("the `-sil[ent]' option to prevent this message from appearing.")))
+ return STATE_OK;
+
+ /* DNS server is not running... */
+ else if (strstr (input_buffer, "No response from server"))
+ die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
+ else if (strstr (input_buffer, "no servers could be reached"))
+ die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
+
+ /* Host name is valid, but server doesn't have records... */
+ else if (strstr (input_buffer, "No records"))
+ die (STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
+
+ /* Connection was refused */
+ else if (strstr (input_buffer, "Connection refused") ||
+ strstr (input_buffer, "Couldn't find server") ||
+ strstr (input_buffer, "Refused") ||
+ (strstr (input_buffer, "** server can't find") &&
+ strstr (input_buffer, ": REFUSED")))
+ die (STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
+
+ /* Query refused (usually by an ACL in the namserver) */
+ else if (strstr (input_buffer, "Query refused"))
+ die (STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
+
+ /* No information (e.g. nameserver IP has two PTR records) */
+ else if (strstr (input_buffer, "No information"))
+ die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
+
+ /* Network is unreachable */
+ else if (strstr (input_buffer, "Network is unreachable"))
+ die (STATE_CRITICAL, _("Network is unreachable\n"));
+
+ /* Internal server failure */
+ else if (strstr (input_buffer, "Server failure"))
+ die (STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
+
+ /* Request error or the DNS lookup timed out */
+ else if (strstr (input_buffer, "Format error") ||
+ strstr (input_buffer, "Timed out"))
+ return STATE_WARNING;
+
+ return STATE_OK;
+
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char *warning = NULL;
+ char *critical = NULL;
+
+ int opt_index = 0;
+ static struct option long_opts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {"server", required_argument, 0, 's'},
+ {"reverse-server", required_argument, 0, 'r'},
+ {"expected-address", required_argument, 0, 'a'},
+ {"expect-nxdomain", no_argument, 0, 'n'},
+ {"expect-authority", no_argument, 0, 'A'},
+ {"all", no_argument, 0, 'L'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* version */
+ verbose = TRUE;
+ break;
+ case 't': /* timeout period */
+ timeout_interval = atoi (optarg);
+ break;
+ case 'H': /* hostname */
+ if (strlen (optarg) >= ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ strcpy (query_address, optarg);
+ break;
+ case 's': /* server name */
+ /* TODO: this host_or_die check is probably unnecessary.
+ * Better to confirm nslookup response matches */
+ host_or_die(optarg);
+ if (strlen (optarg) >= ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ strcpy (dns_server, optarg);
+ break;
+ case 'r': /* reverse server name */
+ /* TODO: Is this host_or_die necessary? */
+ host_or_die(optarg);
+ if (strlen (optarg) >= ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ strcpy (ptr_server, optarg);
+ break;
+ case 'a': /* expected address */
+ if (strlen (optarg) >= ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ if (strchr(optarg, ',') != NULL) {
+ char *comma = strchr(optarg, ',');
+ while (comma != NULL) {
+ expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
+ expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
+ expected_address_cnt++;
+ optarg = comma + 1;
+ comma = strchr(optarg, ',');
+ }
+ expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
+ expected_address[expected_address_cnt] = strdup(optarg);
+ expected_address_cnt++;
+ } else {
+ expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
+ expected_address[expected_address_cnt] = strdup(optarg);
+ expected_address_cnt++;
+ }
+ break;
+ case 'n': /* expect NXDOMAIN */
+ expect_nxdomain = TRUE;
+ break;
+ case 'A': /* expect authority */
+ expect_authority = TRUE;
+ break;
+ case 'L': /* all must match */
+ all_match = TRUE;
+ break;
+ case 'w':
+ warning = optarg;
+ break;
+ case 'c':
+ critical = optarg;
+ break;
+ default: /* args not parsable */
+ usage5();
+ }
+ }
+
+ c = optind;
+ if (strlen(query_address)==0 && c<argc) {
+ if (strlen(argv[c])>=ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ strcpy (query_address, argv[c++]);
+ }
+
+ if (strlen(dns_server)==0 && c<argc) {
+ /* TODO: See -s option */
+ host_or_die(argv[c]);
+ if (strlen(argv[c]) >= ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ strcpy (dns_server, argv[c++]);
+ }
+
+ set_thresholds(&time_thresholds, warning, critical);
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments ()
+{
+ if (query_address[0] == 0) {
+ printf ("missing --host argument\n");
+ return ERROR;
+ }
+
+ if (expected_address_cnt > 0 && expect_nxdomain) {
+ printf ("--expected-address and --expect-nxdomain cannot be combined\n");
+ return ERROR;
+ }
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
+ printf ("%s\n", _("An optional DNS server to use may be specified."));
+ printf ("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" -H, --hostname=HOST\n");
+ printf (" %s\n", _("The name or address you want to query"));
+ printf (" -s, --server=HOST\n");
+ printf (" %s\n", _("Optional DNS server you want to use for the lookup"));
+ printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
+ printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
+ printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
+ printf (" %s\n", _("value matches)."));
+ printf (" -n, --expect-nxdomain\n");
+ printf (" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
+ printf (" %s\n", _("Cannot be used together with -a"));
+ printf (" -A, --expect-authority\n");
+ printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
+ printf (" -w, --warning=seconds\n");
+ printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
+ printf (" -c, --critical=seconds\n");
+ printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
+ printf (" -L, --all\n");
+ printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
+ printf (" %s\n", _("returned. Default off"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
+}
diff --git a/plugins/check_dummy.c b/plugins/check_dummy.c
new file mode 100644
index 0000000..212a134
--- /dev/null
+++ b/plugins/check_dummy.c
@@ -0,0 +1,124 @@
+/*****************************************************************************
+*
+* Monitoring check_dummy plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_dummy plugin
+*
+* This plugin will simply return the state corresponding to the numeric value
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_dummy";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+
+void print_help (void);
+void print_usage (void);
+
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ if (argc < 2)
+ usage4 (_("Could not parse arguments"));
+ else if (strcmp (argv[1], "-V") == 0 || strcmp (argv[1], "--version") == 0) {
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ }
+ else if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
+ print_help ();
+ exit (STATE_UNKNOWN);
+ }
+ else if (!is_integer (argv[1]))
+ usage4 (_("Arguments to check_dummy must be an integer"));
+ else
+ result = atoi (argv[1]);
+
+ switch (result) {
+ case STATE_OK:
+ printf (_("OK"));
+ break;
+ case STATE_WARNING:
+ printf (_("WARNING"));
+ break;
+ case STATE_CRITICAL:
+ printf (_("CRITICAL"));
+ break;
+ case STATE_UNKNOWN:
+ printf (_("UNKNOWN"));
+ break;
+ default:
+ printf (_("UNKNOWN"));
+ printf (": ");
+ printf (_("Status %d is not a supported error state\n"), result);
+ return STATE_UNKNOWN;
+ }
+
+ if (argc >= 3)
+ printf (": %s", argv[2]);
+
+ printf("\n");
+
+ return result;
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin will simply return the state corresponding to the numeric value"));
+
+ printf ("%s\n", _("of the <state> argument with optional text"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s <integer state> [optional text]\n", progname);
+}
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
new file mode 100644
index 0000000..23a9e99
--- /dev/null
+++ b/plugins/check_fping.c
@@ -0,0 +1,527 @@
+/*****************************************************************************
+*
+* Monitoring check_fping plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_disk plugin
+*
+* This plugin will use the fping command to ping the specified host for a
+* fast check
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_fping";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "popen.h"
+#include "netutils.h"
+#include "utils.h"
+#include <stdbool.h>
+
+enum {
+ PACKET_COUNT = 1,
+ PACKET_SIZE = 56,
+ PL = 0,
+ RTA = 1
+};
+
+int textscan (char *buf);
+int process_arguments (int, char **);
+int get_threshold (char *arg, char *rv[2]);
+void print_help (void);
+void print_usage (void);
+
+char *server_name = NULL;
+char *sourceip = NULL;
+char *sourceif = NULL;
+int packet_size = PACKET_SIZE;
+int packet_count = PACKET_COUNT;
+int target_timeout = 0;
+int packet_interval = 0;
+int verbose = FALSE;
+int cpl;
+int wpl;
+double crta;
+double wrta;
+int cpl_p = FALSE;
+int wpl_p = FALSE;
+bool alive_p = FALSE;
+int crta_p = FALSE;
+int wrta_p = FALSE;
+
+int
+main (int argc, char **argv)
+{
+/* normally should be int result = STATE_UNKNOWN; */
+
+ int status = STATE_UNKNOWN;
+ int result = 0;
+ char *fping_prog = NULL;
+ char *server = NULL;
+ char *command_line = NULL;
+ char *input_buffer = NULL;
+ char *option_string = "";
+ input_buffer = malloc (MAX_INPUT_BUFFER);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ server = strscpy (server, server_name);
+
+ /* compose the command */
+ if (target_timeout)
+ xasprintf(&option_string, "%s-t %d ", option_string, target_timeout);
+ if (packet_interval)
+ xasprintf(&option_string, "%s-p %d ", option_string, packet_interval);
+ if (sourceip)
+ xasprintf(&option_string, "%s-S %s ", option_string, sourceip);
+ if (sourceif)
+ xasprintf(&option_string, "%s-I %s ", option_string, sourceif);
+
+#ifdef PATH_TO_FPING6
+ if (address_family != AF_INET && is_inet6_addr(server))
+ fping_prog = strdup(PATH_TO_FPING6);
+ else
+ fping_prog = strdup(PATH_TO_FPING);
+#else
+ fping_prog = strdup(PATH_TO_FPING);
+#endif
+
+ xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog,
+ option_string, packet_size, packet_count, server);
+
+ if (verbose)
+ printf ("%s\n", command_line);
+
+ /* run the command */
+ child_process = spopen (command_line);
+ if (child_process == NULL) {
+ printf (_("Could not open pipe: %s\n"), command_line);
+ return STATE_UNKNOWN;
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL) {
+ printf (_("Could not open stderr for %s\n"), command_line);
+ }
+
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+ if (verbose)
+ printf ("%s", input_buffer);
+ status = max_state (status, textscan (input_buffer));
+ }
+
+ /* If we get anything on STDERR, at least set warning */
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
+ status = max_state (status, STATE_WARNING);
+ if (verbose)
+ printf ("%s", input_buffer);
+ status = max_state (status, textscan (input_buffer));
+ }
+ (void) fclose (child_stderr);
+
+ /* close the pipe */
+ result = spclose (child_process);
+ if (result) {
+ /* need to use max_state not max */
+ status = max_state (status, STATE_WARNING);
+ }
+
+ if (result > 1 ) {
+ status = max_state (status, STATE_UNKNOWN);
+ if (result == 2) {
+ die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
+ }
+ if (result == 3) {
+ die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
+ }
+ if (result == 4) {
+ die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
+ }
+
+ }
+
+ printf ("FPING %s - %s\n", state_text (status), server_name);
+
+ return status;
+}
+
+
+int textscan (char *buf) {
+ char *rtastr = NULL;
+ char *losstr = NULL;
+ char *xmtstr = NULL;
+ double loss;
+ double rta;
+ double xmt;
+ int status = STATE_UNKNOWN;
+
+ /* stops testing after the first successful reply. */
+ if (alive_p && strstr(buf, "avg, 0% loss)")) {
+ rtastr = strstr (buf, "ms (");
+ rtastr = 1 + index(rtastr, '(');
+ rta = strtod(rtastr, NULL);
+ loss=strtod("0",NULL);
+ die (STATE_OK,
+ _("FPING %s - %s (rta=%f ms)|%s\n"),
+ state_text (STATE_OK), server_name,rta,
+ /* No loss since we only waited for the first reply
+ perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100), */
+ fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, TRUE, 0, FALSE, 0));
+ }
+
+ if (strstr (buf, "not found")) {
+ die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
+
+ }
+ else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) {
+ die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"),
+ "host");
+
+ }
+ else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) {
+ die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"),
+ "host");
+ }
+ else if (strstr (buf, "is down")) {
+ die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
+
+ }
+ else if (strstr (buf, "is alive")) {
+ status = STATE_OK;
+
+ }
+ else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) {
+ losstr = strstr (buf, "=");
+ losstr = 1 + strstr (losstr, "/");
+ losstr = 1 + strstr (losstr, "/");
+ rtastr = strstr (buf, "min/avg/max");
+ rtastr = strstr (rtastr, "=");
+ rtastr = 1 + index (rtastr, '/');
+ loss = strtod (losstr, NULL);
+ rta = strtod (rtastr, NULL);
+ if (cpl_p == TRUE && loss > cpl)
+ status = STATE_CRITICAL;
+ else if (crta_p == TRUE && rta > crta)
+ status = STATE_CRITICAL;
+ else if (wpl_p == TRUE && loss > wpl)
+ status = STATE_WARNING;
+ else if (wrta_p == TRUE && rta > wrta)
+ status = STATE_WARNING;
+ else
+ status = STATE_OK;
+ die (status,
+ _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"),
+ state_text (status), server_name, loss, rta,
+ perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100),
+ fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, TRUE, 0, FALSE, 0));
+
+ }
+ else if(strstr (buf, "xmt/rcv/%loss") ) {
+ /* no min/max/avg if host was unreachable in fping v2.2.b1 */
+ /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
+ losstr = strstr (buf, "=");
+ xmtstr = 1 + losstr;
+ xmt = strtod (xmtstr, NULL);
+ if(xmt == 0)
+ die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
+ losstr = 1 + strstr (losstr, "/");
+ losstr = 1 + strstr (losstr, "/");
+ loss = strtod (losstr, NULL);
+ if (atoi(losstr) == 100)
+ status = STATE_CRITICAL;
+ else if (cpl_p == TRUE && loss > cpl)
+ status = STATE_CRITICAL;
+ else if (wpl_p == TRUE && loss > wpl)
+ status = STATE_WARNING;
+ else
+ status = STATE_OK;
+ /* loss=%.0f%%;%d;%d;0;100 */
+ die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
+ state_text (status), server_name, loss ,
+ perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100));
+
+ }
+ else {
+ status = max_state (status, STATE_WARNING);
+ }
+
+ return status;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char *rv[2];
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"sourceip", required_argument, 0, 'S'},
+ {"sourceif", required_argument, 0, 'I'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"alive", no_argument, 0, 'a'},
+ {"bytes", required_argument, 0, 'b'},
+ {"number", required_argument, 0, 'n'},
+ {"target-timeout", required_argument, 0, 'T'},
+ {"interval", required_argument, 0, 'i'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {0, 0, 0, 0}
+ };
+
+ rv[PL] = NULL;
+ rv[RTA] = NULL;
+
+ if (argc < 2)
+ return ERROR;
+
+ if (!is_option (argv[1])) {
+ server_name = argv[1];
+ argv[1] = argv[0];
+ argv = &argv[1];
+ argc--;
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts, &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'a': /* host alive mode */
+ alive_p = TRUE;
+ break;
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* verbose mode */
+ verbose = TRUE;
+ break;
+ case 'H': /* hostname */
+ if (is_host (optarg) == FALSE) {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ server_name = strscpy (server_name, optarg);
+ break;
+ case 'S': /* sourceip */
+ if (is_host (optarg) == FALSE) {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ sourceip = strscpy (sourceip, optarg);
+ break;
+ case 'I': /* sourceip */
+ sourceif = strscpy (sourceif, optarg);
+ break;
+ case '4': /* IPv4 only */
+ address_family = AF_INET;
+ break;
+ case '6': /* IPv6 only */
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage (_("IPv6 support not available\n"));
+#endif
+ break;
+ case 'c':
+ get_threshold (optarg, rv);
+ if (rv[RTA]) {
+ crta = strtod (rv[RTA], NULL);
+ crta_p = TRUE;
+ rv[RTA] = NULL;
+ }
+ if (rv[PL]) {
+ cpl = atoi (rv[PL]);
+ cpl_p = TRUE;
+ rv[PL] = NULL;
+ }
+ break;
+ case 'w':
+ get_threshold (optarg, rv);
+ if (rv[RTA]) {
+ wrta = strtod (rv[RTA], NULL);
+ wrta_p = TRUE;
+ rv[RTA] = NULL;
+ }
+ if (rv[PL]) {
+ wpl = atoi (rv[PL]);
+ wpl_p = TRUE;
+ rv[PL] = NULL;
+ }
+ break;
+ case 'b': /* bytes per packet */
+ if (is_intpos (optarg))
+ packet_size = atoi (optarg);
+ else
+ usage (_("Packet size must be a positive integer"));
+ break;
+ case 'n': /* number of packets */
+ if (is_intpos (optarg))
+ packet_count = atoi (optarg);
+ else
+ usage (_("Packet count must be a positive integer"));
+ break;
+ case 'T': /* timeout in msec */
+ if (is_intpos (optarg))
+ target_timeout = atoi (optarg);
+ else
+ usage (_("Target timeout must be a positive integer"));
+ break;
+ case 'i': /* interval in msec */
+ if (is_intpos (optarg))
+ packet_interval = atoi (optarg);
+ else
+ usage (_("Interval must be a positive integer"));
+ break;
+ }
+ }
+
+ if (server_name == NULL)
+ usage4 (_("Hostname was not supplied"));
+
+ return OK;
+}
+
+
+int
+get_threshold (char *arg, char *rv[2])
+{
+ char *arg1 = NULL;
+ char *arg2 = NULL;
+
+ arg1 = strscpy (arg1, arg);
+ if (strpbrk (arg1, ",:"))
+ arg2 = 1 + strpbrk (arg1, ",:");
+
+ if (arg2) {
+ arg1[strcspn (arg1, ",:")] = 0;
+ if (strstr (arg1, "%") && strstr (arg2, "%"))
+ die (STATE_UNKNOWN,
+ _("%s: Only one threshold may be packet loss (%s)\n"), progname,
+ arg);
+ if (!strstr (arg1, "%") && !strstr (arg2, "%"))
+ die (STATE_UNKNOWN,
+ _("%s: Only one threshold must be packet loss (%s)\n"),
+ progname, arg);
+ }
+
+ if (arg2 && strstr (arg2, "%")) {
+ rv[PL] = arg2;
+ rv[RTA] = arg1;
+ }
+ else if (arg2) {
+ rv[PL] = arg1;
+ rv[RTA] = arg2;
+ }
+ else if (strstr (arg1, "%")) {
+ rv[PL] = arg1;
+ }
+ else {
+ rv[RTA] = arg1;
+ }
+
+ return OK;
+}
+
+
+void print_help (void) {
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
+
+ printf ("%s\n", _("Note that it is necessary to set the suid flag on fping."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-H, --hostname=HOST");
+ printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("warning threshold pair"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("critical threshold pair"));
+ printf (" %s\n", "-a, --alive");
+ printf (" %s\n", _("Return OK after first successful reply"));
+ printf (" %s\n", "-b, --bytes=INTEGER");
+ printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE);
+ printf (" %s\n", "-n, --number=INTEGER");
+ printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT);
+ printf (" %s\n", "-T, --target-timeout=INTEGER");
+ printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
+ printf (" %s\n", "-i, --interval=INTEGER");
+ printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
+ printf (" %s\n", "-S, --sourceip=HOST");
+ printf (" %s\n", _("name or IP Address of sourceip"));
+ printf (" %s\n", "-I, --sourceif=IF");
+ printf (" %s\n", _("source interface name"));
+ printf (UT_VERBOSE);
+ printf ("\n");
+ printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
+ printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
+ printf (" %s\n", _("packet loss to trigger an alarm state."));
+
+ printf ("\n");
+ printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
+}
diff --git a/plugins/check_game.c b/plugins/check_game.c
new file mode 100644
index 0000000..a534b69
--- /dev/null
+++ b/plugins/check_game.c
@@ -0,0 +1,348 @@
+/*****************************************************************************
+*
+* Monitoring check_game plugin
+*
+* License: GPL
+* Copyright (c) 2002-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_game plugin
+*
+* This plugin tests game server connections with the specified host.
+* using the qstat program
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_game";
+const char *copyright = "2002-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "runcmd.h"
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+#define QSTAT_DATA_DELIMITER ","
+
+#define QSTAT_HOST_ERROR "ERROR"
+#define QSTAT_HOST_DOWN "DOWN"
+#define QSTAT_HOST_TIMEOUT "TIMEOUT"
+#define QSTAT_MAX_RETURN_ARGS 12
+
+char *server_ip;
+char *game_type;
+int port = 0;
+
+int verbose;
+
+int qstat_game_players_max = -1;
+int qstat_game_players = -1;
+int qstat_game_field = -1;
+int qstat_map_field = -1;
+int qstat_ping_field = -1;
+
+
+int
+main (int argc, char **argv)
+{
+ char *command_line;
+ int result = STATE_UNKNOWN;
+ char *p, *ret[QSTAT_MAX_RETURN_ARGS];
+ size_t i = 0;
+ output chld_out;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage_va(_("Could not parse arguments"));
+
+ result = STATE_OK;
+
+ /* create the command line to execute */
+ xasprintf (&command_line, "%s -raw %s -%s %s",
+ PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
+
+ if (port)
+ xasprintf (&command_line, "%s:%-d", command_line, port);
+
+ if (verbose > 0)
+ printf ("%s\n", command_line);
+
+ /* run the command. historically, this plugin ignores output on stderr,
+ * as well as return status of the qstat program */
+ (void)np_runcmd(command_line, &chld_out, NULL, 0);
+
+ /* sanity check */
+ /* was thinking about running qstat without any options, capturing the
+ -default line, parsing it & making an array of all know server types
+ but thought this would be too much hassle considering this is a tool
+ for intelligent sysadmins (ha). Could put a static array of known
+ server types in a header file but then we'd be limiting ourselves
+
+ In the end, I figured I'd simply let an error occur & then trap it
+ */
+
+ if (!strncmp (chld_out.line[0], "unknown option", 14)) {
+ printf (_("CRITICAL - Host type parameter incorrect!\n"));
+ result = STATE_CRITICAL;
+ return result;
+ }
+
+ p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
+ while (p != NULL) {
+ ret[i] = p;
+ p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
+ i++;
+ if (i >= QSTAT_MAX_RETURN_ARGS)
+ break;
+ }
+
+ if (strstr (ret[2], QSTAT_HOST_ERROR)) {
+ printf (_("CRITICAL - Host not found\n"));
+ result = STATE_CRITICAL;
+ }
+ else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
+ printf (_("CRITICAL - Game server down or unavailable\n"));
+ result = STATE_CRITICAL;
+ }
+ else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
+ printf (_("CRITICAL - Game server timeout\n"));
+ result = STATE_CRITICAL;
+ }
+ else {
+ printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n",
+ ret[qstat_game_players],
+ ret[qstat_game_players_max],
+ ret[qstat_game_field],
+ ret[qstat_map_field],
+ ret[qstat_ping_field],
+ perfdata ("players", atol(ret[qstat_game_players]), "",
+ FALSE, 0, FALSE, 0,
+ TRUE, 0, TRUE, atol(ret[qstat_game_players_max])),
+ fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
+ FALSE, 0, FALSE, 0,
+ TRUE, 0, FALSE, 0));
+ }
+
+ return result;
+}
+
+
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int opt_index = 0;
+ static struct option long_opts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'P'},
+ {"game-type", required_argument, 0, 'G'},
+ {"map-field", required_argument, 0, 'm'},
+ {"ping-field", required_argument, 0, 'p'},
+ {"game-field", required_argument, 0, 'g'},
+ {"players-field", required_argument, 0, 129},
+ {"max-players-field", required_argument, 0, 130},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-mf", argv[c]) == 0)
+ strcpy (argv[c], "-m");
+ else if (strcmp ("-pf", argv[c]) == 0)
+ strcpy (argv[c], "-p");
+ else if (strcmp ("-gf", argv[c]) == 0)
+ strcpy (argv[c], "-g");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* version */
+ verbose = TRUE;
+ break;
+ case 't': /* timeout period */
+ timeout_interval = atoi (optarg);
+ break;
+ case 'H': /* hostname */
+ if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ server_ip = optarg;
+ break;
+ case 'P': /* port */
+ port = atoi (optarg);
+ break;
+ case 'G': /* hostname */
+ if (strlen (optarg) >= MAX_INPUT_BUFFER)
+ die (STATE_UNKNOWN, _("Input buffer overflow\n"));
+ game_type = optarg;
+ break;
+ case 'p': /* index of ping field */
+ qstat_ping_field = atoi (optarg);
+ if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
+ return ERROR;
+ break;
+ case 'm': /* index on map field */
+ qstat_map_field = atoi (optarg);
+ if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
+ return ERROR;
+ break;
+ case 'g': /* index of game field */
+ qstat_game_field = atoi (optarg);
+ if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
+ return ERROR;
+ break;
+ case 129: /* index of player count field */
+ qstat_game_players = atoi (optarg);
+ if (qstat_game_players_max == 0)
+ qstat_game_players_max = qstat_game_players - 1;
+ if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
+ return ERROR;
+ break;
+ case 130: /* index of max players field */
+ qstat_game_players_max = atoi (optarg);
+ if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
+ return ERROR;
+ break;
+ default: /* args not parsable */
+ usage5();
+ }
+ }
+
+ c = optind;
+ /* first option is the game type */
+ if (!game_type && c<argc)
+ game_type = strdup (argv[c++]);
+
+ /* Second option is the server name */
+ if (!server_ip && c<argc)
+ server_ip = strdup (argv[c++]);
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments (void)
+{
+ if (qstat_game_players_max < 0)
+ qstat_game_players_max = 4;
+
+ if (qstat_game_players < 0)
+ qstat_game_players = 5;
+
+ if (qstat_game_field < 0)
+ qstat_game_field = 2;
+
+ if (qstat_map_field < 0)
+ qstat_map_field = 3;
+
+ if (qstat_ping_field < 0)
+ qstat_ping_field = 5;
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin tests game server connections with the specified host."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-p");
+ printf (" %s\n", _("Optional port of which to connect"));
+ printf (" %s\n", "gf");
+ printf (" %s\n", _("Field number in raw qstat output that contains game name"));
+ printf (" %s\n", "-mf");
+ printf (" %s\n", _("Field number in raw qstat output that contains map name"));
+ printf (" %s\n", "-pf");
+ printf (" %s\n", _("Field number in raw qstat output that contains ping time"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
+ printf (" %s\n", _("If you don't have the package installed, you will need to download it from"));
+ printf (" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> <ip_address>\n", progname);
+}
+
+/******************************************************************************
+ *
+ * Test Cases:
+ *
+ * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
+ *
+ * qstat -raw , -qs 67.20.190.61
+ * ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
+ *
+ * qstat -qs 67.20.190.61
+ * ==> ADDRESS PLAYERS MAP RESPONSE TIME NAME
+ * ==> 67.20.190.61 0/ 6 e2m1 79 / 0 Nightmare.fintek.ca
+ *
+ ******************************************************************************/
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
new file mode 100644
index 0000000..c34bb08
--- /dev/null
+++ b/plugins/check_hpjd.c
@@ -0,0 +1,442 @@
+/*****************************************************************************
+*
+* Monitoring check_hpjd plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_hpjd plugin
+*
+* This plugin tests the STATUS of an HP printer with a JetDirect card.
+* Net-SNMP must be installed on the computer running the plugin.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_hpjd";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "popen.h"
+#include "utils.h"
+#include "netutils.h"
+
+#define DEFAULT_COMMUNITY "public"
+#define DEFAULT_PORT "161"
+
+const char *option_summary = "-H host [-C community]\n";
+
+#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
+#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
+#define HPJD_INTERVENTION_REQUIRED ".1.3.6.1.4.1.11.2.3.9.1.1.2.3"
+#define HPJD_GD_PERIPHERAL_ERROR ".1.3.6.1.4.1.11.2.3.9.1.1.2.6"
+#define HPJD_GD_PAPER_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.8"
+#define HPJD_GD_PAPER_JAM ".1.3.6.1.4.1.11.2.3.9.1.1.2.9"
+#define HPJD_GD_TONER_LOW ".1.3.6.1.4.1.11.2.3.9.1.1.2.10"
+#define HPJD_GD_PAGE_PUNT ".1.3.6.1.4.1.11.2.3.9.1.1.2.11"
+#define HPJD_GD_MEMORY_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.12"
+#define HPJD_GD_DOOR_OPEN ".1.3.6.1.4.1.11.2.3.9.1.1.2.17"
+#define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19"
+#define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3"
+
+#define ONLINE 0
+#define OFFLINE 1
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+char *community = NULL;
+char *address = NULL;
+unsigned int port = 0;
+int check_paper_out = 1;
+
+int
+main (int argc, char **argv)
+{
+ char command_line[1024];
+ int result = STATE_UNKNOWN;
+ int line;
+ char input_buffer[MAX_INPUT_BUFFER];
+ char query_string[512];
+ char *errmsg;
+ char *temp_buffer;
+ int line_status = ONLINE;
+ int paper_status = 0;
+ int intervention_required = 0;
+ int peripheral_error = 0;
+ int paper_jam = 0;
+ int paper_out = 0;
+ int toner_low = 0;
+ int page_punt = 0;
+ int memory_out = 0;
+ int door_open = 0;
+ int paper_output = 0;
+ char display_message[MAX_INPUT_BUFFER];
+
+ errmsg = malloc(MAX_INPUT_BUFFER);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* removed ' 2>1' at end of command 10/27/1999 - EG */
+ /* create the query string */
+ sprintf
+ (query_string,
+ "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0",
+ HPJD_LINE_STATUS,
+ HPJD_PAPER_STATUS,
+ HPJD_INTERVENTION_REQUIRED,
+ HPJD_GD_PERIPHERAL_ERROR,
+ HPJD_GD_PAPER_JAM,
+ HPJD_GD_PAPER_OUT,
+ HPJD_GD_TONER_LOW,
+ HPJD_GD_PAGE_PUNT,
+ HPJD_GD_MEMORY_OUT,
+ HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
+
+ /* get the command to run */
+ sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s",
+ PATH_TO_SNMPGET,
+ community,
+ address,
+ port,
+ query_string);
+
+ /* run the command */
+ child_process = spopen (command_line);
+ if (child_process == NULL) {
+ printf (_("Could not open pipe: %s\n"), command_line);
+ return STATE_UNKNOWN;
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL) {
+ printf (_("Could not open stderr for %s\n"), command_line);
+ }
+
+ result = STATE_OK;
+
+ line = 0;
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+
+ /* strip the newline character from the end of the input */
+ if (input_buffer[strlen (input_buffer) - 1] == '\n')
+ input_buffer[strlen (input_buffer) - 1] = 0;
+
+ line++;
+
+ temp_buffer = strtok (input_buffer, "=");
+ temp_buffer = strtok (NULL, "=");
+
+ if (temp_buffer == NULL && line < 13) {
+
+ result = STATE_UNKNOWN;
+ strcpy (errmsg, input_buffer);
+
+ } else {
+
+ switch (line) {
+
+ case 1: /* 1st line should contain the line status */
+ line_status = atoi (temp_buffer);
+ break;
+ case 2: /* 2nd line should contain the paper status */
+ paper_status = atoi (temp_buffer);
+ break;
+ case 3: /* 3rd line should be intervention required */
+ intervention_required = atoi (temp_buffer);
+ break;
+ case 4: /* 4th line should be peripheral error */
+ peripheral_error = atoi (temp_buffer);
+ break;
+ case 5: /* 5th line should contain the paper jam status */
+ paper_jam = atoi (temp_buffer);
+ break;
+ case 6: /* 6th line should contain the paper out status */
+ paper_out = atoi (temp_buffer);
+ break;
+ case 7: /* 7th line should contain the toner low status */
+ toner_low = atoi (temp_buffer);
+ break;
+ case 8: /* did data come too slow for engine */
+ page_punt = atoi (temp_buffer);
+ break;
+ case 9: /* did we run out of memory */
+ memory_out = atoi (temp_buffer);
+ break;
+ case 10: /* is there a door open */
+ door_open = atoi (temp_buffer);
+ break;
+ case 11: /* is output tray full */
+ paper_output = atoi (temp_buffer);
+ break;
+ case 12: /* display panel message */
+ strcpy (display_message, temp_buffer + 1);
+ break;
+ default: /* fold multiline message */
+ strncat (display_message, input_buffer,
+ sizeof (display_message) - strlen (display_message) - 1);
+ }
+
+ }
+
+ /* break out of the read loop if we encounter an error */
+ if (result != STATE_OK)
+ break;
+ }
+
+ /* WARNING if output found on stderr */
+ if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
+ result = max_state (result, STATE_WARNING);
+ /* remove CRLF */
+ if (input_buffer[strlen (input_buffer) - 1] == '\n')
+ input_buffer[strlen (input_buffer) - 1] = 0;
+ sprintf (errmsg, "%s", input_buffer );
+
+ }
+
+ /* close stderr */
+ (void) fclose (child_stderr);
+
+ /* close the pipe */
+ if (spclose (child_process))
+ result = max_state (result, STATE_WARNING);
+
+ /* if there wasn't any output, display an error */
+ if (line == 0) {
+
+ /* might not be the problem, but most likely is. */
+ result = STATE_UNKNOWN ;
+ xasprintf (&errmsg, "%s : Timeout from host %s\n", errmsg, address );
+
+ }
+
+ /* if we had no read errors, check the printer status results... */
+ if (result == STATE_OK) {
+
+ if (paper_jam) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Paper Jam"));
+ }
+ else if (paper_out) {
+ if (check_paper_out)
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Out of Paper"));
+ }
+ else if (line_status == OFFLINE) {
+ if (strcmp (errmsg, "POWERSAVE ON") != 0) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Printer Offline"));
+ }
+ }
+ else if (peripheral_error) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Peripheral Error"));
+ }
+ else if (intervention_required) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Intervention Required"));
+ }
+ else if (toner_low) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Toner Low"));
+ }
+ else if (memory_out) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Insufficient Memory"));
+ }
+ else if (door_open) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("A Door is Open"));
+ }
+ else if (paper_output) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Output Tray is Full"));
+ }
+ else if (page_punt) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Data too Slow for Engine"));
+ }
+ else if (paper_status) {
+ result = STATE_WARNING;
+ strcpy (errmsg, _("Unknown Paper Error"));
+ }
+ }
+
+ if (result == STATE_OK)
+ printf (_("Printer ok - (%s)\n"), display_message);
+
+ else if (result == STATE_UNKNOWN) {
+
+ printf ("%s\n", errmsg);
+
+ /* if printer could not be reached, escalate to critical */
+ if (strstr (errmsg, "Timeout"))
+ result = STATE_CRITICAL;
+ }
+
+ else if (result == STATE_WARNING)
+ printf ("%s (%s)\n", errmsg, display_message);
+
+ return result;
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"community", required_argument, 0, 'C'},
+/* {"critical", required_argument,0,'c'}, */
+/* {"warning", required_argument,0,'w'}, */
+ {"port", required_argument,0,'p'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'H': /* hostname */
+ if (is_host (optarg)) {
+ address = strscpy(address, optarg) ;
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ break;
+ case 'C': /* community */
+ community = strscpy (community, optarg);
+ break;
+ case 'p':
+ if (!is_intpos(optarg))
+ usage2 (_("Port must be a positive short integer"), optarg);
+ else
+ port = atoi(optarg);
+ break;
+ case 'D': /* disable paper out check*/
+ check_paper_out = 0;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (address == NULL) {
+ if (is_host (argv[c])) {
+ address = argv[c++];
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), argv[c]);
+ }
+ }
+
+ if (community == NULL) {
+ if (argv[c] != NULL )
+ community = argv[c];
+ else
+ community = strdup (DEFAULT_COMMUNITY);
+ }
+
+ if (port == 0) {
+ port = atoi(DEFAULT_PORT);
+ }
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments (void)
+{
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card."));
+ printf ("%s\n", _("Net-snmp must be installed on the computer running the plugin."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-C, --community=STRING");
+ printf (" %s", _("The SNMP community name "));
+ printf (_("(default=%s)"), DEFAULT_COMMUNITY);
+ printf ("\n");
+ printf (" %s\n", "-p, --port=STRING");
+ printf (" %s", _("Specify the port to check "));
+ printf (_("(default=%s)"), DEFAULT_PORT);
+ printf ("\n");
+ printf (" %s\n", "-D");
+ printf (" %s", _("Disable paper check "));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-C community] [-p port] [-D]\n", progname);
+}
diff --git a/plugins/check_http.c b/plugins/check_http.c
new file mode 100644
index 0000000..b9d8145
--- /dev/null
+++ b/plugins/check_http.c
@@ -0,0 +1,1895 @@
+/*****************************************************************************
+*
+* Monitoring check_http plugin
+*
+* License: GPL
+* Copyright (c) 1999-2013 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_http plugin
+*
+* This plugin tests the HTTP service on the specified host. It can test
+* normal (http) and secure (https) servers, follow redirects, search for
+* strings and regular expressions, check connection times, and report on
+* certificate expiration times.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_http";
+const char *copyright = "1999-2022";
+const char *email = "devel@monitoring-plugins.org";
+
+// Do NOT sort those headers, it will break the build
+// TODO: Fix this
+#include "common.h"
+#include "base64.h"
+#include "netutils.h"
+#include "utils.h"
+#include "base64.h"
+#include <ctype.h>
+
+#define STICKY_NONE 0
+#define STICKY_HOST 1
+#define STICKY_PORT 2
+
+#define HTTP_EXPECT "HTTP/1."
+enum {
+ MAX_IPV4_HOSTLENGTH = 255,
+ HTTP_PORT = 80,
+ HTTPS_PORT = 443,
+ MAX_PORT = 65535,
+ DEFAULT_MAX_REDIRS = 15
+};
+
+#ifdef HAVE_SSL
+bool check_cert = false;
+bool continue_after_check_cert = false;
+int ssl_version = 0;
+int days_till_exp_warn, days_till_exp_crit;
+char *randbuff;
+X509 *server_cert;
+# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
+# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
+#else /* ifndef HAVE_SSL */
+# define my_recv(buf, len) read(sd, buf, len)
+# define my_send(buf, len) send(sd, buf, len, 0)
+#endif /* HAVE_SSL */
+bool no_body = false;
+int maximum_age = -1;
+
+enum {
+ REGS = 2,
+ MAX_RE_SIZE = 1024
+};
+#include "regex.h"
+regex_t preg;
+regmatch_t pmatch[REGS];
+char regexp[MAX_RE_SIZE];
+char errbuf[MAX_INPUT_BUFFER];
+int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
+int errcode;
+int invert_regex = 0;
+
+struct timeval tv;
+struct timeval tv_temp;
+
+#define HTTP_URL "/"
+#define CRLF "\r\n"
+
+bool specify_port = false;
+int server_port = HTTP_PORT;
+int virtual_port = 0;
+char server_port_text[6] = "";
+char server_type[6] = "http";
+char *server_address;
+char *host_name;
+int host_name_length;
+char *server_url;
+char *user_agent;
+int server_url_length;
+int server_expect_yn = 0;
+char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
+char header_expect[MAX_INPUT_BUFFER] = "";
+char string_expect[MAX_INPUT_BUFFER] = "";
+char *warning_thresholds = NULL;
+char *critical_thresholds = NULL;
+thresholds *thlds;
+char user_auth[MAX_INPUT_BUFFER] = "";
+char proxy_auth[MAX_INPUT_BUFFER] = "";
+bool display_html = false;
+char **http_opt_headers;
+int http_opt_headers_count = 0;
+int onredirect = STATE_OK;
+int followsticky = STICKY_NONE;
+bool use_ssl = false;
+bool use_sni = false;
+bool verbose = false;
+bool show_extended_perfdata = false;
+bool show_body = false;
+int sd;
+int min_page_len = 0;
+int max_page_len = 0;
+int redir_depth = 0;
+int max_depth = DEFAULT_MAX_REDIRS;
+char *http_method;
+char *http_method_proxy;
+char *http_post_data;
+char *http_content_type;
+char buffer[MAX_INPUT_BUFFER];
+char *client_cert = NULL;
+char *client_privkey = NULL;
+
+// Forward function declarations
+bool process_arguments (int, char **);
+int check_http (void);
+void redir (char *pos, char *status_line);
+bool server_type_check(const char *type);
+int server_port_check(int ssl_flag);
+char *perfd_time (double microsec);
+char *perfd_time_connect (double microsec);
+char *perfd_time_ssl (double microsec);
+char *perfd_time_firstbyte (double microsec);
+char *perfd_time_headers (double microsec);
+char *perfd_time_transfer (double microsec);
+char *perfd_size (int page_len);
+void print_help (void);
+void print_usage (void);
+char *unchunk_content(const char *content);
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
+ server_url = strdup(HTTP_URL);
+ server_url_length = strlen(server_url);
+ xasprintf (&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)",
+ NP_VERSION, VERSION);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == false)
+ usage4 (_("Could not parse arguments"));
+
+ if (display_html == true)
+ printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
+ use_ssl ? "https" : "http", host_name ? host_name : server_address,
+ server_port, server_url);
+
+ /* initialize alarm signal handling, set socket timeout, start timer */
+ (void) signal (SIGALRM, socket_timeout_alarm_handler);
+ (void) alarm (socket_timeout);
+ gettimeofday (&tv, NULL);
+
+ result = check_http ();
+ return result;
+}
+
+/* check whether a file exists */
+void
+test_file (char *path)
+{
+ if (access(path, R_OK) == 0)
+ return;
+ usage2 (_("file does not exist or is not readable"), path);
+}
+
+/*
+ * process command-line arguments
+ * returns true on success, false otherwise
+ */
+bool process_arguments (int argc, char **argv)
+{
+ int c = 1;
+ char *p;
+ char *temp;
+
+ enum {
+ INVERT_REGEX = CHAR_MAX + 1,
+ SNI_OPTION,
+ MAX_REDIRS_OPTION,
+ CONTINUE_AFTER_CHECK_CERT
+ };
+
+ int option = 0;
+ static struct option longopts[] = {
+ STD_LONG_OPTS,
+ {"link", no_argument, 0, 'L'},
+ {"nohtml", no_argument, 0, 'n'},
+ {"ssl", optional_argument, 0, 'S'},
+ {"sni", no_argument, 0, SNI_OPTION},
+ {"post", required_argument, 0, 'P'},
+ {"method", required_argument, 0, 'j'},
+ {"IP-address", required_argument, 0, 'I'},
+ {"url", required_argument, 0, 'u'},
+ {"port", required_argument, 0, 'p'},
+ {"authorization", required_argument, 0, 'a'},
+ {"proxy-authorization", required_argument, 0, 'b'},
+ {"header-string", required_argument, 0, 'd'},
+ {"string", required_argument, 0, 's'},
+ {"expect", required_argument, 0, 'e'},
+ {"regex", required_argument, 0, 'r'},
+ {"ereg", required_argument, 0, 'r'},
+ {"eregi", required_argument, 0, 'R'},
+ {"linespan", no_argument, 0, 'l'},
+ {"onredirect", required_argument, 0, 'f'},
+ {"certificate", required_argument, 0, 'C'},
+ {"client-cert", required_argument, 0, 'J'},
+ {"private-key", required_argument, 0, 'K'},
+ {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
+ {"useragent", required_argument, 0, 'A'},
+ {"header", required_argument, 0, 'k'},
+ {"no-body", no_argument, 0, 'N'},
+ {"max-age", required_argument, 0, 'M'},
+ {"content-type", required_argument, 0, 'T'},
+ {"pagesize", required_argument, 0, 'm'},
+ {"invert-regex", no_argument, NULL, INVERT_REGEX},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"extended-perfdata", no_argument, 0, 'E'},
+ {"show-body", no_argument, 0, 'B'},
+ {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return false;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ if (strcmp ("-hn", argv[c]) == 0)
+ strcpy (argv[c], "-H");
+ if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ if (strcmp ("-nohtml", argv[c]) == 0)
+ strcpy (argv[c], "-n");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB", longopts, &option);
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* usage */
+ usage5 ();
+ break;
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ break;
+ case 't': /* timeout period */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ socket_timeout = atoi (optarg);
+ break;
+ case 'c': /* critical time threshold */
+ critical_thresholds = optarg;
+ break;
+ case 'w': /* warning time threshold */
+ warning_thresholds = optarg;
+ break;
+ case 'A': /* User Agent String */
+ xasprintf (&user_agent, "User-Agent: %s", optarg);
+ break;
+ case 'k': /* Additional headers */
+ if (http_opt_headers_count == 0)
+ http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
+ else
+ http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
+ http_opt_headers[http_opt_headers_count - 1] = optarg;
+ /* xasprintf (&http_opt_headers, "%s", optarg); */
+ break;
+ case 'L': /* show html link */
+ display_html = true;
+ break;
+ case 'n': /* do not show html link */
+ display_html = false;
+ break;
+ case 'C': /* Check SSL cert validity */
+#ifdef HAVE_SSL
+ if ((temp=strchr(optarg,','))!=NULL) {
+ *temp='\0';
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi(optarg);
+ *temp=',';
+ temp++;
+ if (!is_intnonneg (temp))
+ usage2 (_("Invalid certificate expiration period"), temp);
+ days_till_exp_crit = atoi (temp);
+ }
+ else {
+ days_till_exp_crit=0;
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi (optarg);
+ }
+ check_cert = true;
+ goto enable_ssl;
+#endif
+ case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
+#ifdef HAVE_SSL
+ continue_after_check_cert = true;
+ break;
+#endif
+ case 'J': /* use client certificate */
+#ifdef HAVE_SSL
+ test_file(optarg);
+ client_cert = optarg;
+ goto enable_ssl;
+#endif
+ case 'K': /* use client private key */
+#ifdef HAVE_SSL
+ test_file(optarg);
+ client_privkey = optarg;
+ goto enable_ssl;
+#endif
+ case 'S': /* use SSL */
+#ifdef HAVE_SSL
+ enable_ssl:
+ /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple
+ parameters, like -S and -C combinations */
+ use_ssl = true;
+ if (c=='S' && optarg != NULL) {
+ int got_plus = strchr(optarg, '+') != NULL;
+
+ if (!strncmp (optarg, "1.2", 3))
+ ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2;
+ else if (!strncmp (optarg, "1.1", 3))
+ ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1;
+ else if (optarg[0] == '1')
+ ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1;
+ else if (optarg[0] == '3')
+ ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3;
+ else if (optarg[0] == '2')
+ ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2;
+ else
+ usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)"));
+ }
+ if (specify_port == false)
+ server_port = HTTPS_PORT;
+#else
+ /* -C -J and -K fall through to here without SSL */
+ usage4 (_("Invalid option - SSL is not available"));
+#endif
+ break;
+ case SNI_OPTION:
+ use_sni = true;
+ break;
+ case MAX_REDIRS_OPTION:
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid max_redirs count"), optarg);
+ else {
+ max_depth = atoi (optarg);
+ }
+ break;
+ case 'f': /* onredirect */
+ if (!strcmp (optarg, "stickyport"))
+ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
+ else if (!strcmp (optarg, "sticky"))
+ onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
+ else if (!strcmp (optarg, "follow"))
+ onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
+ else if (!strcmp (optarg, "unknown"))
+ onredirect = STATE_UNKNOWN;
+ else if (!strcmp (optarg, "ok"))
+ onredirect = STATE_OK;
+ else if (!strcmp (optarg, "warning"))
+ onredirect = STATE_WARNING;
+ else if (!strcmp (optarg, "critical"))
+ onredirect = STATE_CRITICAL;
+ else usage2 (_("Invalid onredirect option"), optarg);
+ if (verbose)
+ printf(_("option f:%d \n"), onredirect);
+ break;
+ /* Note: H, I, and u must be malloc'd or will fail on redirects */
+ case 'H': /* Host Name (virtual host) */
+ host_name = strdup (optarg);
+ if (host_name[0] == '[') {
+ if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */
+ virtual_port = atoi (p + 2);
+ /* cut off the port */
+ host_name_length = strlen (host_name) - strlen (p) - 1;
+ free (host_name);
+ host_name = strndup (optarg, host_name_length);
+ if (specify_port == false)
+ server_port = virtual_port;
+ }
+ } else if ((p = strchr (host_name, ':')) != NULL
+ && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */
+ virtual_port = atoi (p);
+ /* cut off the port */
+ host_name_length = strlen (host_name) - strlen (p) - 1;
+ free (host_name);
+ host_name = strndup (optarg, host_name_length);
+ if (specify_port == false)
+ server_port = virtual_port;
+ }
+ break;
+ case 'I': /* Server IP-address */
+ server_address = strdup (optarg);
+ break;
+ case 'u': /* URL path */
+ server_url = strdup (optarg);
+ server_url_length = strlen (server_url);
+ break;
+ case 'p': /* Server port */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid port number"), optarg);
+ else {
+ server_port = atoi (optarg);
+ specify_port = true;
+ }
+ break;
+ case 'a': /* authorization info */
+ strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
+ user_auth[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'b': /* proxy-authorization info */
+ strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
+ proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
+ if (! http_post_data)
+ http_post_data = strdup (optarg);
+ if (! http_method)
+ http_method = strdup("POST");
+ break;
+ case 'j': /* Set HTTP method */
+ if (http_method)
+ free(http_method);
+ http_method = strdup (optarg);
+ char *tmp;
+ if ((tmp = strstr(http_method, ":")) > 0) {
+ tmp[0] = '\0';
+ http_method = http_method;
+ http_method_proxy = ++tmp;
+ }
+ break;
+ case 'd': /* string or substring */
+ strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1);
+ header_expect[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 's': /* string or substring */
+ strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
+ string_expect[MAX_INPUT_BUFFER - 1] = 0;
+ break;
+ case 'e': /* string or substring */
+ strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
+ server_expect[MAX_INPUT_BUFFER - 1] = 0;
+ server_expect_yn = 1;
+ break;
+ case 'T': /* Content-type */
+ xasprintf (&http_content_type, "%s", optarg);
+ break;
+ case 'l': /* linespan */
+ cflags &= ~REG_NEWLINE;
+ break;
+ case 'R': /* regex */
+ cflags |= REG_ICASE;
+ // fall through
+ case 'r': /* regex */
+ strncpy (regexp, optarg, MAX_RE_SIZE - 1);
+ regexp[MAX_RE_SIZE - 1] = 0;
+ errcode = regcomp (&preg, regexp, cflags);
+ if (errcode != 0) {
+ (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Could Not Compile Regular Expression: %s"), errbuf);
+ return false;
+ }
+ break;
+ case INVERT_REGEX:
+ invert_regex = 1;
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case 'v': /* verbose */
+ verbose = true;
+ break;
+ case 'm': /* min_page_length */
+ {
+ char *tmp;
+ if (strchr(optarg, ':') != (char *)NULL) {
+ /* range, so get two values, min:max */
+ tmp = strtok(optarg, ":");
+ if (tmp == NULL) {
+ printf("Bad format: try \"-m min:max\"\n");
+ exit (STATE_WARNING);
+ } else
+ min_page_len = atoi(tmp);
+
+ tmp = strtok(NULL, ":");
+ if (tmp == NULL) {
+ printf("Bad format: try \"-m min:max\"\n");
+ exit (STATE_WARNING);
+ } else
+ max_page_len = atoi(tmp);
+ } else
+ min_page_len = atoi (optarg);
+ break;
+ }
+ case 'N': /* no-body */
+ no_body = true;
+ break;
+ case 'M': /* max-age */
+ {
+ int L = strlen(optarg);
+ if (L && optarg[L-1] == 'm')
+ maximum_age = atoi (optarg) * 60;
+ else if (L && optarg[L-1] == 'h')
+ maximum_age = atoi (optarg) * 60 * 60;
+ else if (L && optarg[L-1] == 'd')
+ maximum_age = atoi (optarg) * 60 * 60 * 24;
+ else if (L && (optarg[L-1] == 's' ||
+ isdigit (optarg[L-1])))
+ maximum_age = atoi (optarg);
+ else {
+ fprintf (stderr, "unparsable max-age: %s\n", optarg);
+ exit (STATE_WARNING);
+ }
+ }
+ break;
+ case 'E': /* show extended perfdata */
+ show_extended_perfdata = true;
+ break;
+ case 'B': /* print body content after status line */
+ show_body = true;
+ break;
+ }
+ }
+
+ c = optind;
+
+ if (server_address == NULL && c < argc)
+ server_address = strdup (argv[c++]);
+
+ if (host_name == NULL && c < argc)
+ host_name = strdup (argv[c++]);
+
+ if (server_address == NULL) {
+ if (host_name == NULL)
+ usage4 (_("You must specify a server address or host name"));
+ else
+ server_address = strdup (host_name);
+ }
+
+ set_thresholds(&thlds, warning_thresholds, critical_thresholds);
+
+ if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
+ socket_timeout = (int)thlds->critical->end + 1;
+
+ if (http_method == NULL)
+ http_method = strdup ("GET");
+
+ if (http_method_proxy == NULL)
+ http_method_proxy = strdup ("GET");
+
+ if (client_cert && !client_privkey)
+ usage4 (_("If you use a client certificate you must also specify a private key file"));
+
+ if (virtual_port == 0)
+ virtual_port = server_port;
+
+ return true;
+}
+
+
+
+/* Returns 1 if we're done processing the document body; 0 to keep going */
+static int
+document_headers_done (char *full_page)
+{
+ const char *body;
+
+ for (body = full_page; *body; body++) {
+ if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
+ break;
+ }
+
+ if (!*body)
+ return 0; /* haven't read end of headers yet */
+
+ full_page[body - full_page] = 0;
+ return 1;
+}
+
+static time_t
+parse_time_string (const char *string)
+{
+ struct tm tm;
+ time_t t;
+ memset (&tm, 0, sizeof(tm));
+
+ /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
+
+ if (isupper (string[0]) && /* Tue */
+ islower (string[1]) &&
+ islower (string[2]) &&
+ ',' == string[3] &&
+ ' ' == string[4] &&
+ (isdigit(string[5]) || string[5] == ' ') && /* 25 */
+ isdigit (string[6]) &&
+ ' ' == string[7] &&
+ isupper (string[8]) && /* Dec */
+ islower (string[9]) &&
+ islower (string[10]) &&
+ ' ' == string[11] &&
+ isdigit (string[12]) && /* 2001 */
+ isdigit (string[13]) &&
+ isdigit (string[14]) &&
+ isdigit (string[15]) &&
+ ' ' == string[16] &&
+ isdigit (string[17]) && /* 02: */
+ isdigit (string[18]) &&
+ ':' == string[19] &&
+ isdigit (string[20]) && /* 59: */
+ isdigit (string[21]) &&
+ ':' == string[22] &&
+ isdigit (string[23]) && /* 03 */
+ isdigit (string[24]) &&
+ ' ' == string[25] &&
+ 'G' == string[26] && /* GMT */
+ 'M' == string[27] && /* GMT */
+ 'T' == string[28]) {
+
+ tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
+ tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
+ tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
+ tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
+ tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
+ !strncmp (string+8, "Feb", 3) ? 1 :
+ !strncmp (string+8, "Mar", 3) ? 2 :
+ !strncmp (string+8, "Apr", 3) ? 3 :
+ !strncmp (string+8, "May", 3) ? 4 :
+ !strncmp (string+8, "Jun", 3) ? 5 :
+ !strncmp (string+8, "Jul", 3) ? 6 :
+ !strncmp (string+8, "Aug", 3) ? 7 :
+ !strncmp (string+8, "Sep", 3) ? 8 :
+ !strncmp (string+8, "Oct", 3) ? 9 :
+ !strncmp (string+8, "Nov", 3) ? 10 :
+ !strncmp (string+8, "Dec", 3) ? 11 :
+ -1);
+ tm.tm_year = ((1000 * (string[12]-'0') +
+ 100 * (string[13]-'0') +
+ 10 * (string[14]-'0') +
+ (string[15]-'0'))
+ - 1900);
+
+ tm.tm_isdst = 0; /* GMT is never in DST, right? */
+
+ if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
+ return 0;
+
+ /*
+ This is actually wrong: we need to subtract the local timezone
+ offset from GMT from this value. But, that's ok in this usage,
+ because we only comparing these two GMT dates against each other,
+ so it doesn't matter what time zone we parse them in.
+ */
+
+ t = mktime (&tm);
+ if (t == (time_t) -1) t = 0;
+
+ if (verbose) {
+ const char *s = string;
+ while (*s && *s != '\r' && *s != '\n')
+ fputc (*s++, stdout);
+ printf (" ==> %lu\n", (unsigned long) t);
+ }
+
+ return t;
+
+ } else {
+ return 0;
+ }
+}
+
+/* Checks if the server 'reply' is one of the expected 'statuscodes' */
+static int
+expected_statuscode (const char *reply, const char *statuscodes)
+{
+ char *expected, *code;
+ int result = 0;
+
+ if ((expected = strdup (statuscodes)) == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
+
+ for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
+ if (strstr (reply, code) != NULL) {
+ result = 1;
+ break;
+ }
+
+ free (expected);
+ return result;
+}
+
+static int
+check_document_dates (const char *headers, char **msg)
+{
+ const char *s;
+ char *server_date = 0;
+ char *document_date = 0;
+ int date_result = STATE_OK;
+
+ s = headers;
+ while (*s) {
+ const char *field = s;
+ const char *value = 0;
+
+ /* Find the end of the header field */
+ while (*s && !isspace(*s) && *s != ':')
+ s++;
+
+ /* Remember the header value, if any. */
+ if (*s == ':')
+ value = ++s;
+
+ /* Skip to the end of the header, including continuation lines. */
+ while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
+ s++;
+
+ /* Avoid stepping over end-of-string marker */
+ if (*s)
+ s++;
+
+ /* Process this header. */
+ if (value && value > field+2) {
+ char *ff = (char *) malloc (value-field);
+ char *ss = ff;
+ while (field < value-1)
+ *ss++ = tolower(*field++);
+ *ss++ = 0;
+
+ if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
+ const char *e;
+ while (*value && isspace (*value))
+ value++;
+ for (e = value; *e && *e != '\r' && *e != '\n'; e++)
+ ;
+ ss = (char *) malloc (e - value + 1);
+ strncpy (ss, value, e - value);
+ ss[e - value] = 0;
+ if (!strcmp (ff, "date")) {
+ if (server_date) free (server_date);
+ server_date = ss;
+ } else {
+ if (document_date) free (document_date);
+ document_date = ss;
+ }
+ }
+ free (ff);
+ }
+ }
+
+ /* Done parsing the body. Now check the dates we (hopefully) parsed. */
+ if (!server_date || !*server_date) {
+ xasprintf (msg, _("%sServer date unknown, "), *msg);
+ date_result = max_state_alt(STATE_UNKNOWN, date_result);
+ } else if (!document_date || !*document_date) {
+ xasprintf (msg, _("%sDocument modification date unknown, "), *msg);
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else {
+ time_t srv_data = parse_time_string (server_date);
+ time_t doc_data = parse_time_string (document_date);
+
+ if (srv_data <= 0) {
+ xasprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data <= 0) {
+ xasprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data > srv_data + 30) {
+ xasprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else if (doc_data < srv_data - maximum_age) {
+ int n = (srv_data - doc_data);
+ if (n > (60 * 60 * 24 * 2)) {
+ xasprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ } else {
+ xasprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
+ date_result = max_state_alt(STATE_CRITICAL, date_result);
+ }
+ }
+ free (server_date);
+ free (document_date);
+ }
+ return date_result;
+}
+
+int
+get_content_length (const char *headers)
+{
+ const char *s;
+ int content_length = 0;
+
+ s = headers;
+ while (*s) {
+ const char *field = s;
+ const char *value = 0;
+
+ /* Find the end of the header field */
+ while (*s && !isspace(*s) && *s != ':')
+ s++;
+
+ /* Remember the header value, if any. */
+ if (*s == ':')
+ value = ++s;
+
+ /* Skip to the end of the header, including continuation lines. */
+ while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
+ s++;
+
+ /* Avoid stepping over end-of-string marker */
+ if (*s)
+ s++;
+
+ /* Process this header. */
+ if (value && value > field+2) {
+ char *ff = (char *) malloc (value-field);
+ char *ss = ff;
+ while (field < value-1)
+ *ss++ = tolower(*field++);
+ *ss++ = 0;
+
+ if (!strcmp (ff, "content-length")) {
+ const char *e;
+ while (*value && isspace (*value))
+ value++;
+ for (e = value; *e && *e != '\r' && *e != '\n'; e++)
+ ;
+ ss = (char *) malloc (e - value + 1);
+ strncpy (ss, value, e - value);
+ ss[e - value] = 0;
+ content_length = atoi(ss);
+ free (ss);
+ }
+ free (ff);
+ }
+ }
+ return (content_length);
+}
+
+char *
+prepend_slash (char *path)
+{
+ char *newpath;
+
+ if (path[0] == '/')
+ return path;
+
+ if ((newpath = malloc (strlen(path) + 2)) == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
+ newpath[0] = '/';
+ strcpy (newpath + 1, path);
+ free (path);
+ return newpath;
+}
+
+int
+check_http (void)
+{
+ char *msg;
+ char *status_line;
+ char *status_code;
+ char *header;
+ char *page;
+ char *auth;
+ int http_status;
+ int i = 0;
+ size_t pagesize = 0;
+ char *full_page;
+ char *full_page_new;
+ char *buf;
+ char *pos;
+ long microsec = 0L;
+ double elapsed_time = 0.0;
+ long microsec_connect = 0L;
+ double elapsed_time_connect = 0.0;
+ long microsec_ssl = 0L;
+ double elapsed_time_ssl = 0.0;
+ long microsec_firstbyte = 0L;
+ double elapsed_time_firstbyte = 0.0;
+ long microsec_headers = 0L;
+ double elapsed_time_headers = 0.0;
+ long microsec_transfer = 0L;
+ double elapsed_time_transfer = 0.0;
+ int page_len = 0;
+ int result = STATE_OK;
+ char *force_host_header = NULL;
+
+ /* try to connect to the host at the given port number */
+ gettimeofday (&tv_temp, NULL);
+ if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
+ die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
+ microsec_connect = deltime (tv_temp);
+
+ /* if we are called with the -I option, the -j method is CONNECT and */
+ /* we received -S for SSL, then we tunnel the request through a proxy*/
+ /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
+
+ if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
+ && host_name != NULL && use_ssl == true) {
+
+ if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT);
+ asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent);
+ if (strlen(proxy_auth)) {
+ base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth);
+ xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
+ }
+ /* optionally send any other header tag */
+ if (http_opt_headers_count) {
+ for (i = 0; i < http_opt_headers_count ; i++) {
+ if (force_host_header != http_opt_headers[i]) {
+ xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]);
+ }
+ }
+ /* This cannot be free'd here because a redirection will then try to access this and segfault */
+ /* Covered in a testcase in tests/check_http.t */
+ /* free(http_opt_headers); */
+ }
+ asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf);
+ asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
+ /* we finished our request, send empty line with CRLF */
+ asprintf (&buf, "%s%s", buf, CRLF);
+ if (verbose) printf ("%s\n", buf);
+ send(sd, buf, strlen (buf), 0);
+ buf[0]='\0';
+
+ if (verbose) printf ("Receive response from proxy\n");
+ read (sd, buffer, MAX_INPUT_BUFFER-1);
+ if (verbose) printf ("%s", buffer);
+ /* Here we should check if we got HTTP/1.1 200 Connection established */
+ }
+#ifdef HAVE_SSL
+ elapsed_time_connect = (double)microsec_connect / 1.0e6;
+ if (use_ssl == true) {
+ gettimeofday (&tv_temp, NULL);
+ result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
+ if (verbose) printf ("SSL initialized\n");
+ if (result != STATE_OK)
+ die (STATE_CRITICAL, NULL);
+ microsec_ssl = deltime (tv_temp);
+ elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
+ if (check_cert == true) {
+ result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
+ if (continue_after_check_cert == false) {
+ if (sd) close(sd);
+ np_net_ssl_cleanup();
+ return result;
+ }
+ }
+ }
+#endif /* HAVE_SSL */
+
+ if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0
+ && host_name != NULL && use_ssl == true)
+ asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
+ else
+ asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
+
+ /* tell HTTP/1.1 servers not to keep the connection alive */
+ xasprintf (&buf, "%sConnection: close\r\n", buf);
+
+ /* check if Host header is explicitly set in options */
+ if (http_opt_headers_count) {
+ for (i = 0; i < http_opt_headers_count ; i++) {
+ if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
+ force_host_header = http_opt_headers[i];
+ }
+ }
+ }
+
+ /* optionally send the host header info */
+ if (host_name) {
+ if (force_host_header) {
+ xasprintf (&buf, "%s%s\r\n", buf, force_host_header);
+ }
+ else {
+ /*
+ * Specify the port only if we're using a non-default port (see RFC 2616,
+ * 14.23). Some server applications/configurations cause trouble if the
+ * (default) port is explicitly specified in the "Host:" header line.
+ */
+ if ((use_ssl == false && virtual_port == HTTP_PORT) ||
+ (use_ssl == true && virtual_port == HTTPS_PORT) ||
+ (server_address != NULL && strcmp(http_method, "CONNECT") == 0
+ && host_name != NULL && use_ssl == true))
+ xasprintf (&buf, "%sHost: %s\r\n", buf, host_name);
+ else
+ xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
+ }
+ }
+
+ /* optionally send any other header tag */
+ if (http_opt_headers_count) {
+ for (i = 0; i < http_opt_headers_count ; i++) {
+ if (force_host_header != http_opt_headers[i]) {
+ xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]);
+ }
+ }
+ /* This cannot be free'd here because a redirection will then try to access this and segfault */
+ /* Covered in a testcase in tests/check_http.t */
+ /* free(http_opt_headers); */
+ }
+
+ /* optionally send the authentication info */
+ if (strlen(user_auth)) {
+ base64_encode_alloc (user_auth, strlen (user_auth), &auth);
+ xasprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
+ }
+
+ /* optionally send the proxy authentication info */
+ if (strlen(proxy_auth)) {
+ base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth);
+ xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
+ }
+
+ /* either send http POST data (any data, not only POST)*/
+ if (http_post_data) {
+ if (http_content_type) {
+ xasprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
+ } else {
+ xasprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
+ }
+
+ xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
+ xasprintf (&buf, "%s%s", buf, http_post_data);
+ } else {
+ /* or just a newline so the server knows we're done with the request */
+ xasprintf (&buf, "%s%s", buf, CRLF);
+ }
+
+ if (verbose) printf ("%s\n", buf);
+ gettimeofday (&tv_temp, NULL);
+ my_send (buf, strlen (buf));
+ microsec_headers = deltime (tv_temp);
+ elapsed_time_headers = (double)microsec_headers / 1.0e6;
+
+ /* fetch the page */
+ full_page = strdup("");
+ gettimeofday (&tv_temp, NULL);
+ while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
+ if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) {
+ microsec_firstbyte = deltime (tv_temp);
+ elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6;
+ }
+ while ((pos = memchr(buffer, '\0', i))) {
+ /* replace nul character with a blank */
+ *pos = ' ';
+ }
+ buffer[i] = '\0';
+
+ if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
+
+ memmove(&full_page_new[pagesize], buffer, i + 1);
+
+ full_page = full_page_new;
+
+ pagesize += i;
+
+ if (no_body && document_headers_done (full_page)) {
+ i = 0;
+ break;
+ }
+ }
+ microsec_transfer = deltime (tv_temp);
+ elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
+
+ if (i < 0 && errno != ECONNRESET) {
+ die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
+ }
+
+ /* return a CRITICAL status if we couldn't read any data */
+ if (pagesize == (size_t) 0)
+ die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
+
+ /* close the connection */
+ if (sd) close(sd);
+#ifdef HAVE_SSL
+ np_net_ssl_cleanup();
+#endif
+
+ /* Save check time */
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ /* leave full_page untouched so we can free it later */
+ page = full_page;
+
+ if (verbose)
+ printf ("%s://%s:%d%s is %d characters\n",
+ use_ssl ? "https" : "http", server_address,
+ server_port, server_url, (int)pagesize);
+
+ /* find status line and null-terminate it */
+ status_line = page;
+ page += (size_t) strcspn (page, "\r\n");
+ pos = page;
+ page += (size_t) strspn (page, "\r\n");
+ status_line[strcspn(status_line, "\r\n")] = 0;
+ strip (status_line);
+ if (verbose)
+ printf ("STATUS: %s\n", status_line);
+
+ /* find header info and null-terminate it */
+ header = page;
+ while (strcspn (page, "\r\n") > 0) {
+ page += (size_t) strcspn (page, "\r\n");
+ pos = page;
+ if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
+ (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
+ page += (size_t) 2;
+ else
+ page += (size_t) 1;
+ }
+ page += (size_t) strspn (page, "\r\n");
+ header[pos - header] = 0;
+ if (verbose)
+ printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
+ (no_body ? " [[ skipped ]]" : page));
+
+ /* make sure the status line matches the response we are looking for */
+ if (!expected_statuscode (status_line, server_expect)) {
+ if (server_port == HTTP_PORT)
+ xasprintf (&msg,
+ _("Invalid HTTP response received from host: %s\n"),
+ status_line);
+ else
+ xasprintf (&msg,
+ _("Invalid HTTP response received from host on port %d: %s\n"),
+ server_port, status_line);
+ if (show_body)
+ xasprintf (&msg, _("%s\n%s"), msg, page);
+ die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
+ }
+
+ /* Bypass normal status line check if server_expect was set by user and not default */
+ /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
+ if ( server_expect_yn ) {
+ xasprintf (&msg,
+ _("Status line output matched \"%s\" - "), server_expect);
+ if (verbose)
+ printf ("%s\n",msg);
+ }
+ else {
+ /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
+ /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
+ /* Status-Code = 3 DIGITS */
+
+ status_code = strchr (status_line, ' ') + sizeof (char);
+ if (strspn (status_code, "1234567890") != 3)
+ die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
+
+ http_status = atoi (status_code);
+
+ /* check the return code */
+
+ if (http_status >= 600 || http_status < 100) {
+ die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
+ }
+ /* server errors result in a critical state */
+ else if (http_status >= 500) {
+ xasprintf (&msg, _("%s - "), status_line);
+ result = STATE_CRITICAL;
+ }
+ /* client errors result in a warning state */
+ else if (http_status >= 400) {
+ xasprintf (&msg, _("%s - "), status_line);
+ result = max_state_alt(STATE_WARNING, result);
+ }
+ /* check redirected page if specified */
+ else if (http_status >= 300) {
+
+ if (onredirect == STATE_DEPENDENT)
+ redir (header, status_line);
+ else
+ result = max_state_alt(onredirect, result);
+ xasprintf (&msg, _("%s - "), status_line);
+ } /* end if (http_status >= 300) */
+ else {
+ /* Print OK status anyway */
+ xasprintf (&msg, _("%s - "), status_line);
+ }
+
+ } /* end else (server_expect_yn) */
+
+ /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
+ alarm (0);
+
+ if (maximum_age >= 0) {
+ result = max_state_alt(check_document_dates(header, &msg), result);
+ }
+
+ /* Page and Header content checks go here */
+ if (strlen(header_expect) > 0) {
+ if (strstr(header, header_expect) == NULL) {
+ // We did not find the header, the rest is for building the output and setting the state
+ char output_header_search[30] = "";
+
+ strncpy(&output_header_search[0], header_expect,
+ sizeof(output_header_search));
+
+ if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
+ bcopy("...",
+ &output_header_search[sizeof(output_header_search) - 4],
+ 4);
+ }
+
+ xasprintf (&msg,
+ _("%sheader '%s' not found on '%s://%s:%d%s', "),
+ msg,
+ output_header_search, use_ssl ? "https" : "http",
+ host_name ? host_name : server_address, server_port,
+ server_url);
+
+ result = STATE_CRITICAL;
+ }
+ }
+
+ // At this point we should test if the content is chunked and unchunk it, so
+ // it can be searched (and possibly printed)
+ const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
+ regex_t chunked_header_regex;
+
+ if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
+ die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex");
+ }
+
+ regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found
+
+ if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
+ if (verbose) {
+ printf("Found chunked content\n");
+ }
+ // We actually found the chunked header
+ char *tmp = unchunk_content(page);
+ if (tmp == NULL) {
+ die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body");
+ }
+ page = tmp;
+ }
+
+ if (strlen(string_expect) > 0) {
+ if (!strstr(page, string_expect)) {
+ // We found the string the body, the rest is for building the output
+ char output_string_search[30] = "";
+ strncpy(&output_string_search[0], string_expect,
+ sizeof(output_string_search));
+ if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
+ bcopy("...", &output_string_search[sizeof(output_string_search) - 4],
+ 4);
+ }
+ xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
+ result = STATE_CRITICAL;
+ }
+ }
+
+ if (strlen(regexp) > 0) {
+ errcode = regexec(&preg, page, REGS, pmatch, 0);
+ if ((errcode == 0 && invert_regex == 0) ||
+ (errcode == REG_NOMATCH && invert_regex == 1)) {
+ /* OK - No-op to avoid changing the logic around it */
+ result = max_state_alt(STATE_OK, result);
+ }
+ else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
+ if (invert_regex == 0)
+ xasprintf (&msg, _("%spattern not found, "), msg);
+ else
+ xasprintf (&msg, _("%spattern found, "), msg);
+ result = STATE_CRITICAL;
+ }
+ else {
+ /* FIXME: Shouldn't that be UNKNOWN? */
+ regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+ xasprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf);
+ result = STATE_CRITICAL;
+ }
+ }
+
+ /* make sure the page is of an appropriate size */
+ /* page_len = get_content_length(header); */
+ /* FIXME: Will this work with -N ? IMHO we should use
+ * get_content_length(header) and always check if it's different than the
+ * returned pagesize
+ */
+ /* FIXME: IIRC pagesize returns headers - shouldn't we make
+ * it == get_content_length(header) ??
+ */
+ page_len = pagesize;
+ if ((max_page_len > 0) && (page_len > max_page_len)) {
+ xasprintf (&msg, _("%spage size %d too large, "), msg, page_len);
+ result = max_state_alt(STATE_WARNING, result);
+ } else if ((min_page_len > 0) && (page_len < min_page_len)) {
+ xasprintf (&msg, _("%spage size %d too small, "), msg, page_len);
+ result = max_state_alt(STATE_WARNING, result);
+ }
+
+ /* Cut-off trailing characters */
+ if(msg[strlen(msg)-2] == ',')
+ msg[strlen(msg)-2] = '\0';
+ else
+ msg[strlen(msg)-3] = '\0';
+
+ /* check elapsed time */
+ if (show_extended_perfdata)
+ xasprintf (&msg,
+ _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"),
+ msg, page_len, elapsed_time,
+ (display_html ? "</A>" : ""),
+ perfd_time (elapsed_time),
+ perfd_size (page_len),
+ perfd_time_connect (elapsed_time_connect),
+ use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "",
+ perfd_time_headers (elapsed_time_headers),
+ perfd_time_firstbyte (elapsed_time_firstbyte),
+ perfd_time_transfer (elapsed_time_transfer));
+ else
+ xasprintf (&msg,
+ _("%s - %d bytes in %.3f second response time %s|%s %s"),
+ msg, page_len, elapsed_time,
+ (display_html ? "</A>" : ""),
+ perfd_time (elapsed_time),
+ perfd_size (page_len));
+
+ if (show_body)
+ xasprintf (&msg, _("%s\n%s"), msg, page);
+
+ result = max_state_alt(get_status(elapsed_time, thlds), result);
+
+ die (result, "HTTP %s: %s\n", state_text(result), msg);
+ /* die failed? */
+ return STATE_UNKNOWN;
+}
+
+/* Receivces a pointer to the beginning of the body of a HTTP message
+ * which is chunked and returns a pointer to a freshly allocated memory
+ * region containing the unchunked body or NULL if something failed.
+ * The result must be freed by the caller.
+ */
+char *unchunk_content(const char *content) {
+ // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
+ // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
+ char *result = NULL;
+ char *start_of_chunk;
+ char* end_of_chunk;
+ long size_of_chunk;
+ const char *pointer = content;
+ char *endptr;
+ long length_of_chunk = 0;
+ size_t overall_size = 0;
+
+ while (true) {
+ size_of_chunk = strtol(pointer, &endptr, 16);
+ if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
+ // Apparently underflow or overflow, should not happen
+ if (verbose) {
+ printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
+ }
+ return NULL;
+ }
+ if (endptr == pointer) {
+ // Apparently this was not a number
+ if (verbose) {
+ printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
+ }
+ return NULL;
+ }
+
+ // So, we got the length of the chunk
+ if (*endptr == ';') {
+ // Chunk extension starts here
+ while (*endptr != '\r') {
+ endptr++;
+ }
+ }
+
+ start_of_chunk = endptr + 2;
+ end_of_chunk = start_of_chunk + size_of_chunk;
+ length_of_chunk = (long)(end_of_chunk - start_of_chunk);
+ pointer = end_of_chunk + 2; //Next number should be here
+
+ if (length_of_chunk == 0) {
+ // Chunk length is 0, so this is the last one
+ break;
+ }
+
+ overall_size += length_of_chunk;
+
+ if (result == NULL) {
+ // Size of the chunk plus the ending NULL byte
+ result = (char *)malloc(length_of_chunk +1);
+ if (result == NULL) {
+ if (verbose) {
+ printf("Failed to allocate memory for unchunked body\n");
+ }
+ return NULL;
+ }
+ } else {
+ // Enlarge memory to the new size plus the ending NULL byte
+ void *tmp = realloc(result, overall_size +1);
+ if (tmp == NULL) {
+ if (verbose) {
+ printf("Failed to allocate memory for unchunked body\n");
+ }
+ return NULL;
+ } else {
+ result = tmp;
+ }
+ }
+
+ memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
+ }
+
+ if (overall_size == 0 && result == NULL) {
+ // We might just have received the end chunk without previous content, so result is never allocated
+ result = calloc(1, sizeof(char));
+ // No error handling here, we can only return NULL anyway
+ } else {
+ result[overall_size] = '\0';
+ }
+ return result;
+}
+
+/* per RFC 2396 */
+#define URI_HTTP "%5[HTPShtps]"
+#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
+#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
+#define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
+#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
+#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
+#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
+#define HD4 URI_HTTP "://" URI_HOST
+/* relative reference redirect like //www.site.org/test https://tools.ietf.org/html/rfc3986 */
+#define HD5 "//" URI_HOST "/" URI_PATH
+#define HD6 URI_PATH
+
+void
+redir (char *pos, char *status_line)
+{
+ int i = 0;
+ char *x;
+ char xx[2];
+ char type[6];
+ char *addr;
+ char *url;
+
+ addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
+ if (addr == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
+
+ memset(addr, 0, MAX_IPV4_HOSTLENGTH);
+ url = malloc (strcspn (pos, "\r\n"));
+ if (url == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
+
+ while (pos) {
+ sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
+ if (i == 0) {
+ pos += (size_t) strcspn (pos, "\r\n");
+ pos += (size_t) strspn (pos, "\r\n");
+ if (strlen(pos) == 0)
+ die (STATE_UNKNOWN,
+ _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
+ status_line, (display_html ? "</A>" : ""));
+ continue;
+ }
+
+ pos += i;
+ pos += strspn (pos, " \t");
+
+ /*
+ * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
+ * preceding each extra line with at least one SP or HT.''
+ */
+ for (; (i = strspn (pos, "\r\n")); pos += i) {
+ pos += i;
+ if (!(i = strspn (pos, " \t"))) {
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
+ display_html ? "</A>" : "");
+ }
+ }
+
+ url = realloc (url, strcspn (pos, "\r\n") + 1);
+ if (url == NULL)
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
+
+ /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
+ if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
+ url = prepend_slash (url);
+ use_ssl = server_type_check (type);
+ }
+
+ /* URI_HTTP URI_HOST URI_PATH */
+ else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
+ url = prepend_slash (url);
+ use_ssl = server_type_check (type);
+ i = server_port_check (use_ssl);
+ }
+
+ /* URI_HTTP URI_HOST URI_PORT */
+ else if (sscanf (pos, HD3, type, addr, &i) == 3) {
+ strcpy (url, HTTP_URL);
+ use_ssl = server_type_check (type);
+ }
+
+ /* URI_HTTP URI_HOST */
+ else if (sscanf (pos, HD4, type, addr) == 2) {
+ strcpy (url, HTTP_URL);
+ use_ssl = server_type_check (type);
+ i = server_port_check (use_ssl);
+ }
+ /* URI_HTTP, URI_HOST, URI_PATH */
+ else if (sscanf (pos, HD5, addr, url) == 2) {
+ if(use_ssl){
+ strcpy (type,"https");
+ }
+ else{
+ strcpy (type, server_type);
+ }
+ xasprintf (&url, "/%s", url);
+ use_ssl = server_type_check (type);
+ i = server_port_check (use_ssl);
+ }
+
+ /* URI_PATH */
+ else if (sscanf (pos, HD6, url) == 1) {
+ /* relative url */
+ if ((url[0] != '/')) {
+ if ((x = strrchr(server_url, '/')))
+ *x = '\0';
+ xasprintf (&url, "%s/%s", server_url, url);
+ }
+ i = server_port;
+ strcpy (type, server_type);
+ strcpy (addr, host_name ? host_name : server_address);
+ }
+
+ else {
+ die (STATE_UNKNOWN,
+ _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
+ pos, (display_html ? "</A>" : ""));
+ }
+
+ break;
+
+ } /* end while (pos) */
+
+ if (++redir_depth > max_depth)
+ die (STATE_WARNING,
+ _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
+ max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
+
+ if (server_port==i &&
+ !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
+ (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) &&
+ !strcmp(server_url, url))
+ die (STATE_CRITICAL,
+ _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
+ type, addr, i, url, (display_html ? "</A>" : ""));
+
+ strcpy (server_type, type);
+
+ free (host_name);
+ host_name = strndup (addr, MAX_IPV4_HOSTLENGTH);
+
+ if (!(followsticky & STICKY_HOST)) {
+ free (server_address);
+ server_address = strndup (addr, MAX_IPV4_HOSTLENGTH);
+ }
+ if (!(followsticky & STICKY_PORT)) {
+ server_port = i;
+ }
+
+ free (server_url);
+ server_url = url;
+
+ if (server_port > MAX_PORT)
+ die (STATE_UNKNOWN,
+ _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
+ MAX_PORT, server_type, server_address, server_port, server_url,
+ display_html ? "</A>" : "");
+
+ /* reset virtual port */
+ virtual_port = server_port;
+
+ if (verbose)
+ printf (_("Redirection to %s://%s:%d%s\n"), server_type,
+ host_name ? host_name : server_address, server_port, server_url);
+
+ free(addr);
+ check_http ();
+}
+
+
+bool
+server_type_check (const char *type)
+{
+ if (strcmp (type, "https"))
+ return false;
+ else
+ return true;
+}
+
+int
+server_port_check (int ssl_flag)
+{
+ if (ssl_flag)
+ return HTTPS_PORT;
+ else
+ return HTTP_PORT;
+}
+
+char *perfd_time (double elapsed_time)
+{
+ return fperfdata ("time", elapsed_time, "s",
+ thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
+ thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
+ true, 0, true, socket_timeout);
+}
+
+char *perfd_time_connect (double elapsed_time_connect)
+{
+ return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_ssl (double elapsed_time_ssl)
+{
+ return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_headers (double elapsed_time_headers)
+{
+ return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_firstbyte (double elapsed_time_firstbyte)
+{
+ return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_time_transfer (double elapsed_time_transfer)
+{
+ return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
+}
+
+char *perfd_size (int page_len)
+{
+ return perfdata ("size", page_len, "B",
+ (min_page_len>0?true:false), min_page_len,
+ (min_page_len>0?true:false), 0,
+ true, 0, false, 0);
+}
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
+ printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
+ printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
+ printf ("%s\n", _("certificate expiration times."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+#ifdef HAVE_SSL
+ printf (_("In the first form, make an HTTP request."));
+ printf (_("In the second form, connect to the server and check the TLS certificate."));
+#endif
+ printf (_("NOTE: One or both of -H and -I must be specified"));
+
+ printf ("\n");
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-H, --hostname=ADDRESS");
+ printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
+ printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
+ printf (" %s\n", "-I, --IP-address=ADDRESS");
+ printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
+ printf (" %s\n", "-p, --port=INTEGER");
+ printf (" %s", _("Port number (default: "));
+ printf ("%d)\n", HTTP_PORT);
+
+ printf (UT_IPv46);
+
+#ifdef HAVE_SSL
+ printf (" %s\n", "-S, --ssl=VERSION[+]");
+ printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
+ printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
+ printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
+ printf (" %s\n", "--sni");
+ printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
+ printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
+ printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
+ printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
+ printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
+ printf (" %s\n", "--continue-after-certificate");
+ printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
+ printf (" %s\n", _("Does nothing unless -C is used."));
+ printf (" %s\n", "-J, --client-cert=FILE");
+ printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
+ printf (" %s\n", _("to be used in establishing the SSL session"));
+ printf (" %s\n", "-K, --private-key=FILE");
+ printf (" %s\n", _("Name of file containing the private key (PEM format)"));
+ printf (" %s\n", _("matching the client certificate"));
+#endif
+
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
+ printf (" %s", _("the first (status) line of the server response (default: "));
+ printf ("%s)\n", HTTP_EXPECT);
+ printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
+ printf (" %s\n", "-d, --header-string=STRING");
+ printf (" %s\n", _("String to expect in the response headers"));
+ printf (" %s\n", "-s, --string=STRING");
+ printf (" %s\n", _("String to expect in the content"));
+ printf (" %s\n", "-u, --url=PATH");
+ printf (" %s\n", _("URL to GET or POST (default: /)"));
+ printf (" %s\n", "-P, --post=STRING");
+ printf (" %s\n", _("URL encoded http POST data"));
+ printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)");
+ printf (" %s\n", _("Set HTTP method."));
+ printf (" %s\n", "-N, --no-body");
+ printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
+ printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
+ printf (" %s\n", "-M, --max-age=SECONDS");
+ printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
+ printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
+ printf (" %s\n", "-T, --content-type=STRING");
+ printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
+
+ printf (" %s\n", "-l, --linespan");
+ printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
+ printf (" %s\n", "-r, --regex, --ereg=STRING");
+ printf (" %s\n", _("Search page for regex STRING"));
+ printf (" %s\n", "-R, --eregi=STRING");
+ printf (" %s\n", _("Search page for case-insensitive regex STRING"));
+ printf (" %s\n", "--invert-regex");
+ printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
+
+ printf (" %s\n", "-a, --authorization=AUTH_PAIR");
+ printf (" %s\n", _("Username:password on sites with basic authentication"));
+ printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
+ printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
+ printf (" %s\n", "-A, --useragent=STRING");
+ printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
+ printf (" %s\n", "-k, --header=STRING");
+ printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
+ printf (" %s\n", "-E, --extended-perfdata");
+ printf (" %s\n", _("Print additional performance data"));
+ printf (" %s\n", "-B, --show-body");
+ printf (" %s\n", _("Print body content below status line"));
+ printf (" %s\n", "-L, --link");
+ printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
+ printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
+ printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
+ printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
+ printf (" %s\n", "--max-redirs=INTEGER");
+ printf (" %s", _("Maximal number of redirects (default: "));
+ printf ("%d)\n", DEFAULT_MAX_REDIRS);
+ printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
+ printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
+ printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
+ printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
+ printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
+ printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
+ printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
+
+#ifdef HAVE_SSL
+ printf ("\n");
+ printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
+ printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
+ printf (" %s\n", _("certificate is still valid for the specified number of days."));
+ printf ("\n");
+ printf (" %s\n", _("Please note that this plugin does not check if the presented server"));
+ printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
+ printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
+ printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
+ printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
+ printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
+ printf (" %s\n", _("a STATE_CRITICAL will be returned."));
+ printf ("\n");
+ printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
+ printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
+ printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
+ printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
+ printf (" %s\n\n", _("the certificate is expired."));
+ printf ("\n");
+ printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14");
+ printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
+ printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
+ printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
+ printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
+
+ printf (" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
+ printf (" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com "));
+ printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
+ printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
+ printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
+ printf (" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used"));
+ printf (" %s\n", _("inside the proxied connection: -j CONNECT:POST"));
+
+#endif
+
+ printf (UT_SUPPORT);
+
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
+ printf (" [-J <client certificate file>] [-K <private key>]\n");
+ printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
+ printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
+ printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
+ printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
+ printf (" [-A string] [-k string] [-S <version>] [--sni]\n");
+ printf (" [-T <content-type>] [-j method]\n");
+ printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
+ printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
+}
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
new file mode 100644
index 0000000..0160d98
--- /dev/null
+++ b/plugins/check_ide_smart.c
@@ -0,0 +1,608 @@
+/*****************************************************************************
+*
+* Monitoring check_ide_smart plugin
+* ide-smart 1.3 - IDE S.M.A.R.T. checking tool
+*
+* License: GPL
+* Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
+* 1998 Gadi Oxman <gadio@netvision.net.il>
+* Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ide_smart plugin
+*
+* This plugin checks a local hard drive with the (Linux specific) SMART
+* interface
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ide_smart";
+const char *copyright = "1998-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+
+void print_help (void);
+void print_usage (void);
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#ifdef __linux__
+#include <linux/hdreg.h>
+#include <linux/types.h>
+
+#define OPEN_MODE O_RDONLY
+#endif /* __linux__ */
+#ifdef __NetBSD__
+#include <sys/device.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/videoio.h> /* for __u8 and friends */
+#include <sys/scsiio.h>
+#include <sys/ataio.h>
+#include <dev/ata/atareg.h>
+#include <dev/ic/wdcreg.h>
+
+#define SMART_ENABLE WDSM_ENABLE_OPS
+#define SMART_DISABLE WDSM_DISABLE_OPS
+#define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM
+#define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */
+
+#define OPEN_MODE O_RDWR
+#endif /* __NetBSD__ */
+#include <errno.h>
+
+#define NR_ATTRIBUTES 30
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* */
+
+#define PREFAILURE 2
+#define ADVISORY 1
+#define OPERATIONAL 0
+#define UNKNOWN -1
+
+typedef struct threshold_s
+{
+ __u8 id;
+ __u8 threshold;
+ __u8 reserved[10];
+}
+__attribute__ ((packed)) threshold_t;
+
+typedef struct thresholds_s
+{
+ __u16 revision;
+ threshold_t thresholds[NR_ATTRIBUTES];
+ __u8 reserved[18];
+ __u8 vendor[131];
+ __u8 checksum;
+}
+__attribute__ ((packed)) thresholds_t;
+
+typedef struct value_s
+{
+ __u8 id;
+ __u16 status;
+ __u8 value;
+ __u8 vendor[8];
+}
+__attribute__ ((packed)) value_t;
+
+typedef struct values_s
+{
+ __u16 revision;
+ value_t values[NR_ATTRIBUTES];
+ __u8 offline_status;
+ __u8 vendor1;
+ __u16 offline_timeout;
+ __u8 vendor2;
+ __u8 offline_capability;
+ __u16 smart_capability;
+ __u8 reserved[16];
+ __u8 vendor[125];
+ __u8 checksum;
+}
+__attribute__ ((packed)) values_t;
+
+struct
+{
+ __u8 value;
+ char *text;
+}
+
+offline_status_text[] =
+ {
+ {0x00, "NeverStarted"},
+ {0x02, "Completed"},
+ {0x04, "Suspended"},
+ {0x05, "Aborted"},
+ {0x06, "Failed"},
+ {0, 0}
+ };
+
+struct
+{
+ __u8 value;
+ char *text;
+}
+
+smart_command[] =
+ {
+ {SMART_ENABLE, "SMART_ENABLE"},
+ {SMART_DISABLE, "SMART_DISABLE"},
+ {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
+ {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
+ };
+
+
+/* Index to smart_command table, keep in order */
+enum SmartCommand
+ { SMART_CMD_ENABLE,
+ SMART_CMD_DISABLE,
+ SMART_CMD_IMMEDIATE_OFFLINE,
+ SMART_CMD_AUTO_OFFLINE
+ };
+
+char *get_offline_text (int);
+int smart_read_values (int, values_t *);
+int nagios (values_t *, thresholds_t *);
+void print_value (value_t *, threshold_t *);
+void print_values (values_t *, thresholds_t *);
+int smart_cmd_simple (int, enum SmartCommand, __u8, char);
+int smart_read_thresholds (int, thresholds_t *);
+int verbose = FALSE;
+
+int
+main (int argc, char *argv[])
+{
+ char *device = NULL;
+ int o, longindex;
+ int retval = 0;
+
+ thresholds_t thresholds;
+ values_t values;
+ int fd;
+
+ static struct option longopts[] = {
+ {"device", required_argument, 0, 'd'},
+ {"immediate", no_argument, 0, 'i'},
+ {"quiet-check", no_argument, 0, 'q'},
+ {"auto-on", no_argument, 0, '1'},
+ {"auto-off", no_argument, 0, '0'},
+ {"nagios", no_argument, 0, 'n'}, /* DEPRECATED, but we still accept it */
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0}
+ };
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ while (1) {
+
+ o = getopt_long (argc, argv, "+d:iq10nhVv", longopts, &longindex);
+
+ if (o == -1 || o == EOF || o == 1)
+ break;
+
+ switch (o) {
+ case 'd':
+ device = optarg;
+ break;
+ case 'q':
+ fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\"."));
+ fprintf (stderr, "%s\n", _("Nagios-compatible output is now always returned."));
+ break;
+ case 'i':
+ case '1':
+ case '0':
+ printf ("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help)."));
+ return STATE_CRITICAL;
+ break;
+ case 'n':
+ fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the"));
+ fprintf (stderr, "%s\n", _("default and will be removed from future releases."));
+ break;
+ case 'v': /* verbose */
+ verbose = TRUE;
+ break;
+ case 'h':
+ print_help ();
+ return STATE_UNKNOWN;
+ case 'V':
+ print_revision (progname, NP_VERSION);
+ return STATE_UNKNOWN;
+ default:
+ usage5 ();
+ }
+ }
+
+ if (optind < argc) {
+ device = argv[optind];
+ }
+
+ if (!device) {
+ print_help ();
+ return STATE_UNKNOWN;
+ }
+
+ fd = open (device, OPEN_MODE);
+
+ if (fd < 0) {
+ printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno));
+ return STATE_CRITICAL;
+ }
+
+ if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, FALSE)) {
+ printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
+ return STATE_CRITICAL;
+ }
+
+ smart_read_values (fd, &values);
+ smart_read_thresholds (fd, &thresholds);
+ retval = nagios (&values, &thresholds);
+ if (verbose) print_values (&values, &thresholds);
+
+ close (fd);
+ return retval;
+}
+
+
+
+char *
+get_offline_text (int status)
+{
+ int i;
+ for (i = 0; offline_status_text[i].text; i++) {
+ if (offline_status_text[i].value == status) {
+ return offline_status_text[i].text;
+ }
+ }
+ return "UNKNOWN";
+}
+
+
+
+int
+smart_read_values (int fd, values_t * values)
+{
+#ifdef __linux__
+ int e;
+ __u8 args[4 + 512];
+ args[0] = WIN_SMART;
+ args[1] = 0;
+ args[2] = SMART_READ_VALUES;
+ args[3] = 1;
+ if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
+ e = errno;
+ printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
+ return e;
+ }
+ memcpy (values, args + 4, 512);
+#endif /* __linux__ */
+#ifdef __NetBSD__
+ struct atareq req;
+ unsigned char inbuf[DEV_BSIZE];
+
+ memset(&req, 0, sizeof(req));
+ req.timeout = 1000;
+ memset(&inbuf, 0, sizeof(inbuf));
+
+ req.flags = ATACMD_READ;
+ req.features = WDSM_RD_DATA;
+ req.command = WDCC_SMART;
+ req.databuf = (char *)inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = WDSMART_CYL;
+
+ if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
+ if (req.retsts != ATACMD_OK)
+ errno = ENODEV;
+ }
+
+ if (errno != 0) {
+ int e = errno;
+ printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
+ return e;
+ }
+
+ (void)memcpy(values, inbuf, 512);
+#endif /* __NetBSD__ */
+ return 0;
+}
+
+
+
+int
+nagios (values_t * p, thresholds_t * t)
+{
+ value_t * value = p->values;
+ threshold_t * threshold = t->thresholds;
+ int status = OPERATIONAL;
+ int prefailure = 0;
+ int advisory = 0;
+ int failed = 0;
+ int passed = 0;
+ int total = 0;
+ int i;
+ for (i = 0; i < NR_ATTRIBUTES; i++) {
+ if (value->id && threshold->id && value->id == threshold->id) {
+ if (value->value < threshold->threshold) {
+ ++failed;
+ if (value->status & 1) {
+ status = PREFAILURE;
+ ++prefailure;
+ }
+ else {
+ status = ADVISORY;
+ ++advisory;
+ }
+ }
+ else {
+ ++passed;
+ }
+ ++total;
+ }
+ ++value;
+ ++threshold;
+ }
+ switch (status) {
+ case PREFAILURE:
+ printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
+ prefailure,
+ prefailure > 1 ? 's' : ' ',
+ failed,
+ total);
+ status=STATE_CRITICAL;
+ break;
+ case ADVISORY:
+ printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
+ advisory,
+ advisory > 1 ? "ies" : "y",
+ failed,
+ total);
+ status=STATE_WARNING;
+ break;
+ case OPERATIONAL:
+ printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
+ status=STATE_OK;
+ break;
+ default:
+ printf (_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status,
+ passed, total);
+ status = STATE_UNKNOWN;
+ break;
+ }
+ return status;
+}
+
+
+
+void
+print_value (value_t * p, threshold_t * t)
+{
+ printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
+ p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
+ p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
+ p->value >= t->threshold ? "Passed" : "Failed");
+}
+
+
+
+void
+print_values (values_t * p, thresholds_t * t)
+{
+ value_t * value = p->values;
+ threshold_t * threshold = t->thresholds;
+ int i;
+ for (i = 0; i < NR_ATTRIBUTES; i++) {
+ if (value->id && threshold->id && value->id == threshold->id) {
+ print_value (value++, threshold++);
+ }
+ }
+ printf
+ (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
+ p->offline_status,
+ get_offline_text (p->offline_status & 0x7f),
+ (p->offline_status & 0x80 ? "Yes" : "No"),
+ p->offline_timeout / 60);
+ printf
+ (_("OffLineCapability=%d {%s %s %s}\n"),
+ p->offline_capability,
+ p->offline_capability & 1 ? "Immediate" : "",
+ p->offline_capability & 2 ? "Auto" : "",
+ p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
+ printf
+ (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
+ p->revision,
+ p->checksum,
+ p->smart_capability,
+ p->smart_capability & 1 ? "SaveOnStandBy" : "",
+ p->smart_capability & 2 ? "AutoSave" : "");
+}
+
+
+int
+smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error)
+{
+ int e = STATE_UNKNOWN;
+#ifdef __linux__
+ __u8 args[4];
+ args[0] = WIN_SMART;
+ args[1] = val0;
+ args[2] = smart_command[command].value;
+ args[3] = 0;
+ if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
+ e = STATE_CRITICAL;
+ if (show_error)
+ printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
+ } else {
+ e = STATE_OK;
+ if (show_error)
+ printf (_("OK - Command sent (%s)\n"), smart_command[command].text);
+ }
+
+#endif /* __linux__ */
+#ifdef __NetBSD__
+ struct atareq req;
+
+ memset(&req, 0, sizeof(req));
+ req.timeout = 1000;
+ req.flags = ATACMD_READREG;
+ req.features = smart_command[command].value;
+ req.command = WDCC_SMART;
+ req.cylinder = WDSMART_CYL;
+ req.sec_count = val0;
+
+ if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
+ if (req.retsts != ATACMD_OK)
+ errno = ENODEV;
+ if (req.cylinder != WDSMART_CYL)
+ errno = ENODEV;
+ }
+
+ if (errno != 0) {
+ e = STATE_CRITICAL;
+ if (show_error)
+ printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
+ } else {
+ e = STATE_OK;
+ if (show_error)
+ printf (_("OK - Command sent (%s)\n"), smart_command[command].text);
+ }
+
+#endif /* __NetBSD__ */
+ return e;
+}
+
+
+
+int
+smart_read_thresholds (int fd, thresholds_t * thresholds)
+{
+#ifdef __linux__
+ int e;
+ __u8 args[4 + 512];
+ args[0] = WIN_SMART;
+ args[1] = 0;
+ args[2] = SMART_READ_THRESHOLDS;
+ args[3] = 1;
+ if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
+ e = errno;
+ printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
+ return e;
+ }
+ memcpy (thresholds, args + 4, 512);
+#endif /* __linux__ */
+#ifdef __NetBSD__
+ struct atareq req;
+ unsigned char inbuf[DEV_BSIZE];
+
+ memset(&req, 0, sizeof(req));
+ req.timeout = 1000;
+ memset(&inbuf, 0, sizeof(inbuf));
+
+ req.flags = ATACMD_READ;
+ req.features = WDSM_RD_THRESHOLDS;
+ req.command = WDCC_SMART;
+ req.databuf = (char *)inbuf;
+ req.datalen = sizeof(inbuf);
+ req.cylinder = WDSMART_CYL;
+
+ if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
+ if (req.retsts != ATACMD_OK)
+ errno = ENODEV;
+ }
+
+ if (errno != 0) {
+ int e = errno;
+ printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
+ return e;
+ }
+
+ (void)memcpy(thresholds, inbuf, 512);
+#endif /* __NetBSD__ */
+ return 0;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
+ printf ("Plugin implementation - 1999 Robert Dale <rdale@digital-mission.com>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php]."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-d, --device=DEVICE");
+ printf (" %s\n", _("Select device DEVICE"));
+ printf (" %s\n", _("Note: if the device is specified without this option, any further option will"));
+ printf (" %s\n", _("be ignored."));
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("The SMART command modes (-i/--immediate, -0/--auto-off and -1/--auto-on) were"));
+ printf (" %s\n", _("broken in an underhand manner and have been disabled. You can use smartctl"));
+ printf (" %s\n", _("instead:"));
+ printf (" %s\n", _("-0/--auto-off: use \"smartctl --offlineauto=off\""));
+ printf (" %s\n", _("-1/--auto-on: use \"smartctl --offlineauto=on\""));
+ printf (" %s\n", _("-i/--immediate: use \"smartctl --test=offline\""));
+
+ printf (UT_SUPPORT);
+}
+
+ /* todo : add to the long nanual as example
+ *
+ * Run with: check_ide-smart --nagios [-d] <DRIVE>
+ * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
+ *
+ * - Returns 0 on no errors
+ * - Returns 1 on advisories
+ * - Returns 2 on prefailure
+ * - Returns -1 not too often
+ */
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [-d <device>] [-v]", progname);
+}
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c
new file mode 100644
index 0000000..15113b1
--- /dev/null
+++ b/plugins/check_ldap.c
@@ -0,0 +1,517 @@
+/*****************************************************************************
+*
+* Monitoring check_ldap plugin
+*
+* License: GPL
+* Copyright (c) 2000-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ldap plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+/* progname may be check_ldaps */
+char *progname = "check_ldap";
+const char *copyright = "2000-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+#include <lber.h>
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+
+enum {
+ UNDEFINED = 0,
+#ifdef HAVE_LDAP_SET_OPTION
+ DEFAULT_PROTOCOL = 2,
+#endif
+ DEFAULT_PORT = 389
+};
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+char ld_defattr[] = "(objectclass=*)";
+char *ld_attr = ld_defattr;
+char *ld_host = NULL;
+char *ld_base = NULL;
+char *ld_passwd = NULL;
+char *ld_binddn = NULL;
+int ld_port = -1;
+#ifdef HAVE_LDAP_SET_OPTION
+int ld_protocol = DEFAULT_PROTOCOL;
+#endif
+#ifndef LDAP_OPT_SUCCESS
+# define LDAP_OPT_SUCCESS LDAP_SUCCESS
+#endif
+double warn_time = UNDEFINED;
+double crit_time = UNDEFINED;
+thresholds *entries_thresholds = NULL;
+struct timeval tv;
+char* warn_entries = NULL;
+char* crit_entries = NULL;
+int starttls = FALSE;
+int ssl_on_connect = FALSE;
+int verbose = 0;
+
+/* for ldap tls */
+
+char *SERVICE = "LDAP";
+
+int
+main (int argc, char *argv[])
+{
+
+ LDAP *ld;
+ LDAPMessage *result;
+
+ /* should be int result = STATE_UNKNOWN; */
+
+ int status = STATE_UNKNOWN;
+ long microsec;
+ double elapsed_time;
+
+ /* for ldap tls */
+
+ int tls;
+ int version=3;
+
+ int status_entries = STATE_OK;
+ int num_entries = 0;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ if (strstr(argv[0],"check_ldaps")) {
+ xasprintf (&progname, "check_ldaps");
+ }
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect)
+ starttls = TRUE;
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ /* get the start time */
+ gettimeofday (&tv, NULL);
+
+ /* initialize ldap */
+#ifdef HAVE_LDAP_INIT
+ if (!(ld = ldap_init (ld_host, ld_port))) {
+ printf ("Could not connect to the server at port %i\n", ld_port);
+ return STATE_CRITICAL;
+ }
+#else
+ if (!(ld = ldap_open (ld_host, ld_port))) {
+ if (verbose)
+ ldap_perror(ld, "ldap_open");
+ printf (_("Could not connect to the server at port %i\n"), ld_port);
+ return STATE_CRITICAL;
+ }
+#endif /* HAVE_LDAP_INIT */
+
+#ifdef HAVE_LDAP_SET_OPTION
+ /* set ldap options */
+ if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) !=
+ LDAP_OPT_SUCCESS ) {
+ printf(_("Could not set protocol version %d\n"), ld_protocol);
+ return STATE_CRITICAL;
+ }
+#endif
+
+ if (ld_port == LDAPS_PORT || ssl_on_connect) {
+ xasprintf (&SERVICE, "LDAPS");
+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
+ /* ldaps: set option tls */
+ tls = LDAP_OPT_X_TLS_HARD;
+
+ if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
+ {
+ if (verbose)
+ ldap_perror(ld, "ldaps_option");
+ printf (_("Could not init TLS at port %i!\n"), ld_port);
+ return STATE_CRITICAL;
+ }
+#else
+ printf (_("TLS not supported by the libraries!\n"));
+ return STATE_CRITICAL;
+#endif /* LDAP_OPT_X_TLS */
+ } else if (starttls) {
+ xasprintf (&SERVICE, "LDAP-TLS");
+#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
+ /* ldap with startTLS: set option version */
+ if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS )
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+ }
+ }
+ /* call start_tls */
+ if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS)
+ {
+ if (verbose)
+ ldap_perror(ld, "ldap_start_tls");
+ printf (_("Could not init startTLS at port %i!\n"), ld_port);
+ return STATE_CRITICAL;
+ }
+#else
+ printf (_("startTLS not supported by the library, needs LDAPv3!\n"));
+ return STATE_CRITICAL;
+#endif /* HAVE_LDAP_START_TLS_S */
+ }
+
+ /* bind to the ldap server */
+ if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) !=
+ LDAP_SUCCESS) {
+ if (verbose)
+ ldap_perror(ld, "ldap_bind");
+ printf (_("Could not bind to the LDAP server\n"));
+ return STATE_CRITICAL;
+ }
+
+ /* do a search of all objectclasses in the base dn */
+ if (ldap_search_s (ld, ld_base, (crit_entries!=NULL || warn_entries!=NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result)
+ != LDAP_SUCCESS) {
+ if (verbose)
+ ldap_perror(ld, "ldap_search");
+ printf (_("Could not search/find objectclasses in %s\n"), ld_base);
+ return STATE_CRITICAL;
+ } else if (crit_entries!=NULL || warn_entries!=NULL) {
+ num_entries = ldap_count_entries(ld, result);
+ }
+
+ /* unbind from the ldap server */
+ ldap_unbind (ld);
+
+ /* reset the alarm handler */
+ alarm (0);
+
+ /* calculate the elapsed time and compare to thresholds */
+
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ if (crit_time!=UNDEFINED && elapsed_time>crit_time)
+ status = STATE_CRITICAL;
+ else if (warn_time!=UNDEFINED && elapsed_time>warn_time)
+ status = STATE_WARNING;
+ else
+ status = STATE_OK;
+
+ if(entries_thresholds != NULL) {
+ if (verbose) {
+ printf ("entries found: %d\n", num_entries);
+ print_thresholds("entry thresholds", entries_thresholds);
+ }
+ status_entries = get_status(num_entries, entries_thresholds);
+ if (status_entries == STATE_CRITICAL) {
+ status = STATE_CRITICAL;
+ } else if (status != STATE_CRITICAL) {
+ status = status_entries;
+ }
+ }
+
+ /* print out the result */
+ if (crit_entries!=NULL || warn_entries!=NULL) {
+ printf (_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"),
+ state_text (status),
+ num_entries,
+ elapsed_time,
+ fperfdata ("time", elapsed_time, "s",
+ (int)warn_time, warn_time,
+ (int)crit_time, crit_time,
+ TRUE, 0, FALSE, 0),
+ sperfdata ("entries", (double)num_entries, "",
+ warn_entries,
+ crit_entries,
+ TRUE, 0.0, FALSE, 0.0));
+ } else {
+ printf (_("LDAP %s - %.3f seconds response time|%s\n"),
+ state_text (status),
+ elapsed_time,
+ fperfdata ("time", elapsed_time, "s",
+ (int)warn_time, warn_time,
+ (int)crit_time, crit_time,
+ TRUE, 0, FALSE, 0));
+ }
+
+ return status;
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ /* initialize the long option struct */
+ static struct option longopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {"base", required_argument, 0, 'b'},
+ {"attr", required_argument, 0, 'a'},
+ {"bind", required_argument, 0, 'D'},
+ {"pass", required_argument, 0, 'P'},
+#ifdef HAVE_LDAP_SET_OPTION
+ {"ver2", no_argument, 0, '2'},
+ {"ver3", no_argument, 0, '3'},
+#endif
+ {"starttls", no_argument, 0, 'T'},
+ {"ssl", no_argument, 0, 'S'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"port", required_argument, 0, 'p'},
+ {"warn", required_argument, 0, 'w'},
+ {"crit", required_argument, 0, 'c'},
+ {"warn-entries", required_argument, 0, 'W'},
+ {"crit-entries", required_argument, 0, 'C'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 't': /* timeout period */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ socket_timeout = atoi (optarg);
+ break;
+ case 'H':
+ ld_host = optarg;
+ break;
+ case 'b':
+ ld_base = optarg;
+ break;
+ case 'p':
+ ld_port = atoi (optarg);
+ break;
+ case 'a':
+ ld_attr = optarg;
+ break;
+ case 'D':
+ ld_binddn = optarg;
+ break;
+ case 'P':
+ ld_passwd = optarg;
+ break;
+ case 'w':
+ warn_time = strtod (optarg, NULL);
+ break;
+ case 'c':
+ crit_time = strtod (optarg, NULL);
+ break;
+ case 'W':
+ warn_entries = optarg;
+ break;
+ case 'C':
+ crit_entries = optarg;
+ break;
+#ifdef HAVE_LDAP_SET_OPTION
+ case '2':
+ ld_protocol = 2;
+ break;
+ case '3':
+ ld_protocol = 3;
+ break;
+#endif
+ case '4':
+ address_family = AF_INET;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'T':
+ if (! ssl_on_connect)
+ starttls = TRUE;
+ else
+ usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
+ break;
+ case 'S':
+ if (! starttls) {
+ ssl_on_connect = TRUE;
+ if (ld_port == -1)
+ ld_port = LDAPS_PORT;
+ } else
+ usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage (_("IPv6 support not available\n"));
+#endif
+ break;
+ default:
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (ld_host == NULL && is_host(argv[c]))
+ ld_host = strdup (argv[c++]);
+
+ if (ld_base == NULL && argv[c])
+ ld_base = strdup (argv[c++]);
+
+ if (ld_port == -1)
+ ld_port = DEFAULT_PORT;
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments ()
+{
+ if (ld_host==NULL || strlen(ld_host)==0)
+ usage4 (_("Please specify the host name\n"));
+
+ if (ld_base==NULL)
+ usage4 (_("Please specify the LDAP base\n"));
+
+ if (crit_entries!=NULL || warn_entries!=NULL) {
+ set_thresholds(&entries_thresholds,
+ warn_entries, crit_entries);
+ }
+ if (ld_passwd==NULL)
+ ld_passwd = getenv("LDAP_PASSWORD");
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", DEFAULT_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-a [--attr]");
+ printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
+ printf (" %s\n", "-b [--base]");
+ printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
+ printf (" %s\n", "-D [--bind]");
+ printf (" %s\n", _("ldap bind DN (if required)"));
+ printf (" %s\n", "-P [--pass]");
+ printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
+ printf (" %s\n", "-T [--starttls]");
+ printf (" %s\n", _("use starttls mechanism introduced in protocol version 3"));
+ printf (" %s\n", "-S [--ssl]");
+ printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
+
+#ifdef HAVE_LDAP_SET_OPTION
+ printf (" %s\n", "-2 [--ver2]");
+ printf (" %s\n", _("use ldap protocol version 2"));
+ printf (" %s\n", "-3 [--ver3]");
+ printf (" %s\n", _("use ldap protocol version 3"));
+ printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
+#endif
+
+ printf (UT_WARN_CRIT);
+
+ printf (" %s\n", "-W [--warn-entries]");
+ printf (" %s\n", _("Number of found entries to result in warning status"));
+ printf (" %s\n", "-C [--crit-entries]");
+ printf (" %s\n", _("Number of found entries to result in critical status"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
+ printf (_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
+ printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
+ printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
+ printf (" %s\n", _("to define the behaviour explicitly instead."));
+ printf (" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]",progname);
+ printf ("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
+#ifdef HAVE_LDAP_SET_OPTION
+ "\n [-2|-3] [-4|-6]"
+#else
+ ""
+#endif
+ );
+}
diff --git a/plugins/check_load.c b/plugins/check_load.c
new file mode 100644
index 0000000..313df8a
--- /dev/null
+++ b/plugins/check_load.c
@@ -0,0 +1,417 @@
+/*****************************************************************************
+*
+* Monitoring check_load plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_load plugin
+*
+* This plugin tests the current system load average.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_load";
+const char *copyright = "1999-2022";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "./common.h"
+#include "./runcmd.h"
+#include "./utils.h"
+#include "./popen.h"
+
+#include <string.h>
+
+#ifdef HAVE_SYS_LOADAVG_H
+#include <sys/loadavg.h>
+#endif
+
+/* needed for compilation under NetBSD, as suggested by Andy Doran */
+#ifndef LOADAVG_1MIN
+#define LOADAVG_1MIN 0
+#define LOADAVG_5MIN 1
+#define LOADAVG_15MIN 2
+#endif /* !defined LOADAVG_1MIN */
+
+
+static int process_arguments (int argc, char **argv);
+static int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+static int print_top_consuming_processes();
+
+static int n_procs_to_show = 0;
+
+/* strictly for pretty-print usage in loops */
+static const int nums[3] = { 1, 5, 15 };
+
+/* provide some fairly sane defaults */
+double wload[3] = { 0.0, 0.0, 0.0 };
+double cload[3] = { 0.0, 0.0, 0.0 };
+#define la1 la[0]
+#define la5 la[1]
+#define la15 la[2]
+
+char *status_line;
+bool take_into_account_cpus = false;
+
+static void
+get_threshold(char *arg, double *th)
+{
+ size_t i, n;
+ int valid = 0;
+ char *str = arg, *p;
+
+ n = strlen(arg);
+ for(i = 0; i < 3; i++) {
+ th[i] = strtod(str, &p);
+ if(p == str) break;
+
+ valid = 1;
+ str = p + 1;
+ if(n <= (size_t)(str - arg)) break;
+ }
+
+ /* empty argument or non-floatish, so warn about it and die */
+ if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n"));
+
+ if(i != 2) {
+ /* one or more numbers were given, so fill array with last
+ * we got (most likely to NOT produce the least expected result) */
+ for(n = i; n < 3; n++) th[n] = th[i];
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int result = -1;
+ int i;
+ long numcpus;
+
+ double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
+#ifndef HAVE_GETLOADAVG
+ char input_buffer[MAX_INPUT_BUFFER];
+# ifdef HAVE_PROC_LOADAVG
+ FILE *fp;
+ char *str, *next;
+# endif
+#endif
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ setlocale(LC_NUMERIC, "POSIX");
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+#ifdef HAVE_GETLOADAVG
+ result = getloadavg (la, 3);
+ if (result != 3)
+ return STATE_UNKNOWN;
+#else
+# ifdef HAVE_PROC_LOADAVG
+ fp = fopen (PROC_LOADAVG, "r");
+ if (fp == NULL) {
+ printf (_("Error opening %s\n"), PROC_LOADAVG);
+ return STATE_UNKNOWN;
+ }
+
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
+ str = (char *)input_buffer;
+ for(i = 0; i < 3; i++) {
+ la[i] = strtod(str, &next);
+ str = next;
+ }
+ }
+
+ fclose (fp);
+# else
+ child_process = spopen (PATH_TO_UPTIME);
+ if (child_process == NULL) {
+ printf (_("Error opening %s\n"), PATH_TO_UPTIME);
+ return STATE_UNKNOWN;
+ }
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL) {
+ printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME);
+ }
+ fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
+ if(strstr(input_buffer, "load average:")) {
+ sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
+ }
+ else if(strstr(input_buffer, "load averages:")) {
+ sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
+ }
+ else {
+ printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
+ return STATE_UNKNOWN;
+ }
+
+ result = spclose (child_process);
+ if (result) {
+ printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
+ return STATE_UNKNOWN;
+ }
+# endif
+#endif
+
+ if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
+#ifdef HAVE_GETLOADAVG
+ printf (_("Error in getloadavg()\n"));
+#else
+# ifdef HAVE_PROC_LOADAVG
+ printf (_("Error processing %s\n"), PROC_LOADAVG);
+# else
+ printf (_("Error processing %s\n"), PATH_TO_UPTIME);
+# endif
+#endif
+ return STATE_UNKNOWN;
+ }
+
+ /* we got this far, so assume OK until we've measured */
+ result = STATE_OK;
+
+ xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15);
+ xasprintf(&status_line, ("total %s"), status_line);
+
+
+ double scaled_la[3] = { 0.0, 0.0, 0.0 };
+ bool is_using_scaled_load_values = false;
+
+ if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) {
+ is_using_scaled_load_values = true;
+
+ scaled_la[0] = la[0] / numcpus;
+ scaled_la[1] = la[1] / numcpus;
+ scaled_la[2] = la[2] / numcpus;
+
+ char *tmp = NULL;
+ xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]);
+ xasprintf(&status_line, "scaled %s - %s", tmp, status_line);
+ }
+
+ for(i = 0; i < 3; i++) {
+ if (is_using_scaled_load_values) {
+ if(scaled_la[i] > cload[i]) {
+ result = STATE_CRITICAL;
+ break;
+ }
+ else if(scaled_la[i] > wload[i]) result = STATE_WARNING;
+ } else {
+ if(la[i] > cload[i]) {
+ result = STATE_CRITICAL;
+ break;
+ }
+ else if(la[i] > wload[i]) result = STATE_WARNING;
+ }
+ }
+
+ printf("LOAD %s - %s|", state_text(result), status_line);
+ for(i = 0; i < 3; i++) {
+ if (is_using_scaled_load_values) {
+ printf("load%d=%.3f;;;0; ", nums[i], la[i]);
+ printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]);
+ } else {
+ printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
+ }
+ }
+
+ putchar('\n');
+ if (n_procs_to_show > 0) {
+ print_top_consuming_processes();
+ }
+ return result;
+}
+
+
+/* process command-line arguments */
+static int
+process_arguments (int argc, char **argv)
+{
+ int c = 0;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"percpu", no_argument, 0, 'r'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"procs-to-show", required_argument, 0, 'n'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'w': /* warning time threshold */
+ get_threshold(optarg, wload);
+ break;
+ case 'c': /* critical time threshold */
+ get_threshold(optarg, cload);
+ break;
+ case 'r': /* Divide load average by number of CPUs */
+ take_into_account_cpus = true;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'n':
+ n_procs_to_show = atoi(optarg);
+ break;
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (c == argc)
+ return validate_arguments ();
+
+ /* handle the case if both arguments are missing,
+ * but not if only one is given without -c or -w flag */
+ if(c - argc == 2) {
+ get_threshold(argv[c++], wload);
+ get_threshold(argv[c++], cload);
+ }
+ else if(c - argc == 1) {
+ get_threshold(argv[c++], cload);
+ }
+
+ return validate_arguments ();
+}
+
+
+static int
+validate_arguments (void)
+{
+ int i = 0;
+
+ /* match cload first, as it will give the most friendly error message
+ * if user hasn't given the -c switch properly */
+ for(i = 0; i < 3; i++) {
+ if(cload[i] < 0)
+ die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
+ if(wload[i] < 0)
+ die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
+ if(wload[i] > cload[i])
+ die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
+ }
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin tests the current system load average."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
+ printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
+ printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
+ printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
+ printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
+ printf (" %s\n", "-r, --percpu");
+ printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
+ printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
+ printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
+ printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
+}
+
+#ifdef PS_USES_PROCPCPU
+int cmpstringp(const void *p1, const void *p2) {
+ int procuid = 0;
+ int procpid = 0;
+ int procppid = 0;
+ int procvsz = 0;
+ int procrss = 0;
+ float procpcpu = 0;
+ char procstat[8];
+#ifdef PS_USES_PROCETIME
+ char procetime[MAX_INPUT_BUFFER];
+#endif /* PS_USES_PROCETIME */
+ char procprog[MAX_INPUT_BUFFER];
+ int pos;
+ sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST);
+ float procpcpu1 = procpcpu;
+ sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST);
+ return procpcpu1 < procpcpu;
+}
+#endif /* PS_USES_PROCPCPU */
+
+static int print_top_consuming_processes() {
+ int i = 0;
+ struct output chld_out, chld_err;
+ if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){
+ fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
+ return STATE_UNKNOWN;
+ }
+ if (chld_out.lines < 2) {
+ fprintf(stderr, _("some error occurred getting procs list.\n"));
+ return STATE_UNKNOWN;
+ }
+#ifdef PS_USES_PROCPCPU
+ qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp);
+#endif /* PS_USES_PROCPCPU */
+ int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1)
+ ? (int)chld_out.lines : n_procs_to_show + 1;
+ for (i = 0; i < lines_to_show; i += 1) {
+ printf("%s\n", chld_out.line[i]);
+ }
+ return OK;
+}
diff --git a/plugins/check_mrtg.c b/plugins/check_mrtg.c
new file mode 100644
index 0000000..1fda549
--- /dev/null
+++ b/plugins/check_mrtg.c
@@ -0,0 +1,385 @@
+/*****************************************************************************
+*
+* Monitoring check_mrtg plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_mrtg plugin
+*
+* This plugin will check either the average or maximum value of one of the
+* two variables recorded in an MRTG log file.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_mrtg";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+char *log_file = NULL;
+int expire_minutes = 0;
+int use_average = TRUE;
+int variable_number = -1;
+unsigned long value_warning_threshold = 0L;
+unsigned long value_critical_threshold = 0L;
+char *label;
+char *units;
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_OK;
+ FILE *fp;
+ int line;
+ char input_buffer[MAX_INPUT_BUFFER];
+ char *temp_buffer;
+ time_t current_time;
+ time_t timestamp = 0L;
+ unsigned long average_value_rate = 0L;
+ unsigned long maximum_value_rate = 0L;
+ unsigned long rate = 0L;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments\n"));
+
+ /* open the MRTG log file for reading */
+ fp = fopen (log_file, "r");
+ if (fp == NULL) {
+ printf (_("Unable to open MRTG log file\n"));
+ return STATE_UNKNOWN;
+ }
+
+ line = 0;
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
+
+ line++;
+
+ /* skip the first line of the log file */
+ if (line == 1)
+ continue;
+
+ /* break out of read loop if we've passed the number of entries we want to read */
+ if (line > 2)
+ break;
+
+ /* grab the timestamp */
+ temp_buffer = strtok (input_buffer, " ");
+ timestamp = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the average value 1 rate */
+ temp_buffer = strtok (NULL, " ");
+ if (variable_number == 1)
+ average_value_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the average value 2 rate */
+ temp_buffer = strtok (NULL, " ");
+ if (variable_number == 2)
+ average_value_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the maximum value 1 rate */
+ temp_buffer = strtok (NULL, " ");
+ if (variable_number == 1)
+ maximum_value_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the maximum value 2 rate */
+ temp_buffer = strtok (NULL, " ");
+ if (variable_number == 2)
+ maximum_value_rate = strtoul (temp_buffer, NULL, 10);
+ }
+
+ /* close the log file */
+ fclose (fp);
+
+ /* if we couldn't read enough data, return an unknown error */
+ if (line <= 2) {
+ printf (_("Unable to process MRTG log file\n"));
+ return STATE_UNKNOWN;
+ }
+
+ /* make sure the MRTG data isn't too old */
+ time (&current_time);
+ if (expire_minutes > 0
+ && (current_time - timestamp) > (expire_minutes * 60)) {
+ printf (_("MRTG data has expired (%d minutes old)\n"),
+ (int) ((current_time - timestamp) / 60));
+ return STATE_WARNING;
+ }
+
+ /* else check the incoming/outgoing rates */
+ if (use_average == TRUE)
+ rate = average_value_rate;
+ else
+ rate = maximum_value_rate;
+
+ if (rate > value_critical_threshold)
+ result = STATE_CRITICAL;
+ else if (rate > value_warning_threshold)
+ result = STATE_WARNING;
+
+ printf("%s. %s = %lu %s|%s\n",
+ (use_average == TRUE) ? _("Avg") : _("Max"),
+ label, rate, units,
+ perfdata(label, (long) rate, units,
+ (int) value_warning_threshold, (long) value_warning_threshold,
+ (int) value_critical_threshold, (long) value_critical_threshold,
+ 0, 0, 0, 0));
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"logfile", required_argument, 0, 'F'},
+ {"expires", required_argument, 0, 'e'},
+ {"aggregation", required_argument, 0, 'a'},
+ {"variable", required_argument, 0, 'v'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"label", required_argument, 0, 'l'},
+ {"units", required_argument, 0, 'u'},
+ {"variable", required_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'F': /* input file */
+ log_file = optarg;
+ break;
+ case 'e': /* ups name */
+ expire_minutes = atoi (optarg);
+ break;
+ case 'a': /* port */
+ if (!strcmp (optarg, "MAX"))
+ use_average = FALSE;
+ else
+ use_average = TRUE;
+ break;
+ case 'v':
+ variable_number = atoi (optarg);
+ if (variable_number < 1 || variable_number > 2)
+ usage4 (_("Invalid variable number"));
+ break;
+ case 'w': /* critical time threshold */
+ value_warning_threshold = strtoul (optarg, NULL, 10);
+ break;
+ case 'c': /* warning time threshold */
+ value_critical_threshold = strtoul (optarg, NULL, 10);
+ break;
+ case 'l': /* label */
+ label = optarg;
+ break;
+ case 'u': /* timeout */
+ units = optarg;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (log_file == NULL && argc > c) {
+ log_file = argv[c++];
+ }
+
+ if (expire_minutes <= 0 && argc > c) {
+ if (is_intpos (argv[c]))
+ expire_minutes = atoi (argv[c++]);
+ else
+ die (STATE_UNKNOWN,
+ _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"),
+ argv[c], progname);
+ }
+
+ if (argc > c && strcmp (argv[c], "MAX") == 0) {
+ use_average = FALSE;
+ c++;
+ }
+ else if (argc > c && strcmp (argv[c], "AVG") == 0) {
+ use_average = TRUE;
+ c++;
+ }
+
+ if (argc > c && variable_number == -1) {
+ variable_number = atoi (argv[c++]);
+ if (variable_number < 1 || variable_number > 2) {
+ printf ("%s :", argv[c]);
+ usage (_("Invalid variable number\n"));
+ }
+ }
+
+ if (argc > c && value_warning_threshold == 0) {
+ value_warning_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ if (argc > c && value_critical_threshold == 0) {
+ value_critical_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ if (argc > c && strlen (label) == 0) {
+ label = argv[c++];
+ }
+
+ if (argc > c && strlen (units) == 0) {
+ units = argv[c++];
+ }
+
+ return validate_arguments ();
+}
+
+int
+validate_arguments (void)
+{
+ if (variable_number == -1)
+ usage4 (_("You must supply the variable number"));
+
+ if (label == NULL)
+ label = strdup ("value");
+
+ if (units == NULL)
+ units = strdup ("");
+
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin will check either the average or maximum value of one of the"));
+ printf ("%s\n", _("two variables recorded in an MRTG log file."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-F, --logfile=FILE");
+ printf (" %s\n", _("The MRTG log file containing the data you want to monitor"));
+ printf (" %s\n", "-e, --expires=MINUTES");
+ printf (" %s\n", _("Minutes before MRTG data is considered to be too old"));
+ printf (" %s\n", "-a, --aggregation=AVG|MAX");
+ printf (" %s\n", _("Should we check average or maximum values?"));
+ printf (" %s\n", "-v, --variable=INTEGER");
+ printf (" %s\n", _("Which variable set should we inspect? (1 or 2)"));
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Threshold value for data to result in WARNING status"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Threshold value for data to result in CRITICAL status"));
+ printf (" %s\n", "-l, --label=STRING");
+ printf (" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)"));
+ printf (" %s\n", "-u, --units=STRING");
+ printf (" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,"));
+ printf (" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")"));
+
+ printf ("\n");
+ printf (" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If"));
+ printf (" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If"));
+ printf (" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING"));
+ printf (" %s\n", _("status is returned and a warning message is printed."));
+
+ printf ("\n");
+ printf (" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to"));
+ printf (" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
+ printf (" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
+ printf (" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows"));
+ printf (" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
+ printf (" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
+
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log"));
+ printf (" %s\n", _("file. If you want to monitor both values you will have to define two"));
+ printf (" %s\n", _("commands with different values for the <variable> argument. Of course,"));
+ printf (" %s\n", _("you can always hack the code to make this plugin work for you..."));
+ printf (" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
+ printf (" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
+
+ printf (UT_SUPPORT);
+}
+
+
+
+/* original command line:
+ <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n",progname);
+ printf ("[-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]\n");
+}
diff --git a/plugins/check_mrtgtraf.c b/plugins/check_mrtgtraf.c
new file mode 100644
index 0000000..eb66f62
--- /dev/null
+++ b/plugins/check_mrtgtraf.c
@@ -0,0 +1,381 @@
+/*****************************************************************************
+*
+* Monitoring check_mrtgtraf plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_mtrgtraf plugin
+*
+* This plugin will check the incoming/outgoing transfer rates of a router
+* switch, etc recorded in an MRTG log.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#include "common.h"
+#include "utils.h"
+
+const char *progname = "check_mrtgtraf";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help(void);
+void print_usage(void);
+
+char *log_file = NULL;
+int expire_minutes = -1;
+int use_average = TRUE;
+unsigned long incoming_warning_threshold = 0L;
+unsigned long incoming_critical_threshold = 0L;
+unsigned long outgoing_warning_threshold = 0L;
+unsigned long outgoing_critical_threshold = 0L;
+
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_OK;
+ FILE *fp;
+ int line;
+ char input_buffer[MAX_INPUT_BUFFER];
+ char *temp_buffer;
+ time_t current_time;
+ char *error_message;
+ time_t timestamp = 0L;
+ unsigned long average_incoming_rate = 0L;
+ unsigned long average_outgoing_rate = 0L;
+ unsigned long maximum_incoming_rate = 0L;
+ unsigned long maximum_outgoing_rate = 0L;
+ unsigned long incoming_rate = 0L;
+ unsigned long outgoing_rate = 0L;
+ double adjusted_incoming_rate = 0.0;
+ double adjusted_outgoing_rate = 0.0;
+ char incoming_speed_rating[8];
+ char outgoing_speed_rating[8];
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* open the MRTG log file for reading */
+ fp = fopen (log_file, "r");
+ if (fp == NULL)
+ usage4 (_("Unable to open MRTG log file"));
+
+ line = 0;
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
+
+ line++;
+
+ /* skip the first line of the log file */
+ if (line == 1)
+ continue;
+
+ /* break out of read loop */
+ /* if we've passed the number of entries we want to read */
+ if (line > 2)
+ break;
+
+ /* grab the timestamp */
+ temp_buffer = strtok (input_buffer, " ");
+ timestamp = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the average incoming transfer rate */
+ temp_buffer = strtok (NULL, " ");
+ average_incoming_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the average outgoing transfer rate */
+ temp_buffer = strtok (NULL, " ");
+ average_outgoing_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the maximum incoming transfer rate */
+ temp_buffer = strtok (NULL, " ");
+ maximum_incoming_rate = strtoul (temp_buffer, NULL, 10);
+
+ /* grab the maximum outgoing transfer rate */
+ temp_buffer = strtok (NULL, " ");
+ maximum_outgoing_rate = strtoul (temp_buffer, NULL, 10);
+ }
+
+ /* close the log file */
+ fclose (fp);
+
+ /* if we couldn't read enough data, return an unknown error */
+ if (line <= 2)
+ usage4 (_("Unable to process MRTG log file"));
+
+ /* make sure the MRTG data isn't too old */
+ time (&current_time);
+ if ((expire_minutes > 0) &&
+ (current_time - timestamp) > (expire_minutes * 60))
+ die (STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"),
+ (int) ((current_time - timestamp) / 60));
+
+ /* else check the incoming/outgoing rates */
+ if (use_average == TRUE) {
+ incoming_rate = average_incoming_rate;
+ outgoing_rate = average_outgoing_rate;
+ }
+ else {
+ incoming_rate = maximum_incoming_rate;
+ outgoing_rate = maximum_outgoing_rate;
+ }
+
+ /* report incoming traffic in Bytes/sec */
+ if (incoming_rate < 1024) {
+ strcpy (incoming_speed_rating, "B");
+ adjusted_incoming_rate = (double) incoming_rate;
+ }
+
+ /* report incoming traffic in KBytes/sec */
+ else if (incoming_rate < (1024 * 1024)) {
+ strcpy (incoming_speed_rating, "KB");
+ adjusted_incoming_rate = (double) (incoming_rate / 1024.0);
+ }
+
+ /* report incoming traffic in MBytes/sec */
+ else {
+ strcpy (incoming_speed_rating, "MB");
+ adjusted_incoming_rate = (double) (incoming_rate / 1024.0 / 1024.0);
+ }
+
+ /* report outgoing traffic in Bytes/sec */
+ if (outgoing_rate < 1024) {
+ strcpy (outgoing_speed_rating, "B");
+ adjusted_outgoing_rate = (double) outgoing_rate;
+ }
+
+ /* report outgoing traffic in KBytes/sec */
+ else if (outgoing_rate < (1024 * 1024)) {
+ strcpy (outgoing_speed_rating, "KB");
+ adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0);
+ }
+
+ /* report outgoing traffic in MBytes/sec */
+ else {
+ strcpy (outgoing_speed_rating, "MB");
+ adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0 / 1024.0);
+ }
+
+ if (incoming_rate > incoming_critical_threshold
+ || outgoing_rate > outgoing_critical_threshold) {
+ result = STATE_CRITICAL;
+ }
+ else if (incoming_rate > incoming_warning_threshold
+ || outgoing_rate > outgoing_warning_threshold) {
+ result = STATE_WARNING;
+ }
+
+ xasprintf (&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"),
+ (use_average == TRUE) ? _("Avg") : _("Max"), adjusted_incoming_rate,
+ incoming_speed_rating, (use_average == TRUE) ? _("Avg") : _("Max"),
+ adjusted_outgoing_rate, outgoing_speed_rating,
+ fperfdata("in", adjusted_incoming_rate, incoming_speed_rating,
+ (int)incoming_warning_threshold, incoming_warning_threshold,
+ (int)incoming_critical_threshold, incoming_critical_threshold,
+ TRUE, 0, FALSE, 0),
+ fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating,
+ (int)outgoing_warning_threshold, outgoing_warning_threshold,
+ (int)outgoing_critical_threshold, outgoing_critical_threshold,
+ TRUE, 0, FALSE, 0));
+
+ printf (_("Traffic %s - %s\n"), state_text(result), error_message);
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"filename", required_argument, 0, 'F'},
+ {"expires", required_argument, 0, 'e'},
+ {"aggregation", required_argument, 0, 'a'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVF:e:a:c:w:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'F': /* input file */
+ log_file = optarg;
+ break;
+ case 'e': /* expiration time */
+ expire_minutes = atoi (optarg);
+ break;
+ case 'a': /* aggregation (AVE or MAX) */
+ if (!strcmp (optarg, "MAX"))
+ use_average = FALSE;
+ else
+ use_average = TRUE;
+ break;
+ case 'c': /* warning threshold */
+ sscanf (optarg, "%lu,%lu", &incoming_critical_threshold,
+ &outgoing_critical_threshold);
+ break;
+ case 'w': /* critical threshold */
+ sscanf (optarg, "%lu,%lu", &incoming_warning_threshold,
+ &outgoing_warning_threshold);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (argc > c && log_file == NULL) {
+ log_file = argv[c++];
+ }
+
+ if (argc > c && expire_minutes == -1) {
+ expire_minutes = atoi (argv[c++]);
+ }
+
+ if (argc > c && strcmp (argv[c], "MAX") == 0) {
+ use_average = FALSE;
+ c++;
+ }
+ else if (argc > c && strcmp (argv[c], "AVG") == 0) {
+ use_average = TRUE;
+ c++;
+ }
+
+ if (argc > c && incoming_warning_threshold == 0) {
+ incoming_warning_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ if (argc > c && incoming_critical_threshold == 0) {
+ incoming_critical_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ if (argc > c && outgoing_warning_threshold == 0) {
+ outgoing_warning_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ if (argc > c && outgoing_critical_threshold == 0) {
+ outgoing_critical_threshold = strtoul (argv[c++], NULL, 10);
+ }
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments (void)
+{
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,"));
+ printf ("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older"));
+ printf ("%s\n", _("than <expire_minutes>, a WARNING status is returned. If either the"));
+ printf ("%s\n", _("incoming or outgoing rates exceed the <icl> or <ocl> thresholds (in"));
+ printf ("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed"));
+ printf ("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-F, --filename=STRING");
+ printf (" %s\n", _("File to read log from"));
+ printf (" %s\n", "-e, --expires=INTEGER");
+ printf (" %s\n", _("Minutes after which log expires"));
+ printf (" %s\n", "-a, --aggregation=(AVG|MAX)");
+ printf (" %s\n", _("Test average or maximum"));
+ printf (" %s\n", "-w, --warning");
+ printf (" %s\n", _("Warning threshold pair <incoming>,<outgoing>"));
+ printf (" %s\n", "-c, --critical");
+ printf (" %s\n", _("Critical threshold pair <incoming>,<outgoing>"));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from"));
+ printf (" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
+ printf (" %s\n", _("- While MRTG can monitor things other than traffic rates, this"));
+ printf (" %s\n", _(" plugin probably won't work with much else without modification."));
+ printf (" %s\n", _("- The calculated i/o rates are a little off from what MRTG actually"));
+ printf (" %s\n", _(" reports. I'm not sure why this is right now, but will look into it"));
+ printf (" %s\n", _(" for future enhancements of this plugin."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf (_("Usage"));
+ printf (" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n",progname);
+ printf ("-c <critical_pair> [-e expire_minutes]\n");
+}
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
new file mode 100644
index 0000000..7d85554
--- /dev/null
+++ b/plugins/check_mysql.c
@@ -0,0 +1,612 @@
+/*****************************************************************************
+*
+* Monitoring check_mysql plugin
+*
+* License: GPL
+* Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)
+* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
+* Copyright (c) 1999-2011 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_mysql plugin
+*
+* This program tests connections to a mysql server
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_mysql";
+const char *copyright = "1999-2011";
+const char *email = "devel@monitoring-plugins.org";
+
+#define SLAVERESULTSIZE 96
+
+#include "common.h"
+#include "utils.h"
+#include "utils_base.h"
+#include "netutils.h"
+
+#include <mysql.h>
+#include <mysqld_error.h>
+#include <errmsg.h>
+
+char *db_user = NULL;
+char *db_host = NULL;
+char *db_socket = NULL;
+char *db_pass = NULL;
+char *db = NULL;
+char *ca_cert = NULL;
+char *ca_dir = NULL;
+char *cert = NULL;
+char *key = NULL;
+char *ciphers = NULL;
+bool ssl = false;
+char *opt_file = NULL;
+char *opt_group = NULL;
+unsigned int db_port = MYSQL_PORT;
+int check_slave = 0, warn_sec = 0, crit_sec = 0;
+int ignore_auth = 0;
+int verbose = 0;
+
+static double warning_time = 0;
+static double critical_time = 0;
+
+#define LENGTH_METRIC_UNIT 6
+static const char *metric_unit[LENGTH_METRIC_UNIT] = {
+ "Open_files",
+ "Open_tables",
+ "Qcache_free_memory",
+ "Qcache_queries_in_cache",
+ "Threads_connected",
+ "Threads_running"
+};
+
+#define LENGTH_METRIC_COUNTER 9
+static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
+ "Connections",
+ "Qcache_hits",
+ "Qcache_inserts",
+ "Qcache_lowmem_prunes",
+ "Qcache_not_cached",
+ "Queries",
+ "Questions",
+ "Table_locks_waited",
+ "Uptime"
+};
+
+#define MYSQLDUMP_THREADS_QUERY "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
+
+thresholds *my_threshold = NULL;
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+int
+main (int argc, char **argv)
+{
+
+ MYSQL mysql;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ /* should be status */
+
+ char *result = NULL;
+ char *error = NULL;
+ char slaveresult[SLAVERESULTSIZE] = { 0 };
+ char* perf;
+
+ perf = strdup ("");
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize mysql */
+ mysql_init (&mysql);
+
+ if (opt_file != NULL)
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file);
+
+ if (opt_group != NULL)
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group);
+ else
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");
+
+ if (ssl)
+ mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers);
+ /* establish a connection to the server and error checking */
+ if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) {
+ /* Depending on internally-selected auth plugin MySQL might return */
+ /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
+ /* Semantically these errors are the same. */
+ if (ignore_auth && (mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno (&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR))
+ {
+ printf("MySQL OK - Version: %s (protocol %d)\n",
+ mysql_get_server_info(&mysql),
+ mysql_get_proto_info(&mysql)
+ );
+ mysql_close (&mysql);
+ return STATE_OK;
+ }
+ else if (mysql_errno (&mysql) == CR_UNKNOWN_HOST)
+ die (STATE_WARNING, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_VERSION_ERROR)
+ die (STATE_WARNING, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY)
+ die (STATE_WARNING, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR)
+ die (STATE_WARNING, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR)
+ die (STATE_WARNING, "%s\n", mysql_error (&mysql));
+ else
+ die (STATE_CRITICAL, "%s\n", mysql_error (&mysql));
+ }
+
+ /* get the server stats */
+ result = strdup (mysql_stat (&mysql));
+
+ /* error checking once more */
+ if (mysql_error (&mysql)) {
+ if (mysql_errno (&mysql) == CR_SERVER_GONE_ERROR)
+ die (STATE_CRITICAL, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_SERVER_LOST)
+ die (STATE_CRITICAL, "%s\n", mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_UNKNOWN_ERROR)
+ die (STATE_CRITICAL, "%s\n", mysql_error (&mysql));
+ }
+
+ /* try to fetch some perf data */
+ if (mysql_query (&mysql, "show global status") == 0) {
+ if ( (res = mysql_store_result (&mysql)) == NULL) {
+ error = strdup(mysql_error(&mysql));
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, _("status store_result error: %s\n"), error);
+ }
+
+ while ( (row = mysql_fetch_row (res)) != NULL) {
+ int i;
+
+ for(i = 0; i < LENGTH_METRIC_UNIT; i++) {
+ if (strcmp(row[0], metric_unit[i]) == 0) {
+ xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i],
+ atol(row[1]), "", FALSE, 0, FALSE, 0, FALSE, 0, FALSE, 0));
+ continue;
+ }
+ }
+ for(i = 0; i < LENGTH_METRIC_COUNTER; i++) {
+ if (strcmp(row[0], metric_counter[i]) == 0) {
+ xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i],
+ atol(row[1]), "c", FALSE, 0, FALSE, 0, FALSE, 0, FALSE, 0));
+ continue;
+ }
+ }
+ }
+ /* remove trailing space */
+ if (strlen(perf) > 0)
+ perf[strlen(perf) - 1] = '\0';
+ }
+
+ if(check_slave) {
+ /* check the slave status */
+ if (mysql_query (&mysql, "show slave status") != 0) {
+ error = strdup(mysql_error(&mysql));
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, _("slave query error: %s\n"), error);
+ }
+
+ /* store the result */
+ if ( (res = mysql_store_result (&mysql)) == NULL) {
+ error = strdup(mysql_error(&mysql));
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, _("slave store_result error: %s\n"), error);
+ }
+
+ /* Check there is some data */
+ if (mysql_num_rows(res) == 0) {
+ mysql_close(&mysql);
+ die (STATE_WARNING, "%s\n", _("No slaves defined"));
+ }
+
+ /* fetch the first row */
+ if ( (row = mysql_fetch_row (res)) == NULL) {
+ error = strdup(mysql_error(&mysql));
+ mysql_free_result (res);
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, _("slave fetch row error: %s\n"), error);
+ }
+
+ if (mysql_field_count (&mysql) == 12) {
+ /* mysql 3.23.x */
+ snprintf (slaveresult, SLAVERESULTSIZE, _("Slave running: %s"), row[6]);
+ if (strcmp (row[6], "Yes") != 0) {
+ mysql_free_result (res);
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, "%s\n", slaveresult);
+ }
+
+ } else {
+ /* mysql 4.x.x and mysql 5.x.x */
+ int slave_io_field = -1 , slave_sql_field = -1, seconds_behind_field = -1, i, num_fields;
+ MYSQL_FIELD* fields;
+
+ num_fields = mysql_num_fields(res);
+ fields = mysql_fetch_fields(res);
+ for(i = 0; i < num_fields; i++) {
+ if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
+ slave_io_field = i;
+ continue;
+ }
+ if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
+ slave_sql_field = i;
+ continue;
+ }
+ if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) {
+ seconds_behind_field = i;
+ continue;
+ }
+ }
+
+ /* Check if slave status is available */
+ if ((slave_io_field < 0) || (slave_sql_field < 0) || (num_fields == 0)) {
+ mysql_free_result (res);
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, "Slave status unavailable\n");
+ }
+
+ /* Save slave status in slaveresult */
+ snprintf (slaveresult, SLAVERESULTSIZE, "Slave IO: %s Slave SQL: %s Seconds Behind Master: %s", row[slave_io_field], row[slave_sql_field], seconds_behind_field!=-1?row[seconds_behind_field]:"Unknown");
+
+ /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */
+ if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) {
+ MYSQL_RES *res_mysqldump;
+ MYSQL_ROW row_mysqldump;
+ unsigned int mysqldump_threads = 0;
+
+ if (mysql_query (&mysql, MYSQLDUMP_THREADS_QUERY) == 0) {
+ /* store the result */
+ if ( (res_mysqldump = mysql_store_result (&mysql)) != NULL) {
+ if (mysql_num_rows(res_mysqldump) == 1) {
+ if ( (row_mysqldump = mysql_fetch_row (res_mysqldump)) != NULL) {
+ mysqldump_threads = atoi(row_mysqldump[0]);
+ }
+ }
+ /* free the result */
+ mysql_free_result (res_mysqldump);
+ }
+ mysql_close (&mysql);
+ }
+ if (mysqldump_threads == 0) {
+ die (STATE_CRITICAL, "%s\n", slaveresult);
+ } else {
+ strncat(slaveresult, " Mysqldump: in progress", SLAVERESULTSIZE-1);
+ }
+ }
+
+ if (verbose >=3) {
+ if (seconds_behind_field == -1) {
+ printf("seconds_behind_field not found\n");
+ } else {
+ printf ("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]);
+ }
+ }
+
+ /* Check Seconds Behind against threshold */
+ if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp (row[seconds_behind_field], "NULL") != 0)) {
+ double value = atof(row[seconds_behind_field]);
+ int status;
+
+ status = get_status(value, my_threshold);
+
+ xasprintf (&perf, "%s %s", perf, fperfdata ("seconds behind master", value, "s",
+ TRUE, (double) warning_time,
+ TRUE, (double) critical_time,
+ FALSE, 0,
+ FALSE, 0));
+
+ if (status == STATE_WARNING) {
+ printf("SLOW_SLAVE %s: %s|%s\n", _("WARNING"), slaveresult, perf);
+ exit(STATE_WARNING);
+ } else if (status == STATE_CRITICAL) {
+ printf("SLOW_SLAVE %s: %s|%s\n", _("CRITICAL"), slaveresult, perf);
+ exit(STATE_CRITICAL);
+ }
+ }
+ }
+
+ /* free the result */
+ mysql_free_result (res);
+ }
+
+ /* close the connection */
+ mysql_close (&mysql);
+
+ /* print out the result of stats */
+ if (check_slave) {
+ printf ("%s %s|%s\n", result, slaveresult, perf);
+ } else {
+ printf ("%s|%s\n", result, perf);
+ }
+
+ return STATE_OK;
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char *warning = NULL;
+ char *critical = NULL;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"socket", required_argument, 0, 's'},
+ {"database", required_argument, 0, 'd'},
+ {"username", required_argument, 0, 'u'},
+ {"password", required_argument, 0, 'p'},
+ {"file", required_argument, 0, 'f'},
+ {"group", required_argument, 0, 'g'},
+ {"port", required_argument, 0, 'P'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"check-slave", no_argument, 0, 'S'},
+ {"ignore-auth", no_argument, 0, 'n'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"ssl", no_argument, 0, 'l'},
+ {"ca-cert", optional_argument, 0, 'C'},
+ {"key", required_argument,0,'k'},
+ {"cert", required_argument,0,'a'},
+ {"ca-dir", required_argument, 0, 'D'},
+ {"ciphers", required_argument, 0, 'L'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 1)
+ return ERROR;
+
+ while (1) {
+ c = getopt_long (argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'H': /* hostname */
+ if (is_host (optarg)) {
+ db_host = optarg;
+ }
+ else if (*optarg == '/') {
+ db_socket = optarg;
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ break;
+ case 's': /* socket */
+ db_socket = optarg;
+ break;
+ case 'd': /* database */
+ db = optarg;
+ break;
+ case 'l':
+ ssl = true;
+ break;
+ case 'C':
+ ca_cert = optarg;
+ break;
+ case 'a':
+ cert = optarg;
+ break;
+ case 'k':
+ key = optarg;
+ break;
+ case 'D':
+ ca_dir = optarg;
+ break;
+ case 'L':
+ ciphers = optarg;
+ break;
+ case 'u': /* username */
+ db_user = optarg;
+ break;
+ case 'p': /* authentication information: password */
+ db_pass = strdup(optarg);
+
+ /* Delete the password from process list */
+ while (*optarg != '\0') {
+ *optarg = 'X';
+ optarg++;
+ }
+ break;
+ case 'f': /* client options file */
+ opt_file = optarg;
+ break;
+ case 'g': /* client options group */
+ opt_group = optarg;
+ break;
+ case 'P': /* critical time threshold */
+ db_port = atoi (optarg);
+ break;
+ case 'S':
+ check_slave = 1; /* check-slave */
+ break;
+ case 'n':
+ ignore_auth = 1; /* ignore-auth */
+ break;
+ case 'w':
+ warning = optarg;
+ warning_time = strtod (warning, NULL);
+ break;
+ case 'c':
+ critical = optarg;
+ critical_time = strtod (critical, NULL);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'v':
+ verbose++;
+ break;
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+
+ set_thresholds(&my_threshold, warning, critical);
+
+ while ( argc > c ) {
+
+ if (db_host == NULL)
+ if (is_host (argv[c])) {
+ db_host = argv[c++];
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), argv[c]);
+ }
+ else if (db_user == NULL)
+ db_user = argv[c++];
+ else if (db_pass == NULL)
+ db_pass = argv[c++];
+ else if (db == NULL)
+ db = argv[c++];
+ else if (is_intnonneg (argv[c]))
+ db_port = atoi (argv[c++]);
+ else
+ break;
+ }
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments (void)
+{
+ if (db_user == NULL)
+ db_user = strdup("");
+
+ if (db_host == NULL)
+ db_host = strdup("");
+
+ if (db == NULL)
+ db = strdup("");
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", MYSQL_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf (_(COPYRIGHT), copyright, email);
+
+ printf ("%s\n", _("This program tests connections to a MySQL server"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'P', myport);
+ printf (" %s\n", "-n, --ignore-auth");
+ printf (" %s\n", _("Ignore authentication failure and check for mysql connectivity only"));
+
+ printf (" %s\n", "-s, --socket=STRING");
+ printf (" %s\n", _("Use the specified socket (has no effect if -H is used)"));
+
+ printf (" %s\n", "-d, --database=STRING");
+ printf (" %s\n", _("Check database with indicated name"));
+ printf (" %s\n", "-f, --file=STRING");
+ printf (" %s\n", _("Read from the specified client options file"));
+ printf (" %s\n", "-g, --group=STRING");
+ printf (" %s\n", _("Use a client options group"));
+ printf (" %s\n", "-u, --username=STRING");
+ printf (" %s\n", _("Connect using the indicated username"));
+ printf (" %s\n", "-p, --password=STRING");
+ printf (" %s\n", _("Use the indicated password to authenticate the connection"));
+ printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
+ printf (" %s\n", _("Your clear-text password could be visible as a process table entry"));
+ printf (" %s\n", "-S, --check-slave");
+ printf (" %s\n", _("Check if the slave thread is running properly."));
+ printf (" %s\n", "-w, --warning");
+ printf (" %s\n", _("Exit with WARNING status if slave server is more than INTEGER seconds"));
+ printf (" %s\n", _("behind master"));
+ printf (" %s\n", "-c, --critical");
+ printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds"));
+ printf (" %s\n", _("behind master"));
+ printf (" %s\n", "-l, --ssl");
+ printf (" %s\n", _("Use ssl encryption"));
+ printf (" %s\n", "-C, --ca-cert=STRING");
+ printf (" %s\n", _("Path to CA signing the cert"));
+ printf (" %s\n", "-a, --cert=STRING");
+ printf (" %s\n", _("Path to SSL certificate"));
+ printf (" %s\n", "-k, --key=STRING");
+ printf (" %s\n", _("Path to private SSL key"));
+ printf (" %s\n", "-D, --ca-dir=STRING");
+ printf (" %s\n", _("Path to CA directory"));
+ printf (" %s\n", "-L, --ciphers=STRING");
+ printf (" %s\n", _("List of valid SSL ciphers"));
+
+
+ printf ("\n");
+ printf (" %s\n", _("There are no required arguments. By default, the local database is checked"));
+ printf (" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
+ printf (" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("You must specify -p with an empty string to force an empty password,"));
+ printf (" %s\n", _("overriding any my.cnf settings."));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s [-d database] [-H host] [-P port] [-s socket]\n",progname);
+ printf (" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
+ printf (" [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group]\n");
+}
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
new file mode 100644
index 0000000..ac2fb15
--- /dev/null
+++ b/plugins/check_mysql_query.c
@@ -0,0 +1,354 @@
+/*****************************************************************************
+*
+* Monitoring check_mysql_query plugin
+*
+* License: GPL
+* Copyright (c) 2006-2009 Monitoring Plugins Development Team
+* Original code from check_mysql, copyright 1999 Didi Rieder
+*
+* Description:
+*
+* This file contains the check_mysql_query plugin
+*
+* This plugin is for running arbitrary SQL and checking the results
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_mysql_query";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_base.h"
+#include "netutils.h"
+
+#include <mysql.h>
+#include <errmsg.h>
+
+char *db_user = NULL;
+char *db_host = NULL;
+char *db_socket = NULL;
+char *db_pass = NULL;
+char *db = NULL;
+char *opt_file = NULL;
+char *opt_group = NULL;
+unsigned int db_port = MYSQL_PORT;
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+char *sql_query = NULL;
+int verbose = 0;
+thresholds *my_thresholds = NULL;
+
+
+int
+main (int argc, char **argv)
+{
+
+ MYSQL mysql;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ double value;
+ char *error = NULL;
+ int status;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize mysql */
+ mysql_init (&mysql);
+
+ if (opt_file != NULL)
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file);
+
+ if (opt_group != NULL)
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group);
+ else
+ mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");
+
+ /* establish a connection to the server and error checking */
+ if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) {
+ if (mysql_errno (&mysql) == CR_UNKNOWN_HOST)
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_VERSION_ERROR)
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY)
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR)
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
+ else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR)
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
+ else
+ die (STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error (&mysql));
+ }
+
+ if (mysql_query (&mysql, sql_query) != 0) {
+ error = strdup(mysql_error(&mysql));
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
+ }
+
+ /* store the result */
+ if ( (res = mysql_store_result (&mysql)) == NULL) {
+ error = strdup(mysql_error(&mysql));
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
+ }
+
+ /* Check there is some data */
+ if (mysql_num_rows(res) == 0) {
+ mysql_close(&mysql);
+ die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
+ }
+
+ /* fetch the first row */
+ if ( (row = mysql_fetch_row (res)) == NULL) {
+ error = strdup(mysql_error(&mysql));
+ mysql_free_result (res);
+ mysql_close (&mysql);
+ die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
+ }
+
+ if (! is_numeric(row[0])) {
+ die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
+ }
+
+ value = strtod(row[0], NULL);
+
+ /* free the result */
+ mysql_free_result (res);
+
+ /* close the connection */
+ mysql_close (&mysql);
+
+ if (verbose >= 3)
+ printf("mysql result: %f\n", value);
+
+ status = get_status(value, my_thresholds);
+
+ if (status == STATE_OK) {
+ printf("QUERY %s: ", _("OK"));
+ } else if (status == STATE_WARNING) {
+ printf("QUERY %s: ", _("WARNING"));
+ } else if (status == STATE_CRITICAL) {
+ printf("QUERY %s: ", _("CRITICAL"));
+ }
+ printf(_("'%s' returned %f | %s"), sql_query, value,
+ fperfdata("result", value, "",
+ my_thresholds->warning?TRUE:FALSE, my_thresholds->warning?my_thresholds->warning->end:0,
+ my_thresholds->critical?TRUE:FALSE, my_thresholds->critical?my_thresholds->critical->end:0,
+ FALSE, 0,
+ FALSE, 0)
+ );
+ printf("\n");
+
+ return status;
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char *warning = NULL;
+ char *critical = NULL;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"socket", required_argument, 0, 's'},
+ {"database", required_argument, 0, 'd'},
+ {"username", required_argument, 0, 'u'},
+ {"password", required_argument, 0, 'p'},
+ {"file", required_argument, 0, 'f'},
+ {"group", required_argument, 0, 'g'},
+ {"port", required_argument, 0, 'P'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"query", required_argument, 0, 'q'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 1)
+ return ERROR;
+
+ while (1) {
+ c = getopt_long (argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'H': /* hostname */
+ if (is_host (optarg)) {
+ db_host = optarg;
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ break;
+ case 's': /* socket */
+ db_socket = optarg;
+ break;
+ case 'd': /* database */
+ db = optarg;
+ break;
+ case 'u': /* username */
+ db_user = optarg;
+ break;
+ case 'p': /* authentication information: password */
+ db_pass = strdup(optarg);
+
+ /* Delete the password from process list */
+ while (*optarg != '\0') {
+ *optarg = 'X';
+ optarg++;
+ }
+ break;
+ case 'f': /* client options file */
+ opt_file = optarg;
+ break;
+ case 'g': /* client options group */
+ opt_group = optarg;
+ break;
+ case 'P': /* critical time threshold */
+ db_port = atoi (optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'q':
+ xasprintf(&sql_query, "%s", optarg);
+ break;
+ case 'w':
+ warning = optarg;
+ break;
+ case 'c':
+ critical = optarg;
+ break;
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+
+ set_thresholds(&my_thresholds, warning, critical);
+
+ return validate_arguments ();
+}
+
+
+int
+validate_arguments (void)
+{
+ if (sql_query == NULL)
+ usage("Must specify a SQL query to run");
+
+ if (db_user == NULL)
+ db_user = strdup("");
+
+ if (db_host == NULL)
+ db_host = strdup("");
+
+ if (db == NULL)
+ db = strdup("");
+
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", MYSQL_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf (_(COPYRIGHT), copyright, email);
+
+ printf ("%s\n", _("This program checks a query result against threshold levels"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (" -q, --query=STRING\n");
+ printf (" %s\n", _("SQL query to run. Only first column in first row will be read"));
+ printf (UT_WARN_CRIT_RANGE);
+ printf (UT_HOST_PORT, 'P', myport);
+ printf (" %s\n", "-s, --socket=STRING");
+ printf (" %s\n", _("Use the specified socket (has no effect if -H is used)"));
+ printf (" -d, --database=STRING\n");
+ printf (" %s\n", _("Database to check"));
+ printf (" %s\n", "-f, --file=STRING");
+ printf (" %s\n", _("Read from the specified client options file"));
+ printf (" %s\n", "-g, --group=STRING");
+ printf (" %s\n", _("Use a client options group"));
+ printf (" -u, --username=STRING\n");
+ printf (" %s\n", _("Username to login with"));
+ printf (" -p, --password=STRING\n");
+ printf (" %s\n", _("Password to login with"));
+ printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
+ printf (" %s\n", _("Your clear-text password could be visible as a process table entry"));
+
+ printf ("\n");
+ printf (" %s\n", _("A query is required. The result from the query should be numeric."));
+ printf (" %s\n", _("For extra security, create a user with minimal access."));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("You must specify -p with an empty string to force an empty password,"));
+ printf (" %s\n", _("overriding any my.cnf settings."));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n",progname);
+ printf (" [-d database] [-u user] [-p password] [-f optfile] [-g group]\n");
+}
diff --git a/plugins/check_nagios.c b/plugins/check_nagios.c
new file mode 100644
index 0000000..40d68f0
--- /dev/null
+++ b/plugins/check_nagios.c
@@ -0,0 +1,325 @@
+/*****************************************************************************
+*
+* Monitoring check_nagios plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_nagios plugin
+*
+* This plugin checks the status of the Nagios process on the local machine.
+* The plugin will check to make sure the Nagios status log is no older than
+* the number of minutes specified by the expires option.
+* It also checks the process table for a process matching the command
+* argument.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_nagios";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "runcmd.h"
+#include "utils.h"
+
+int process_arguments (int, char **);
+void print_help (void);
+void print_usage (void);
+
+char *status_log = NULL;
+char *process_string = NULL;
+int expire_minutes = 0;
+
+int verbose = 0;
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ char input_buffer[MAX_INPUT_BUFFER];
+ unsigned long latest_entry_time = 0L;
+ unsigned long temp_entry_time = 0L;
+ int proc_entries = 0;
+ time_t current_time;
+ char *temp_ptr;
+ FILE *fp;
+ int procuid = 0;
+ int procpid = 0;
+ int procppid = 0;
+ int procvsz = 0;
+ int procrss = 0;
+ float procpcpu = 0;
+ char procstat[8];
+#ifdef PS_USES_PROCETIME
+ char procetime[MAX_INPUT_BUFFER];
+#endif /* PS_USES_PROCETIME */
+ char procprog[MAX_INPUT_BUFFER];
+ char *procargs;
+ int pos, cols;
+ int expected_cols = PS_COLS - 1;
+ const char *zombie = "Z";
+ char *temp_string;
+ output chld_out, chld_err;
+ size_t i;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage_va(_("Could not parse arguments"));
+
+ /* Set signal handling and alarm timeout */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ usage_va(_("Cannot catch SIGALRM"));
+ }
+
+ /* handle timeouts gracefully... */
+ alarm (timeout_interval);
+
+ /* open the status log */
+ fp = fopen (status_log, "r");
+ if (fp == NULL) {
+ die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
+ }
+
+ /* get the date/time of the last item updated in the log */
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
+ if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) {
+ temp_entry_time = strtoul (temp_ptr + 8, NULL, 10);
+ latest_entry_time = temp_entry_time;
+ break;
+ } else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) {
+ temp_entry_time = strtoul (temp_ptr + 1, NULL, 10);
+ if (temp_entry_time > latest_entry_time)
+ latest_entry_time = temp_entry_time;
+ }
+ }
+ fclose (fp);
+
+ if (verbose >= 2)
+ printf("command: %s\n", PS_COMMAND);
+
+ /* run the command to check for the Nagios process.. */
+ if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
+ result = STATE_WARNING;
+
+ /* count the number of matching Nagios processes... */
+ for(i = 0; i < chld_out.lines; i++) {
+ cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
+ /* Zombie processes do not give a procprog command */
+ if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
+ cols = expected_cols;
+ /* Set some value for procargs for the strip command further below
+ * Seen to be a problem on some Solaris 7 and 8 systems */
+ chld_out.line[i][pos] = '\n';
+ chld_out.line[i][pos+1] = 0x0;
+ }
+ if ( cols >= expected_cols ) {
+ xasprintf (&procargs, "%s", chld_out.line[i] + pos);
+ strip (procargs);
+
+ /* Some ps return full pathname for command. This removes path */
+ temp_string = strtok ((char *)procprog, "/");
+ while (temp_string) {
+ strcpy(procprog, temp_string);
+ temp_string = strtok (NULL, "/");
+ }
+
+ /* May get empty procargs */
+ if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
+ proc_entries++;
+ if (verbose >= 2) {
+ printf (_("Found process: %s %s\n"), procprog, procargs);
+ }
+ }
+ }
+ }
+
+ /* If we get anything on stderr, at least set warning */
+ if(chld_err.buflen)
+ result = max_state (result, STATE_WARNING);
+
+ /* reset the alarm handler */
+ alarm (0);
+
+ if (proc_entries == 0) {
+ die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
+ }
+
+ if (latest_entry_time == 0L) {
+ die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
+ }
+
+ time (&current_time);
+ if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) {
+ result = STATE_WARNING;
+ } else {
+ result = STATE_OK;
+ }
+
+ printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
+ printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries);
+ printf (", ");
+ printf (
+ ngettext ("status log updated %d second ago",
+ "status log updated %d seconds ago",
+ (int) (current_time - latest_entry_time) ),
+ (int) (current_time - latest_entry_time) );
+ printf ("\n");
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"filename", required_argument, 0, 'F'},
+ {"expires", required_argument, 0, 'e'},
+ {"command", required_argument, 0, 'C'},
+ {"timeout", optional_argument, 0, 't'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ if (!is_option (argv[1])) {
+ status_log = argv[1];
+ if (is_intnonneg (argv[2]))
+ expire_minutes = atoi (argv[2]);
+ else
+ die (STATE_UNKNOWN,
+ _("Expiration time must be an integer (seconds)\n"));
+ process_string = argv[3];
+ return OK;
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVvF:C:e:t:", longopts, &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'F': /* status log */
+ status_log = optarg;
+ break;
+ case 'C': /* command */
+ process_string = optarg;
+ break;
+ case 'e': /* expiry time */
+ if (is_intnonneg (optarg))
+ expire_minutes = atoi (optarg);
+ else
+ die (STATE_UNKNOWN,
+ _("Expiration time must be an integer (seconds)\n"));
+ break;
+ case 't': /* timeout */
+ if (is_intnonneg (optarg))
+ timeout_interval = atoi (optarg);
+ else
+ die (STATE_UNKNOWN,
+ _("Timeout must be an integer (seconds)\n"));
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default: /* print short usage_va statement if args not parsable */
+ usage5();
+ }
+ }
+
+
+ if (status_log == NULL)
+ die (STATE_UNKNOWN, _("You must provide the status_log\n"));
+
+ if (process_string == NULL)
+ die (STATE_UNKNOWN, _("You must provide a process string\n"));
+
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf (_(COPYRIGHT), copyright, email);
+
+ printf ("%s\n", _("This plugin checks the status of the Nagios process on the local machine"));
+ printf ("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
+ printf ("%s\n", _("the number of minutes specified by the expires option."));
+ printf ("%s\n", _("It also checks the process table for a process matching the command argument."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-F, --filename=FILE");
+ printf (" %s\n", _("Name of the log file to check"));
+ printf (" %s\n", "-e, --expires=INTEGER");
+ printf (" %s\n", _("Minutes aging after which logfile is considered stale"));
+ printf (" %s\n", "-C, --command=STRING");
+ printf (" %s\n", _("Substring to search for in process arguments"));
+ printf (" %s\n", "-t, --timeout=INTEGER");
+ printf (" %s\n", _("Timeout for the plugin in seconds"));
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
+}
diff --git a/plugins/check_nt.c b/plugins/check_nt.c
new file mode 100644
index 0000000..d73d83c
--- /dev/null
+++ b/plugins/check_nt.c
@@ -0,0 +1,801 @@
+/*****************************************************************************
+*
+* Monitoring check_nt plugin
+*
+* License: GPL
+* Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com)
+* Copyright (c) 2003-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_nt plugin
+*
+* This plugin collects data from the NSClient service running on a
+* Windows NT/2000/XP/2003 server.
+* This plugin requires NSClient software to run on NT
+* (http://nsclient.ready2run.nl/)
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_nt";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum checkvars {
+ CHECK_NONE,
+ CHECK_CLIENTVERSION,
+ CHECK_CPULOAD,
+ CHECK_UPTIME,
+ CHECK_USEDDISKSPACE,
+ CHECK_SERVICESTATE,
+ CHECK_PROCSTATE,
+ CHECK_MEMUSE,
+ CHECK_COUNTER,
+ CHECK_FILEAGE,
+ CHECK_INSTANCES
+};
+
+enum {
+ MAX_VALUE_LIST = 30,
+ PORT = 1248
+};
+
+char *server_address=NULL;
+char *volume_name=NULL;
+int server_port=PORT;
+char *value_list=NULL;
+char *req_password=NULL;
+unsigned long lvalue_list[MAX_VALUE_LIST];
+unsigned long warning_value=0L;
+unsigned long critical_value=0L;
+int check_warning_value=FALSE;
+int check_critical_value=FALSE;
+enum checkvars vars_to_check = CHECK_NONE;
+int show_all=FALSE;
+
+char recv_buffer[MAX_INPUT_BUFFER];
+
+void fetch_data (const char* address, int port, const char* sendb);
+int process_arguments(int, char **);
+void preparelist(char *string);
+int strtoularray(unsigned long *array, char *string, const char *delim);
+void print_help(void);
+void print_usage(void);
+
+int main(int argc, char **argv){
+
+/* should be int result = STATE_UNKNOWN; */
+
+ int return_code = STATE_UNKNOWN;
+ char *send_buffer=NULL;
+ char *output_message=NULL;
+ char *perfdata=NULL;
+ char *temp_string=NULL;
+ char *temp_string_perf=NULL;
+ char *description=NULL,*counter_unit = NULL;
+ char *minval = NULL, *maxval = NULL, *errcvt = NULL;
+ char *fds=NULL, *tds=NULL;
+ char *numstr;
+
+ double total_disk_space=0;
+ double free_disk_space=0;
+ double percent_used_space=0;
+ double warning_used_space=0;
+ double critical_used_space=0;
+ double mem_commitLimit=0;
+ double mem_commitByte=0;
+ double fminval = 0, fmaxval = 0;
+ unsigned long utilization;
+ unsigned long uptime;
+ unsigned long age_in_minutes;
+ double counter_value = 0.0;
+ int offset=0;
+ int updays=0;
+ int uphours=0;
+ int upminutes=0;
+
+ int isPercent = FALSE;
+ int allRight = FALSE;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if(process_arguments(argc,argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal(SIGALRM,socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm(socket_timeout);
+
+ switch (vars_to_check) {
+
+ case CHECK_CLIENTVERSION:
+
+ xasprintf(&send_buffer, "%s&1", req_password);
+ fetch_data (server_address, server_port, send_buffer);
+ if (value_list != NULL && strcmp(recv_buffer, value_list) != 0) {
+ xasprintf (&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list);
+ return_code = STATE_WARNING;
+ } else {
+ xasprintf (&output_message, "%s", recv_buffer);
+ return_code = STATE_OK;
+ }
+ break;
+
+ case CHECK_CPULOAD:
+
+ if (value_list==NULL)
+ output_message = strdup (_("missing -l parameters"));
+ else if (strtoularray(lvalue_list,value_list,",")==FALSE)
+ output_message = strdup (_("wrong -l parameter."));
+ else {
+ /* -l parameters is present with only integers */
+ return_code=STATE_OK;
+ temp_string = strdup (_("CPU Load"));
+ temp_string_perf = strdup (" ");
+
+ /* loop until one of the parameters is wrong or not present */
+ while (lvalue_list[0+offset]> (unsigned long)0 &&
+ lvalue_list[0+offset]<=(unsigned long)17280 &&
+ lvalue_list[1+offset]> (unsigned long)0 &&
+ lvalue_list[1+offset]<=(unsigned long)100 &&
+ lvalue_list[2+offset]> (unsigned long)0 &&
+ lvalue_list[2+offset]<=(unsigned long)100) {
+
+ /* Send request and retrieve data */
+ xasprintf(&send_buffer,"%s&2&%lu",req_password,lvalue_list[0+offset]);
+ fetch_data (server_address, server_port, send_buffer);
+
+ utilization=strtoul(recv_buffer,NULL,10);
+
+ /* Check if any of the request is in a warning or critical state */
+ if(utilization >= lvalue_list[2+offset])
+ return_code=STATE_CRITICAL;
+ else if(utilization >= lvalue_list[1+offset] && return_code<STATE_WARNING)
+ return_code=STATE_WARNING;
+
+ xasprintf(&output_message,_(" %lu%% (%lu min average)"), utilization, lvalue_list[0+offset]);
+ xasprintf(&temp_string,"%s%s",temp_string,output_message);
+ xasprintf(&perfdata,_(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0+offset], utilization,
+ lvalue_list[1+offset], lvalue_list[2+offset]);
+ xasprintf(&temp_string_perf,"%s%s",temp_string_perf,perfdata);
+ offset+=3; /* move across the array */
+ }
+
+ if (strlen(temp_string)>10) { /* we had at least one loop */
+ output_message = strdup (temp_string);
+ perfdata = temp_string_perf;
+ } else
+ output_message = strdup (_("not enough values for -l parameters"));
+ }
+ break;
+
+ case CHECK_UPTIME:
+
+ if (value_list == NULL) {
+ value_list = "minutes";
+ }
+ if (strncmp(value_list, "seconds", strlen("seconds") + 1 ) &&
+ strncmp(value_list, "minutes", strlen("minutes") + 1) &&
+ strncmp(value_list, "hours", strlen("hours") + 1) &&
+ strncmp(value_list, "days", strlen("days") + 1)) {
+
+ output_message = strdup (_("wrong -l argument"));
+ } else {
+ xasprintf(&send_buffer, "%s&3", req_password);
+ fetch_data (server_address, server_port, send_buffer);
+ uptime=strtoul(recv_buffer,NULL,10);
+ updays = uptime / 86400;
+ uphours = (uptime % 86400) / 3600;
+ upminutes = ((uptime % 86400) % 3600) / 60;
+
+ if (!strncmp(value_list, "minutes", strlen("minutes")))
+ uptime = uptime / 60;
+ else if (!strncmp(value_list, "hours", strlen("hours")))
+ uptime = uptime / 3600;
+ else if (!strncmp(value_list, "days", strlen("days")))
+ uptime = uptime / 86400;
+ /* else uptime in seconds, nothing to do */
+
+ xasprintf(&output_message,_("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"),updays, uphours, upminutes, uptime);
+
+ if (check_critical_value==TRUE && uptime <= critical_value)
+ return_code=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && uptime <= warning_value)
+ return_code=STATE_WARNING;
+ else
+ return_code=STATE_OK;
+ }
+ break;
+
+ case CHECK_USEDDISKSPACE:
+
+ if (value_list==NULL)
+ output_message = strdup (_("missing -l parameters"));
+ else if (strlen(value_list)!=1)
+ output_message = strdup (_("wrong -l argument"));
+ else {
+ xasprintf(&send_buffer,"%s&4&%s", req_password, value_list);
+ fetch_data (server_address, server_port, send_buffer);
+ fds=strtok(recv_buffer,"&");
+ tds=strtok(NULL,"&");
+ if(fds!=NULL)
+ free_disk_space=atof(fds);
+ if(tds!=NULL)
+ total_disk_space=atof(tds);
+
+ if (total_disk_space>0 && free_disk_space>=0) {
+ percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
+ warning_used_space = ((float)warning_value / 100) * total_disk_space;
+ critical_used_space = ((float)critical_value / 100) * total_disk_space;
+
+ xasprintf(&temp_string,_("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"),
+ value_list, total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824,
+ percent_used_space, free_disk_space / 1073741824, (free_disk_space / total_disk_space)*100);
+ xasprintf(&temp_string_perf,_("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list,
+ (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
+ critical_used_space / 1073741824, total_disk_space / 1073741824);
+
+ if(check_critical_value==TRUE && percent_used_space >= critical_value)
+ return_code=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_used_space >= warning_value)
+ return_code=STATE_WARNING;
+ else
+ return_code=STATE_OK;
+
+ output_message = strdup (temp_string);
+ perfdata = temp_string_perf;
+ } else {
+ output_message = strdup (_("Free disk space : Invalid drive"));
+ return_code=STATE_UNKNOWN;
+ }
+ }
+ break;
+
+ case CHECK_SERVICESTATE:
+ case CHECK_PROCSTATE:
+
+ if (value_list==NULL)
+ output_message = strdup (_("No service/process specified"));
+ else {
+ preparelist(value_list); /* replace , between services with & to send the request */
+ xasprintf(&send_buffer,"%s&%u&%s&%s", req_password,(vars_to_check==CHECK_SERVICESTATE)?5:6,
+ (show_all==TRUE) ? "ShowAll" : "ShowFail",value_list);
+ fetch_data (server_address, server_port, send_buffer);
+ numstr = strtok(recv_buffer,"&");
+ if (numstr == NULL)
+ die(STATE_UNKNOWN, _("could not fetch information from server\n"));
+ return_code=atoi(numstr);
+ temp_string=strtok(NULL,"&");
+ output_message = strdup (temp_string);
+ }
+ break;
+
+ case CHECK_MEMUSE:
+
+ xasprintf(&send_buffer,"%s&7", req_password);
+ fetch_data (server_address, server_port, send_buffer);
+ numstr = strtok(recv_buffer,"&");
+ if (numstr == NULL)
+ die(STATE_UNKNOWN, _("could not fetch information from server\n"));
+ mem_commitLimit=atof(numstr);
+ numstr = strtok(NULL,"&");
+ if (numstr == NULL)
+ die(STATE_UNKNOWN, _("could not fetch information from server\n"));
+ mem_commitByte=atof(numstr);
+ percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
+ warning_used_space = ((float)warning_value / 100) * mem_commitLimit;
+ critical_used_space = ((float)critical_value / 100) * mem_commitLimit;
+
+ /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
+ which equals RAM + Pagefiles. */
+ xasprintf(&output_message,_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
+ mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space,
+ (mem_commitLimit - mem_commitByte) / 1048567, (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
+ xasprintf(&perfdata,_("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567,
+ warning_used_space / 1048567, critical_used_space / 1048567, mem_commitLimit / 1048567);
+
+ return_code=STATE_OK;
+ if(check_critical_value==TRUE && percent_used_space >= critical_value)
+ return_code=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_used_space >= warning_value)
+ return_code=STATE_WARNING;
+
+ break;
+
+ case CHECK_COUNTER:
+
+
+ /*
+ CHECK_COUNTER has been modified to provide extensive perfdata information.
+ In order to do this, some modifications have been done to the code
+ and some constraints have been introduced.
+
+ 1) For the sake of simplicity of the code, perfdata information will only be
+ provided when the "description" field is added.
+
+ 2) If the counter you're going to measure is percent-based, the code will detect
+ the percent sign in its name and will attribute minimum (0%) and maximum (100%)
+ values automagically, as well the "%" sign to graph units.
+
+ 3) OTOH, if the counter is "absolute", you'll have to provide the following
+ the counter unit - that is, the dimensions of the counter you're getting. Examples:
+ pages/s, packets transferred, etc.
+
+ 4) If you want, you may provide the minimum and maximum values to expect. They aren't mandatory,
+ but once specified they MUST have the same order of magnitude and units of -w and -c; otherwise.
+ strange things will happen when you make graphs of your data.
+ */
+
+ if (value_list == NULL)
+ output_message = strdup (_("No counter specified"));
+ else
+ {
+ preparelist (value_list); /* replace , between services with & to send the request */
+ isPercent = (strchr (value_list, '%') != NULL);
+
+ strtok (value_list, "&"); /* burn the first parameters */
+ description = strtok (NULL, "&");
+ counter_unit = strtok (NULL, "&");
+ xasprintf (&send_buffer, "%s&8&%s", req_password, value_list);
+ fetch_data (server_address, server_port, send_buffer);
+ counter_value = atof (recv_buffer);
+
+ if (description == NULL)
+ xasprintf (&output_message, "%.f", counter_value);
+ else if (isPercent)
+ {
+ counter_unit = strdup ("%");
+ allRight = TRUE;
+ }
+
+ if ((counter_unit != NULL) && (!allRight))
+ {
+ minval = strtok (NULL, "&");
+ maxval = strtok (NULL, "&");
+
+ /* All parameters specified. Let's check the numbers */
+
+ fminval = (minval != NULL) ? strtod (minval, &errcvt) : -1;
+ fmaxval = (minval != NULL) ? strtod (maxval, &errcvt) : -1;
+
+ if ((fminval == 0) && (minval == errcvt))
+ output_message = strdup (_("Minimum value contains non-numbers"));
+ else
+ {
+ if ((fmaxval == 0) && (maxval == errcvt))
+ output_message = strdup (_("Maximum value contains non-numbers"));
+ else
+ allRight = TRUE; /* Everything is OK. */
+
+ }
+ }
+ else if ((counter_unit == NULL) && (description != NULL))
+ output_message = strdup (_("No unit counter specified"));
+
+ if (allRight)
+ {
+ /* Let's format the output string, finally... */
+ if (strstr(description, "%") == NULL) {
+ xasprintf (&output_message, "%s = %.2f %s", description, counter_value, counter_unit);
+ } else {
+ /* has formatting, will segv if wrong */
+ xasprintf (&output_message, description, counter_value);
+ }
+ xasprintf (&output_message, "%s |", output_message);
+ xasprintf (&output_message,"%s %s", output_message,
+ fperfdata (description, counter_value,
+ counter_unit, 1, warning_value, 1, critical_value,
+ (!(isPercent) && (minval != NULL)), fminval,
+ (!(isPercent) && (minval != NULL)), fmaxval));
+ }
+ }
+
+ if (critical_value > warning_value)
+ { /* Normal thresholds */
+ if (check_critical_value == TRUE && counter_value >= critical_value)
+ return_code = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && counter_value >= warning_value)
+ return_code = STATE_WARNING;
+ else
+ return_code = STATE_OK;
+ }
+ else
+ { /* inverse thresholds */
+ return_code = STATE_OK;
+ if (check_critical_value == TRUE && counter_value <= critical_value)
+ return_code = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && counter_value <= warning_value)
+ return_code = STATE_WARNING;
+ }
+ break;
+
+ case CHECK_FILEAGE:
+
+ if (value_list==NULL)
+ output_message = strdup (_("No counter specified"));
+ else {
+ preparelist(value_list); /* replace , between services with & to send the request */
+ xasprintf(&send_buffer,"%s&9&%s", req_password,value_list);
+ fetch_data (server_address, server_port, send_buffer);
+ age_in_minutes = atoi(strtok(recv_buffer,"&"));
+ description = strtok(NULL,"&");
+ output_message = strdup (description);
+
+ if (critical_value > warning_value) { /* Normal thresholds */
+ if(check_critical_value==TRUE && age_in_minutes >= critical_value)
+ return_code=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && age_in_minutes >= warning_value)
+ return_code=STATE_WARNING;
+ else
+ return_code=STATE_OK;
+ }
+ else { /* inverse thresholds */
+ if(check_critical_value==TRUE && age_in_minutes <= critical_value)
+ return_code=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && age_in_minutes <= warning_value)
+ return_code=STATE_WARNING;
+ else
+ return_code=STATE_OK;
+ }
+ }
+ break;
+
+ case CHECK_INSTANCES:
+ if (value_list==NULL)
+ output_message = strdup (_("No counter specified"));
+ else {
+ xasprintf(&send_buffer,"%s&10&%s", req_password,value_list);
+ fetch_data (server_address, server_port, send_buffer);
+ if (!strncmp(recv_buffer,"ERROR",5)) {
+ printf("NSClient - %s\n",recv_buffer);
+ exit(STATE_UNKNOWN);
+ }
+ xasprintf(&output_message,"%s",recv_buffer);
+ return_code=STATE_OK;
+ }
+ break;
+
+ case CHECK_NONE:
+ default:
+ usage4 (_("Please specify a variable to check"));
+ break;
+
+ }
+
+ /* reset timeout */
+ alarm(0);
+
+ if (perfdata==NULL)
+ printf("%s\n",output_message);
+ else
+ printf("%s | %s\n",output_message,perfdata);
+ return return_code;
+}
+
+
+
+/* process command-line arguments */
+int process_arguments(int argc, char **argv){
+ int c;
+
+ int option = 0;
+ static struct option longopts[] =
+ {
+ {"port", required_argument,0,'p'},
+ {"timeout", required_argument,0,'t'},
+ {"critical", required_argument,0,'c'},
+ {"warning", required_argument,0,'w'},
+ {"variable", required_argument,0,'v'},
+ {"hostname", required_argument,0,'H'},
+ {"params", required_argument,0,'l'},
+ {"secret", required_argument,0,'s'},
+ {"display", required_argument,0,'d'},
+ {"unknown-timeout", no_argument, 0, 'u'},
+ {"version", no_argument, 0,'V'},
+ {"help", no_argument, 0,'h'},
+ {0,0,0,0}
+ };
+
+ /* no options were supplied */
+ if(argc<2) return ERROR;
+
+ /* backwards compatibility */
+ if (! is_option(argv[1])) {
+ server_address = strdup(argv[1]);
+ argv[1]=argv[0];
+ argv=&argv[1];
+ argc--;
+ }
+
+ for (c=1;c<argc;c++) {
+ if(strcmp("-to",argv[c])==0)
+ strcpy(argv[c],"-t");
+ else if (strcmp("-wv",argv[c])==0)
+ strcpy(argv[c],"-w");
+ else if (strcmp("-cv",argv[c])==0)
+ strcpy(argv[c],"-c");
+ }
+
+ while (1) {
+ c = getopt_long(argc,argv,"+hVH:t:c:w:p:v:l:s:d:u",longopts,&option);
+
+ if (c==-1||c==EOF||c==1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help();
+ exit(STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ case 'H': /* hostname */
+ server_address = optarg;
+ break;
+ case 's': /* password */
+ req_password = optarg;
+ break;
+ case 'p': /* port */
+ if (is_intnonneg(optarg))
+ server_port=atoi(optarg);
+ else
+ die(STATE_UNKNOWN,_("Server port must be an integer\n"));
+ break;
+ case 'v':
+ if(strlen(optarg)<4)
+ return ERROR;
+ if(!strcmp(optarg,"CLIENTVERSION"))
+ vars_to_check=CHECK_CLIENTVERSION;
+ else if(!strcmp(optarg,"CPULOAD"))
+ vars_to_check=CHECK_CPULOAD;
+ else if(!strcmp(optarg,"UPTIME"))
+ vars_to_check=CHECK_UPTIME;
+ else if(!strcmp(optarg,"USEDDISKSPACE"))
+ vars_to_check=CHECK_USEDDISKSPACE;
+ else if(!strcmp(optarg,"SERVICESTATE"))
+ vars_to_check=CHECK_SERVICESTATE;
+ else if(!strcmp(optarg,"PROCSTATE"))
+ vars_to_check=CHECK_PROCSTATE;
+ else if(!strcmp(optarg,"MEMUSE"))
+ vars_to_check=CHECK_MEMUSE;
+ else if(!strcmp(optarg,"COUNTER"))
+ vars_to_check=CHECK_COUNTER;
+ else if(!strcmp(optarg,"FILEAGE"))
+ vars_to_check=CHECK_FILEAGE;
+ else if(!strcmp(optarg,"INSTANCES"))
+ vars_to_check=CHECK_INSTANCES;
+ else
+ return ERROR;
+ break;
+ case 'l': /* value list */
+ value_list = optarg;
+ break;
+ case 'w': /* warning threshold */
+ warning_value=strtoul(optarg,NULL,10);
+ check_warning_value=TRUE;
+ break;
+ case 'c': /* critical threshold */
+ critical_value=strtoul(optarg,NULL,10);
+ check_critical_value=TRUE;
+ break;
+ case 'd': /* Display select for services */
+ if (!strcmp(optarg,"SHOWALL"))
+ show_all = TRUE;
+ break;
+ case 'u':
+ socket_timeout_state=STATE_UNKNOWN;
+ break;
+ case 't': /* timeout */
+ socket_timeout=atoi(optarg);
+ if(socket_timeout<=0)
+ return ERROR;
+ }
+
+ }
+ if (server_address == NULL)
+ usage4 (_("You must provide a server address or host name"));
+
+ if (vars_to_check==CHECK_NONE)
+ return ERROR;
+
+ if (req_password == NULL)
+ req_password = strdup (_("None"));
+
+ return OK;
+}
+
+
+
+void fetch_data (const char *address, int port, const char *sendb) {
+ int result;
+
+ result=process_tcp_request(address, port, sendb, recv_buffer,sizeof(recv_buffer));
+
+ if(result!=STATE_OK)
+ die (result, _("could not fetch information from server\n"));
+
+ if (!strncmp(recv_buffer,"ERROR",5))
+ die (STATE_UNKNOWN, "NSClient - %s\n",recv_buffer);
+}
+
+int strtoularray(unsigned long *array, char *string, const char *delim) {
+ /* split a <delim> delimited string into a long array */
+ int idx=0;
+ char *t1;
+
+ for (idx=0;idx<MAX_VALUE_LIST;idx++)
+ array[idx]=0;
+
+ idx=0;
+ for(t1 = strtok(string,delim);t1 != NULL; t1 = strtok(NULL, delim)) {
+ if (is_numeric(t1) && idx<MAX_VALUE_LIST) {
+ array[idx]=strtoul(t1,NULL,10);
+ idx++;
+ } else
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void preparelist(char *string) {
+ /* Replace all , with & which is the delimiter for the request */
+ int i;
+
+ for (i = 0; (size_t)i < strlen(string); i++)
+ if (string[i] == ',') {
+ string[i]='&';
+ }
+}
+
+
+
+void print_help(void)
+{
+ print_revision(progname, NP_VERSION);
+
+ printf ("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin collects data from the NSClient service running on a"));
+ printf ("%s\n", _("Windows NT/2000/XP/2003 server."));
+
+ printf ("\n\n");
+
+ print_usage();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf ("%s\n", _("Options:"));
+ printf (" %s\n", "-H, --hostname=HOST");
+ printf (" %s\n", _("Name of the host to check"));
+ printf (" %s\n", "-p, --port=INTEGER");
+ printf (" %s", _("Optional port number (default: "));
+ printf ("%d)\n", PORT);
+ printf (" %s\n", "-s, --secret=<password>");
+ printf (" %s\n", _("Password needed for the request"));
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a warning status"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a critical status"));
+ printf (" %s\n", "-t, --timeout=INTEGER");
+ printf (" %s", _("Seconds before connection attempt times out (default: "));
+ printf (" %s\n", "-l, --params=<parameters>");
+ printf (" %s", _("Parameters passed to specified check (see below)"));
+ printf (" %s\n", "-d, --display={SHOWALL}");
+ printf (" %s", _("Display options (currently only SHOWALL works)"));
+ printf (" %s\n", "-u, --unknown-timeout");
+ printf (" %s", _("Return UNKNOWN on timeouts"));
+ printf ("%d)\n", DEFAULT_SOCKET_TIMEOUT);
+ printf (" %s\n", "-h, --help");
+ printf (" %s\n", _("Print this help screen"));
+ printf (" %s\n", "-V, --version");
+ printf (" %s\n", _("Print version information"));
+ printf (" %s\n", "-v, --variable=STRING");
+ printf (" %s\n\n", _("Variable to check"));
+ printf ("%s\n", _("Valid variables are:"));
+ printf (" %s", "CLIENTVERSION =");
+ printf (" %s\n", _("Get the NSClient version"));
+ printf (" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
+ printf (" %s\n", "CPULOAD =");
+ printf (" %s\n", _("Average CPU load on last x minutes."));
+ printf (" %s\n", _("Request a -l parameter with the following syntax:"));
+ printf (" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
+ printf (" %s\n", _("<minute range> should be less than 24*60."));
+ printf (" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot."));
+ printf (" %s\n", "ie: -l 60,90,95,120,90,95");
+ printf (" %s\n", "UPTIME =");
+ printf (" %s\n", _("Get the uptime of the machine."));
+ printf (" %s\n", _("-l <unit> "));
+ printf (" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
+ printf (" %s\n", _("Thresholds will use the unit specified above."));
+ printf (" %s\n", "USEDDISKSPACE =");
+ printf (" %s\n", _("Size and percentage of disk use."));
+ printf (" %s\n", _("Request a -l parameter containing the drive letter only."));
+ printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
+ printf (" %s\n", "MEMUSE =");
+ printf (" %s\n", _("Memory use."));
+ printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
+ printf (" %s\n", "SERVICESTATE =");
+ printf (" %s\n", _("Check the state of one or several services."));
+ printf (" %s\n", _("Request a -l parameters with the following syntax:"));
+ printf (" %s\n", _("-l <service1>,<service2>,<service3>,..."));
+ printf (" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
+ printf (" %s\n", _("in the returned string."));
+ printf (" %s\n", "PROCSTATE =");
+ printf (" %s\n", _("Check if one or several process are running."));
+ printf (" %s\n", _("Same syntax as SERVICESTATE."));
+ printf (" %s\n", "COUNTER =");
+ printf (" %s\n", _("Check any performance counter of Windows NT/2000."));
+ printf (" %s\n", _("Request a -l parameters with the following syntax:"));
+ printf (" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
+ printf (" %s\n", _("The <description> parameter is optional and is given to a printf "));
+ printf (" %s\n", _("output command which requires a float parameter."));
+ printf (" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
+ printf (" %s\n", _("Some examples:"));
+ printf (" %s\n", "\"Paging file usage is %%.2f %%%%\"");
+ printf (" %s\n", "\"%%.f %%%% paging file used.\"");
+ printf (" %s\n", "INSTANCES =");
+ printf (" %s\n", _("Check any performance counter object of Windows NT/2000."));
+ printf (" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
+ printf (" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
+ printf (" %s\n", _("if it is two words, it should be enclosed in quotes"));
+ printf (" %s\n", _("The returned results will be a comma-separated list of instances on "));
+ printf (" %s\n", _(" the selected computer for that object."));
+ printf (" %s\n", _("The purpose of this is to be run from command line to determine what instances"));
+ printf (" %s\n", _(" are available for monitoring without having to log onto the Windows server"));
+ printf (" %s\n", _(" to run Perfmon directly."));
+ printf (" %s\n", _("It can also be used in scripts that automatically create the monitoring service"));
+ printf (" %s\n", _(" configuration files."));
+ printf (" %s\n", _("Some examples:"));
+ printf (" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
+
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("- The NSClient service should be running on the server to get any information"));
+ printf (" %s\n", "(http://nsclient.ready2run.nl).");
+ printf (" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
+ printf (" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
+ printf (" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
+ printf (" %s\n", _("One fix for this is to change the port to something else on check_nt "));
+ printf (" %s\n", _("and on the client service it\'s connecting to."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void print_usage(void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host -v variable [-p port] [-w warning] [-c critical]\n",progname);
+ printf ("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
+}
+
diff --git a/plugins/check_ntp.c b/plugins/check_ntp.c
new file mode 100644
index 0000000..99537c8
--- /dev/null
+++ b/plugins/check_ntp.c
@@ -0,0 +1,900 @@
+/*****************************************************************************
+*
+* Monitoring check_ntp plugin
+*
+* License: GPL
+* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
+* Copyright (c) 2006-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ntp plugin
+*
+* This plugin to check ntp servers independent of any commandline
+* programs or external libraries.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ntp";
+const char *copyright = "2006-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+static char *server_address=NULL;
+static int verbose=0;
+static short do_offset=0;
+static char *owarn="60";
+static char *ocrit="120";
+static short do_jitter=0;
+static char *jwarn="5000";
+static char *jcrit="10000";
+
+int process_arguments (int, char **);
+thresholds *offset_thresholds = NULL;
+thresholds *jitter_thresholds = NULL;
+void print_help (void);
+void print_usage (void);
+
+/* number of times to perform each request to get a good average. */
+#ifndef AVG_NUM
+#define AVG_NUM 4
+#endif
+
+/* max size of control message data */
+#define MAX_CM_SIZE 468
+
+/* this structure holds everything in an ntp request/response as per rfc1305 */
+typedef struct {
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+ uint8_t stratum; /* clock stratum */
+ int8_t poll; /* polling interval */
+ int8_t precision; /* precision of the local clock */
+ int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
+ uint32_t rtdisp; /* like above, but for max err to primary src */
+ uint32_t refid; /* ref clock identifier */
+ uint64_t refts; /* reference timestamp. local time local clock */
+ uint64_t origts; /* time at which request departed client */
+ uint64_t rxts; /* time at which request arrived at server */
+ uint64_t txts; /* time at which request departed server */
+} ntp_message;
+
+/* this structure holds data about results from querying offset from a peer */
+typedef struct {
+ time_t waiting; /* ts set when we started waiting for a response */
+ int num_responses; /* number of successfully received responses */
+ uint8_t stratum; /* copied verbatim from the ntp_message */
+ double rtdelay; /* converted from the ntp_message */
+ double rtdisp; /* converted from the ntp_message */
+ double offset[AVG_NUM]; /* offsets from each response */
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+} ntp_server_results;
+
+/* this structure holds everything in an ntp control message as per rfc1305 */
+typedef struct {
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+ uint8_t op; /* R,E,M bits and Opcode */
+ uint16_t seq; /* Packet sequence */
+ uint16_t status; /* Clock status */
+ uint16_t assoc; /* Association */
+ uint16_t offset; /* Similar to TCP sequence # */
+ uint16_t count; /* # bytes of data */
+ char data[MAX_CM_SIZE]; /* ASCII data of the request */
+ /* NB: not necessarily NULL terminated! */
+} ntp_control_message;
+
+/* this is an association/status-word pair found in control packet responses */
+typedef struct {
+ uint16_t assoc;
+ uint16_t status;
+} ntp_assoc_status_pair;
+
+/* bits 1,2 are the leap indicator */
+#define LI_MASK 0xc0
+#define LI(x) ((x&LI_MASK)>>6)
+#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0)
+/* and these are the values of the leap indicator */
+#define LI_NOWARNING 0x00
+#define LI_EXTRASEC 0x01
+#define LI_MISSINGSEC 0x02
+#define LI_ALARM 0x03
+/* bits 3,4,5 are the ntp version */
+#define VN_MASK 0x38
+#define VN(x) ((x&VN_MASK)>>3)
+#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0)
+#define VN_RESERVED 0x02
+/* bits 6,7,8 are the ntp mode */
+#define MODE_MASK 0x07
+#define MODE(x) (x&MODE_MASK)
+#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0)
+/* here are some values */
+#define MODE_CLIENT 0x03
+#define MODE_CONTROLMSG 0x06
+/* In control message, bits 8-10 are R,E,M bits */
+#define REM_MASK 0xe0
+#define REM_RESP 0x80
+#define REM_ERROR 0x40
+#define REM_MORE 0x20
+/* In control message, bits 11 - 15 are opcode */
+#define OP_MASK 0x1f
+#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0)
+#define OP_READSTAT 0x01
+#define OP_READVAR 0x02
+/* In peer status bytes, bits 6,7,8 determine clock selection status */
+#define PEER_SEL(x) ((ntohs(x)>>8)&0x07)
+#define PEER_INCLUDED 0x04
+#define PEER_SYNCSOURCE 0x06
+
+/**
+ ** a note about the 32-bit "fixed point" numbers:
+ **
+ they are divided into halves, each being a 16-bit int in network byte order:
+ - the first 16 bits are an int on the left side of a decimal point.
+ - the second 16 bits represent a fraction n/(2^16)
+ likewise for the 64-bit "fixed point" numbers with everything doubled :)
+ **/
+
+/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
+ number. note that these can be used as lvalues too */
+#define L16(x) (((uint16_t*)&x)[0])
+#define R16(x) (((uint16_t*)&x)[1])
+/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
+ number. these too can be used as lvalues */
+#define L32(x) (((uint32_t*)&x)[0])
+#define R32(x) (((uint32_t*)&x)[1])
+
+/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
+#define EPOCHDIFF 0x83aa7e80UL
+
+/* extract a 32-bit ntp fixed point number into a double */
+#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)
+
+/* likewise for a 64-bit ntp fp number */
+#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\
+ (ntohl(L32(n))-EPOCHDIFF) + \
+ (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
+ 0)
+
+/* convert a struct timeval to a double */
+#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec))
+
+/* convert an ntp 64-bit fp number to a struct timeval */
+#define NTP64toTV(n,t) \
+ do{ if(!n) t.tv_sec = t.tv_usec = 0; \
+ else { \
+ t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \
+ t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \
+ } \
+ }while(0)
+
+/* convert a struct timeval to an ntp 64-bit fp number */
+#define TVtoNTP64(t,n) \
+ do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \
+ else { \
+ L32(n)=htonl(t.tv_sec + EPOCHDIFF); \
+ R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \
+ } \
+ } while(0)
+
+/* NTP control message header is 12 bytes, plus any data in the data
+ * field, plus null padding to the nearest 32-bit boundary per rfc.
+ */
+#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0))
+
+/* finally, a little helper or two for debugging: */
+#define DBG(x) do{if(verbose>1){ x; }}while(0);
+#define PRINTSOCKADDR(x) \
+ do{ \
+ printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\
+ }while(0);
+
+/* calculate the offset of the local clock */
+static inline double calc_offset(const ntp_message *m, const struct timeval *t){
+ double client_tx, peer_rx, peer_tx, client_rx;
+ client_tx = NTP64asDOUBLE(m->origts);
+ peer_rx = NTP64asDOUBLE(m->rxts);
+ peer_tx = NTP64asDOUBLE(m->txts);
+ client_rx=TVasDOUBLE((*t));
+ return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
+}
+
+/* print out a ntp packet in human readable/debuggable format */
+void print_ntp_message(const ntp_message *p){
+ struct timeval ref, orig, rx, tx;
+
+ NTP64toTV(p->refts,ref);
+ NTP64toTV(p->origts,orig);
+ NTP64toTV(p->rxts,rx);
+ NTP64toTV(p->txts,tx);
+
+ printf("packet contents:\n");
+ printf("\tflags: 0x%.2x\n", p->flags);
+ printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
+ printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
+ printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
+ printf("\tstratum = %d\n", p->stratum);
+ printf("\tpoll = %g\n", pow(2, p->poll));
+ printf("\tprecision = %g\n", pow(2, p->precision));
+ printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
+ printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
+ printf("\trefid = %x\n", p->refid);
+ printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
+ printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
+ printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
+ printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
+}
+
+void print_ntp_control_message(const ntp_control_message *p){
+ int i=0, numpeers=0;
+ const ntp_assoc_status_pair *peer=NULL;
+
+ printf("control packet contents:\n");
+ printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
+ printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
+ printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
+ printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
+ printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP);
+ printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE);
+ printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR);
+ printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK);
+ printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
+ printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
+ printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
+ printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
+ printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
+ numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair));
+ if(p->op&REM_RESP && p->op&OP_READSTAT){
+ peer=(ntp_assoc_status_pair*)p->data;
+ for(i=0;i<numpeers;i++){
+ printf("\tpeer id %.2x status %.2x",
+ ntohs(peer[i].assoc), ntohs(peer[i].status));
+ if (PEER_SEL(peer[i].status) >= PEER_INCLUDED){
+ if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){
+ printf(" <-- current sync source");
+ } else {
+ printf(" <-- current sync candidate");
+ }
+ }
+ printf("\n");
+ }
+ }
+}
+
+void setup_request(ntp_message *p){
+ struct timeval t;
+
+ memset(p, 0, sizeof(ntp_message));
+ LI_SET(p->flags, LI_ALARM);
+ VN_SET(p->flags, 4);
+ MODE_SET(p->flags, MODE_CLIENT);
+ p->poll=4;
+ p->precision=(int8_t)0xfa;
+ L16(p->rtdelay)=htons(1);
+ L16(p->rtdisp)=htons(1);
+
+ gettimeofday(&t, NULL);
+ TVtoNTP64(t,p->txts);
+}
+
+/* select the "best" server from a list of servers, and return its index.
+ * this is done by filtering servers based on stratum, dispersion, and
+ * finally round-trip delay. */
+int best_offset_server(const ntp_server_results *slist, int nservers){
+ int cserver=0, best_server=-1;
+
+ /* for each server */
+ for(cserver=0; cserver<nservers; cserver++){
+ /* We don't want any servers that fails these tests */
+ /* Sort out servers that didn't respond or responede with a 0 stratum;
+ * stratum 0 is for reference clocks so no NTP server should ever report
+ * a stratum 0 */
+ if ( slist[cserver].stratum == 0){
+ if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
+ continue;
+ }
+ /* Sort out servers with error flags */
+ if ( LI(slist[cserver].flags) == LI_ALARM ){
+ if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
+ continue;
+ }
+
+ /* If we don't have a server yet, use the first one */
+ if (best_server == -1) {
+ best_server = cserver;
+ DBG(printf("using peer %d as our first candidate\n", best_server));
+ continue;
+ }
+
+ /* compare the server to the best one we've seen so far */
+ /* does it have an equal or better stratum? */
+ DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
+ if(slist[cserver].stratum <= slist[best_server].stratum){
+ DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
+ /* does it have an equal or better dispersion? */
+ if(slist[cserver].rtdisp <= slist[best_server].rtdisp){
+ DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
+ /* does it have a better rtdelay? */
+ if(slist[cserver].rtdelay < slist[best_server].rtdelay){
+ DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
+ best_server = cserver;
+ DBG(printf("peer %d is now our best candidate\n", best_server));
+ }
+ }
+ }
+ }
+
+ if(best_server >= 0) {
+ DBG(printf("best server selected: peer %d\n", best_server));
+ return best_server;
+ } else {
+ DBG(printf("no peers meeting synchronization criteria :(\n"));
+ return -1;
+ }
+}
+
+/* do everything we need to get the total average offset
+ * - we use a certain amount of parallelization with poll() to ensure
+ * we don't waste time sitting around waiting for single packets.
+ * - we also "manually" handle resolving host names and connecting, because
+ * we have to do it in a way that our lazy macros don't handle currently :( */
+double offset_request(const char *host, int *status){
+ int i=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
+ int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
+ time_t now_time=0, start_ts=0;
+ ntp_message *req=NULL;
+ double avg_offset=0.;
+ struct timeval recv_time;
+ struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
+ struct pollfd *ufds=NULL;
+ ntp_server_results *servers=NULL;
+
+ /* setup hints to only return results from getaddrinfo that we'd like */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = address_family;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* fill in ai with the list of hosts resolved by the host name */
+ ga_result = getaddrinfo(host, "123", &hints, &ai);
+ if(ga_result!=0){
+ die(STATE_UNKNOWN, "error getting address for %s: %s\n",
+ host, gai_strerror(ga_result));
+ }
+
+ /* count the number of returned hosts, and allocate stuff accordingly */
+ for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; }
+ req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts);
+ if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array");
+ socklist=(int*)malloc(sizeof(int)*num_hosts);
+ if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
+ ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts);
+ if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
+ servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts);
+ if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array");
+ memset(servers, 0, sizeof(ntp_server_results)*num_hosts);
+ DBG(printf("Found %d peers to check\n", num_hosts));
+
+ /* setup each socket for writing, and the corresponding struct pollfd */
+ ai_tmp=ai;
+ for(i=0;ai_tmp;i++){
+ socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+ if(socklist[i] == -1) {
+ perror(NULL);
+ die(STATE_UNKNOWN, "can not create new socket");
+ }
+ if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){
+ /* don't die here, because it is enough if there is one server
+ answering in time. This also would break for dual ipv4/6 stacked
+ ntp servers when the client only supports on of them.
+ */
+ DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
+ } else {
+ ufds[i].fd=socklist[i];
+ ufds[i].events=POLLIN;
+ ufds[i].revents=0;
+ }
+ ai_tmp = ai_tmp->ai_next;
+ }
+
+ /* now do AVG_NUM checks to each host. we stop before timeout/2 seconds
+ * have passed in order to ensure post-processing and jitter time. */
+ now_time=start_ts=time(NULL);
+ while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){
+ /* loop through each server and find each one which hasn't
+ * been touched in the past second or so and is still lacking
+ * some responses. for each of these servers, send a new request,
+ * and update the "waiting" timestamp with the current time. */
+ now_time=time(NULL);
+
+ for(i=0; i<num_hosts; i++){
+ if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){
+ if(verbose && servers[i].waiting != 0) printf("re-");
+ if(verbose) printf("sending request to peer %d\n", i);
+ setup_request(&req[i]);
+ write(socklist[i], &req[i], sizeof(ntp_message));
+ servers[i].waiting=now_time;
+ break;
+ }
+ }
+
+ /* quickly poll for any sockets with pending data */
+ servers_readable=poll(ufds, num_hosts, 100);
+ if(servers_readable==-1){
+ perror("polling ntp sockets");
+ die(STATE_UNKNOWN, "communication errors");
+ }
+
+ /* read from any sockets with pending data */
+ for(i=0; servers_readable && i<num_hosts; i++){
+ if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){
+ if(verbose) {
+ printf("response from peer %d: ", i);
+ }
+
+ read(ufds[i].fd, &req[i], sizeof(ntp_message));
+ gettimeofday(&recv_time, NULL);
+ DBG(print_ntp_message(&req[i]));
+ respnum=servers[i].num_responses++;
+ servers[i].offset[respnum]=calc_offset(&req[i], &recv_time);
+ if(verbose) {
+ printf("offset %.10g\n", servers[i].offset[respnum]);
+ }
+ servers[i].stratum=req[i].stratum;
+ servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp);
+ servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay);
+ servers[i].waiting=0;
+ servers[i].flags=req[i].flags;
+ servers_readable--;
+ one_read = 1;
+ if(servers[i].num_responses==AVG_NUM) servers_completed++;
+ }
+ }
+ /* lather, rinse, repeat. */
+ }
+
+ if (one_read == 0) {
+ die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
+ }
+
+ /* now, pick the best server from the list */
+ best_index=best_offset_server(servers, num_hosts);
+ if(best_index < 0){
+ *status=STATE_UNKNOWN;
+ } else {
+ /* finally, calculate the average offset */
+ for(i=0; i<servers[best_index].num_responses;i++){
+ avg_offset+=servers[best_index].offset[i];
+ }
+ avg_offset/=servers[best_index].num_responses;
+ }
+
+ /* cleanup */
+ /* FIXME: Not closing the socket to avoid reuse of the local port
+ * which can cause old NTP packets to be read instead of NTP control
+ * packets in jitter_request(). THERE MUST BE ANOTHER WAY...
+ * for(j=0; j<num_hosts; j++){ close(socklist[j]); } */
+ free(socklist);
+ free(ufds);
+ free(servers);
+ free(req);
+ freeaddrinfo(ai);
+
+ if(verbose) printf("overall average offset: %.10g\n", avg_offset);
+ return avg_offset;
+}
+
+void
+setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
+ memset(p, 0, sizeof(ntp_control_message));
+ LI_SET(p->flags, LI_NOWARNING);
+ VN_SET(p->flags, VN_RESERVED);
+ MODE_SET(p->flags, MODE_CONTROLMSG);
+ OP_SET(p->op, opcode);
+ p->seq = htons(seq);
+ /* Remaining fields are zero for requests */
+}
+
+/* XXX handle responses with the error bit set */
+double jitter_request(int *status){
+ int conn=-1, i, npeers=0, num_candidates=0, syncsource_found=0;
+ int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0;
+ int peers_size=0, peer_offset=0;
+ ntp_assoc_status_pair *peers=NULL;
+ ntp_control_message req;
+ const char *getvar = "jitter";
+ double rval = 0.0, jitter = -1.0;
+ char *startofvalue=NULL, *nptr=NULL;
+ void *tmp;
+
+ /* Long-winded explanation:
+ * Getting the jitter requires a number of steps:
+ * 1) Send a READSTAT request.
+ * 2) Interpret the READSTAT reply
+ * a) The data section contains a list of peer identifiers (16 bits)
+ * and associated status words (16 bits)
+ * b) We want the value of 0x06 in the SEL (peer selection) value,
+ * which means "current synchronizatin source". If that's missing,
+ * we take anything better than 0x04 (see the rfc for details) but
+ * set a minimum of warning.
+ * 3) Send a READVAR request for information on each peer identified
+ * in 2b greater than the minimum selection value.
+ * 4) Extract the jitter value from the data[] (it's ASCII)
+ */
+ my_udp_connect(server_address, 123, &conn);
+
+ /* keep sending requests until the server stops setting the
+ * REM_MORE bit, though usually this is only 1 packet. */
+ do{
+ setup_control_request(&req, OP_READSTAT, 1);
+ DBG(printf("sending READSTAT request"));
+ write(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+ /* Attempt to read the largest size packet possible */
+ req.count=htons(MAX_CM_SIZE);
+ DBG(printf("receiving READSTAT response"))
+ read(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+ /* Each peer identifier is 4 bytes in the data section, which
+ * we represent as a ntp_assoc_status_pair datatype.
+ */
+ peers_size+=ntohs(req.count);
+ if((tmp=realloc(peers, peers_size)) == NULL)
+ free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
+ peers=tmp;
+ memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count));
+ npeers=peers_size/sizeof(ntp_assoc_status_pair);
+ peer_offset+=ntohs(req.count);
+ } while(req.op&REM_MORE);
+
+ /* first, let's find out if we have a sync source, or if there are
+ * at least some candidates. in the case of the latter we'll issue
+ * a warning but go ahead with the check on them. */
+ for (i = 0; i < npeers; i++){
+ if (PEER_SEL(peers[i].status) >= PEER_INCLUDED){
+ num_candidates++;
+ if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){
+ syncsource_found=1;
+ min_peer_sel=PEER_SYNCSOURCE;
+ }
+ }
+ }
+ if(verbose) printf("%d candidate peers available\n", num_candidates);
+ if(verbose && syncsource_found) printf("synchronization source found\n");
+ if(! syncsource_found){
+ *status = STATE_UNKNOWN;
+ if(verbose) printf("warning: no synchronization source found\n");
+ }
+
+
+ for (run=0; run<AVG_NUM; run++){
+ if(verbose) printf("jitter run %d of %d\n", run+1, AVG_NUM);
+ for (i = 0; i < npeers; i++){
+ /* Only query this server if it is the current sync source */
+ if (PEER_SEL(peers[i].status) >= min_peer_sel){
+ char jitter_data[MAX_CM_SIZE+1];
+ size_t jitter_data_count;
+
+ num_selected++;
+ setup_control_request(&req, OP_READVAR, 2);
+ req.assoc = peers[i].assoc;
+ /* By spec, putting the variable name "jitter" in the request
+ * should cause the server to provide _only_ the jitter value.
+ * thus reducing net traffic, guaranteeing us only a single
+ * datagram in reply, and making interpretation much simpler
+ */
+ /* Older servers doesn't know what jitter is, so if we get an
+ * error on the first pass we redo it with "dispersion" */
+ strncpy(req.data, getvar, MAX_CM_SIZE-1);
+ req.count = htons(strlen(getvar));
+ DBG(printf("sending READVAR request...\n"));
+ write(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+
+ req.count = htons(MAX_CM_SIZE);
+ DBG(printf("receiving READVAR response...\n"));
+ read(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+
+ if(req.op&REM_ERROR && strstr(getvar, "jitter")) {
+ if(verbose) printf("The 'jitter' command failed (old ntp server?)\nRestarting with 'dispersion'...\n");
+ getvar = "dispersion";
+ num_selected--;
+ i--;
+ continue;
+ }
+
+ /* get to the float value */
+ if(verbose) {
+ printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc));
+ }
+ if((jitter_data_count = ntohs(req.count)) >= sizeof(jitter_data)){
+ die(STATE_UNKNOWN,
+ _("jitter response too large (%lu bytes)\n"),
+ (unsigned long)jitter_data_count);
+ }
+ memcpy(jitter_data, req.data, jitter_data_count);
+ jitter_data[jitter_data_count] = '\0';
+ startofvalue = strchr(jitter_data, '=');
+ if(startofvalue != NULL) {
+ startofvalue++;
+ jitter = strtod(startofvalue, &nptr);
+ }
+ if(startofvalue == NULL || startofvalue==nptr){
+ printf("warning: unable to read server jitter response.\n");
+ *status = STATE_UNKNOWN;
+ } else {
+ if(verbose) printf("%g\n", jitter);
+ num_valid++;
+ rval += jitter;
+ }
+ }
+ }
+ if(verbose){
+ printf("jitter parsed from %d/%d peers\n", num_valid, num_selected);
+ }
+ }
+
+ rval = num_valid ? rval / num_valid : -1.0;
+
+ close(conn);
+ if(peers!=NULL) free(peers);
+ /* If we return -1.0, it means no synchronization source was found */
+ return rval;
+}
+
+int process_arguments(int argc, char **argv){
+ int c;
+ int option=0;
+ static struct option longopts[] = {
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"jwarn", required_argument, 0, 'j'},
+ {"jcrit", required_argument, 0, 'k'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {0, 0, 0, 0}
+ };
+
+
+ if (argc < 2)
+ usage ("\n");
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vhv46w:c:j:k:t:H:", longopts, &option);
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(STATE_UNKNOWN);
+ break;
+ case 'V':
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'w':
+ do_offset=1;
+ owarn = optarg;
+ break;
+ case 'c':
+ do_offset=1;
+ ocrit = optarg;
+ break;
+ case 'j':
+ do_jitter=1;
+ jwarn = optarg;
+ break;
+ case 'k':
+ do_jitter=1;
+ jcrit = optarg;
+ break;
+ case 'H':
+ if(is_host(optarg) == FALSE)
+ usage2(_("Invalid hostname/address"), optarg);
+ server_address = strdup(optarg);
+ break;
+ case 't':
+ socket_timeout=atoi(optarg);
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case '?':
+ /* print short usage statement if args not parsable */
+ usage5 ();
+ break;
+ }
+ }
+
+ if(server_address == NULL){
+ usage4(_("Hostname was not supplied"));
+ }
+
+ return 0;
+}
+
+char *perfd_offset (double offset)
+{
+ return fperfdata ("offset", offset, "s",
+ TRUE, offset_thresholds->warning->end,
+ TRUE, offset_thresholds->critical->end,
+ FALSE, 0, FALSE, 0);
+}
+
+char *perfd_jitter (double jitter)
+{
+ return fperfdata ("jitter", jitter, "s",
+ do_jitter, jitter_thresholds->warning->end,
+ do_jitter, jitter_thresholds->critical->end,
+ TRUE, 0, FALSE, 0);
+}
+
+int main(int argc, char *argv[]){
+ int result, offset_result, jitter_result;
+ double offset=0, jitter=0;
+ char *result_line, *perfdata_line;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ result = offset_result = jitter_result = STATE_OK;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ set_thresholds(&offset_thresholds, owarn, ocrit);
+ set_thresholds(&jitter_thresholds, jwarn, jcrit);
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ offset = offset_request(server_address, &offset_result);
+ /* check_ntp used to always return CRITICAL if offset_result == STATE_UNKNOWN.
+ * Now we'll only do that is the offset thresholds were set */
+ if (do_offset && offset_result == STATE_UNKNOWN) {
+ result = STATE_CRITICAL;
+ } else {
+ result = get_status(fabs(offset), offset_thresholds);
+ }
+
+ /* If not told to check the jitter, we don't even send packets.
+ * jitter is checked using NTP control packets, which not all
+ * servers recognize. Trying to check the jitter on OpenNTPD
+ * (for example) will result in an error
+ */
+ if(do_jitter){
+ jitter=jitter_request(&jitter_result);
+ result = max_state_alt(result, get_status(jitter, jitter_thresholds));
+ /* -1 indicates that we couldn't calculate the jitter
+ * Only overrides STATE_OK from the offset */
+ if(jitter == -1.0 && result == STATE_OK)
+ result = STATE_UNKNOWN;
+ }
+ result = max_state_alt(result, jitter_result);
+
+ switch (result) {
+ case STATE_CRITICAL :
+ xasprintf(&result_line, _("NTP CRITICAL:"));
+ break;
+ case STATE_WARNING :
+ xasprintf(&result_line, _("NTP WARNING:"));
+ break;
+ case STATE_OK :
+ xasprintf(&result_line, _("NTP OK:"));
+ break;
+ default :
+ xasprintf(&result_line, _("NTP UNKNOWN:"));
+ break;
+ }
+ if(offset_result == STATE_UNKNOWN){
+ xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
+ xasprintf(&perfdata_line, "");
+ } else {
+ xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
+ xasprintf(&perfdata_line, "%s", perfd_offset(offset));
+ }
+ if (do_jitter) {
+ xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
+ xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
+ }
+ printf("%s|%s\n", result_line, perfdata_line);
+
+ if(server_address!=NULL) free(server_address);
+ return result;
+}
+
+
+
+void print_help(void){
+ print_revision(progname, NP_VERSION);
+
+ printf ("Copyright (c) 2006 Sean Finney\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin checks the selected ntp server"));
+
+ printf ("\n\n");
+
+ print_usage();
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (UT_HOST_PORT, 'p', "123");
+ printf (UT_IPv46);
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("Offset to result in warning status (seconds)"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("Offset to result in critical status (seconds)"));
+ printf (" %s\n", "-j, --jwarn=THRESHOLD");
+ printf (" %s\n", _("Warning threshold for jitter"));
+ printf (" %s\n", "-k, --jcrit=THRESHOLD");
+ printf (" %s\n", _("Critical threshold for jitter"));
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (UT_VERBOSE);
+
+ printf("\n");
+ printf("%s\n", _("Notes:"));
+ printf(UT_THRESHOLDS_NOTES);
+
+ printf("\n");
+ printf("%s\n", _("Examples:"));
+ printf(" %s\n", _("Normal offset check:"));
+ printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1"));
+ printf("\n");
+ printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available"));
+ printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
+ printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
+
+ printf (UT_SUPPORT);
+
+ printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
+ printf ("%s\n\n", _("check_ntp_time instead."));
+}
+
+void
+print_usage(void)
+{
+ printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
+ printf ("%s\n\n", _("check_ntp_time instead."));
+ printf ("%s\n", _("Usage:"));
+ printf(" %s -H <host> [-w <warn>] [-c <crit>] [-j <warn>] [-k <crit>] [-4|-6] [-v verbose]\n", progname);
+}
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
new file mode 100644
index 0000000..49cb100
--- /dev/null
+++ b/plugins/check_ntp_peer.c
@@ -0,0 +1,756 @@
+/*****************************************************************************
+*
+* Monitoring check_ntp_peer plugin
+*
+* License: GPL
+* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
+* Copyright (c) 2006-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ntp_peer plugin
+*
+* This plugin checks an NTP server independent of any commandline
+* programs or external libraries.
+*
+* Use this plugin to check the health of an NTP server. It supports
+* checking the offset with the sync peer, the jitter and stratum. This
+* plugin will not check the clock offset between the local host and NTP
+* server; please use check_ntp_time for that purpose.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ntp_peer";
+const char *copyright = "2006-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+static char *server_address=NULL;
+static int port=123;
+static int verbose=0;
+static int quiet=0;
+static short do_offset=0;
+static char *owarn="60";
+static char *ocrit="120";
+static short do_stratum=0;
+static char *swarn="-1:16";
+static char *scrit="-1:16";
+static short do_jitter=0;
+static char *jwarn="-1:5000";
+static char *jcrit="-1:10000";
+static short do_truechimers=0;
+static char *twarn="0:";
+static char *tcrit="0:";
+static int syncsource_found=0;
+static int li_alarm=0;
+
+int process_arguments (int, char **);
+thresholds *offset_thresholds = NULL;
+thresholds *jitter_thresholds = NULL;
+thresholds *stratum_thresholds = NULL;
+thresholds *truechimer_thresholds = NULL;
+void print_help (void);
+void print_usage (void);
+
+/* max size of control message data */
+#define MAX_CM_SIZE 468
+
+/* this structure holds everything in an ntp control message as per rfc1305 */
+typedef struct {
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+ uint8_t op; /* R,E,M bits and Opcode */
+ uint16_t seq; /* Packet sequence */
+ uint16_t status; /* Clock status */
+ uint16_t assoc; /* Association */
+ uint16_t offset; /* Similar to TCP sequence # */
+ uint16_t count; /* # bytes of data */
+ char data[MAX_CM_SIZE]; /* ASCII data of the request */
+ /* NB: not necessarily NULL terminated! */
+} ntp_control_message;
+
+/* this is an association/status-word pair found in control packet responses */
+typedef struct {
+ uint16_t assoc;
+ uint16_t status;
+} ntp_assoc_status_pair;
+
+/* bits 1,2 are the leap indicator */
+#define LI_MASK 0xc0
+#define LI(x) ((x&LI_MASK)>>6)
+#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0)
+/* and these are the values of the leap indicator */
+#define LI_NOWARNING 0x00
+#define LI_EXTRASEC 0x01
+#define LI_MISSINGSEC 0x02
+#define LI_ALARM 0x03
+/* bits 3,4,5 are the ntp version */
+#define VN_MASK 0x38
+#define VN(x) ((x&VN_MASK)>>3)
+#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0)
+#define VN_RESERVED 0x02
+/* bits 6,7,8 are the ntp mode */
+#define MODE_MASK 0x07
+#define MODE(x) (x&MODE_MASK)
+#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0)
+/* here are some values */
+#define MODE_CLIENT 0x03
+#define MODE_CONTROLMSG 0x06
+/* In control message, bits 8-10 are R,E,M bits */
+#define REM_MASK 0xe0
+#define REM_RESP 0x80
+#define REM_ERROR 0x40
+#define REM_MORE 0x20
+/* In control message, bits 11 - 15 are opcode */
+#define OP_MASK 0x1f
+#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0)
+#define OP_READSTAT 0x01
+#define OP_READVAR 0x02
+/* In peer status bytes, bits 6,7,8 determine clock selection status */
+#define PEER_SEL(x) ((ntohs(x)>>8)&0x07)
+#define PEER_TRUECHIMER 0x02
+#define PEER_INCLUDED 0x04
+#define PEER_SYNCSOURCE 0x06
+
+/* NTP control message header is 12 bytes, plus any data in the data
+ * field, plus null padding to the nearest 32-bit boundary per rfc.
+ */
+#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0))
+
+/* finally, a little helper or two for debugging: */
+#define DBG(x) do{if(verbose>1){ x; }}while(0);
+#define PRINTSOCKADDR(x) \
+ do{ \
+ printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\
+ }while(0);
+
+void print_ntp_control_message(const ntp_control_message *p){
+ int i=0, numpeers=0;
+ const ntp_assoc_status_pair *peer=NULL;
+
+ printf("control packet contents:\n");
+ printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
+ printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
+ printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
+ printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
+ printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP);
+ printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE);
+ printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR);
+ printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK);
+ printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
+ printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
+ printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
+ printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
+ printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
+ numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair));
+ if(p->op&REM_RESP && p->op&OP_READSTAT){
+ peer=(ntp_assoc_status_pair*)p->data;
+ for(i=0;i<numpeers;i++){
+ printf("\tpeer id %.2x status %.2x",
+ ntohs(peer[i].assoc), ntohs(peer[i].status));
+ if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){
+ printf(" <-- current sync source");
+ } else if(PEER_SEL(peer[i].status) >= PEER_INCLUDED){
+ printf(" <-- current sync candidate");
+ } else if(PEER_SEL(peer[i].status) >= PEER_TRUECHIMER){
+ printf(" <-- outlyer, but truechimer");
+ }
+ printf("\n");
+ }
+ }
+}
+
+void
+setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
+ memset(p, 0, sizeof(ntp_control_message));
+ LI_SET(p->flags, LI_NOWARNING);
+ VN_SET(p->flags, VN_RESERVED);
+ MODE_SET(p->flags, MODE_CONTROLMSG);
+ OP_SET(p->op, opcode);
+ p->seq = htons(seq);
+ /* Remaining fields are zero for requests */
+}
+
+/* This function does all the actual work; roughly here's what it does
+ * beside setting the offset, jitter and stratum passed as argument:
+ * - offset can be negative, so if it cannot get the offset, offset_result
+ * is set to UNKNOWN, otherwise OK.
+ * - jitter and stratum are set to -1 if they cannot be retrieved so any
+ * positive value means a success retrieving the value.
+ * - status is set to WARNING if there's no sync.peer (otherwise OK) and is
+ * the return value of the function.
+ * status is pretty much useless as syncsource_found is a global variable
+ * used later in main to check is the server was synchronized. It works
+ * so I left it alone */
+int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){
+ int conn=-1, i, npeers=0, num_candidates=0;
+ double tmp_offset = 0;
+ int min_peer_sel=PEER_INCLUDED;
+ int peers_size=0, peer_offset=0;
+ int status;
+ ntp_assoc_status_pair *peers=NULL;
+ ntp_control_message req;
+ const char *getvar = "stratum,offset,jitter";
+ char *data, *value, *nptr;
+ void *tmp;
+
+ status = STATE_OK;
+ *offset_result = STATE_UNKNOWN;
+ *jitter = *stratum = -1;
+ *num_truechimers = 0;
+
+ /* Long-winded explanation:
+ * Getting the sync peer offset, jitter and stratum requires a number of
+ * steps:
+ * 1) Send a READSTAT request.
+ * 2) Interpret the READSTAT reply
+ * a) The data section contains a list of peer identifiers (16 bits)
+ * and associated status words (16 bits)
+ * b) We want the value of 0x06 in the SEL (peer selection) value,
+ * which means "current synchronizatin source". If that's missing,
+ * we take anything better than 0x04 (see the rfc for details) but
+ * set a minimum of warning.
+ * 3) Send a READVAR request for information on each peer identified
+ * in 2b greater than the minimum selection value.
+ * 4) Extract the offset, jitter and stratum value from the data[]
+ * (it's ASCII)
+ */
+ my_udp_connect(server_address, port, &conn);
+
+ /* keep sending requests until the server stops setting the
+ * REM_MORE bit, though usually this is only 1 packet. */
+ do{
+ setup_control_request(&req, OP_READSTAT, 1);
+ DBG(printf("sending READSTAT request"));
+ write(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+
+ do {
+ /* Attempt to read the largest size packet possible */
+ req.count=htons(MAX_CM_SIZE);
+ DBG(printf("receiving READSTAT response"))
+ if(read(conn, &req, SIZEOF_NTPCM(req)) == -1)
+ die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
+ DBG(print_ntp_control_message(&req));
+ /* discard obviously invalid packets */
+ if (ntohs(req.count) > MAX_CM_SIZE)
+ die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
+ } while (!(req.op&OP_READSTAT && ntohs(req.seq) == 1));
+
+ if (LI(req.flags) == LI_ALARM) li_alarm = 1;
+ /* Each peer identifier is 4 bytes in the data section, which
+ * we represent as a ntp_assoc_status_pair datatype.
+ */
+ peers_size+=ntohs(req.count);
+ if((tmp=realloc(peers, peers_size)) == NULL)
+ free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
+ peers=tmp;
+ memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count));
+ npeers=peers_size/sizeof(ntp_assoc_status_pair);
+ peer_offset+=ntohs(req.count);
+ } while(req.op&REM_MORE);
+
+ /* first, let's find out if we have a sync source, or if there are
+ * at least some candidates. In the latter case we'll issue
+ * a warning but go ahead with the check on them. */
+ for (i = 0; i < npeers; i++){
+ if(PEER_SEL(peers[i].status) >= PEER_TRUECHIMER){
+ (*num_truechimers)++;
+ if(PEER_SEL(peers[i].status) >= PEER_INCLUDED){
+ num_candidates++;
+ if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){
+ syncsource_found=1;
+ min_peer_sel=PEER_SYNCSOURCE;
+ }
+ }
+ }
+ }
+ if(verbose) printf("%d candidate peers available\n", num_candidates);
+ if(verbose && syncsource_found) printf("synchronization source found\n");
+ if(! syncsource_found){
+ status = STATE_WARNING;
+ if(verbose) printf("warning: no synchronization source found\n");
+ }
+ if(li_alarm){
+ status = STATE_WARNING;
+ if(verbose) printf("warning: LI_ALARM bit is set\n");
+ }
+
+
+ for (i = 0; i < npeers; i++){
+ /* Only query this server if it is the current sync source */
+ /* If there's no sync.peer, query all candidates and use the best one */
+ if (PEER_SEL(peers[i].status) >= min_peer_sel){
+ if(verbose) printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
+ xasprintf(&data, "");
+ do{
+ setup_control_request(&req, OP_READVAR, 2);
+ req.assoc = peers[i].assoc;
+ /* Putting the wanted variable names in the request
+ * cause the server to provide _only_ the requested values.
+ * thus reducing net traffic, guaranteeing us only a single
+ * datagram in reply, and making interpretation much simpler
+ */
+ /* Older servers doesn't know what jitter is, so if we get an
+ * error on the first pass we redo it with "dispersion" */
+ strncpy(req.data, getvar, MAX_CM_SIZE-1);
+ req.count = htons(strlen(getvar));
+ DBG(printf("sending READVAR request...\n"));
+ write(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+
+ do {
+ req.count = htons(MAX_CM_SIZE);
+ DBG(printf("receiving READVAR response...\n"));
+ read(conn, &req, SIZEOF_NTPCM(req));
+ DBG(print_ntp_control_message(&req));
+ } while (!(req.op&OP_READVAR && ntohs(req.seq) == 2));
+
+ if(!(req.op&REM_ERROR))
+ xasprintf(&data, "%s%s", data, req.data);
+ } while(req.op&REM_MORE);
+
+ if(req.op&REM_ERROR) {
+ if(strstr(getvar, "jitter")) {
+ if(verbose) printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with 'dispersion'...\n");
+ getvar = "stratum,offset,dispersion";
+ i--;
+ continue;
+ } else if(strlen(getvar)) {
+ if(verbose) printf("Server didn't like dispersion either; will retrieve everything\n");
+ getvar = "";
+ i--;
+ continue;
+ }
+ }
+
+ if(verbose > 1)
+ printf("Server responded: >>>%s<<<\n", data);
+
+ /* get the offset */
+ if(verbose)
+ printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
+
+ value = np_extract_ntpvar(data, "offset");
+ nptr=NULL;
+ /* Convert the value if we have one */
+ if(value != NULL)
+ tmp_offset = strtod(value, &nptr) / 1000;
+ /* If value is null or no conversion was performed */
+ if(value == NULL || value==nptr) {
+ if(verbose) printf("error: unable to read server offset response.\n");
+ } else {
+ if(verbose) printf("%.10g\n", tmp_offset);
+ if(*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) {
+ *offset = tmp_offset;
+ *offset_result = STATE_OK;
+ } else {
+ /* Skip this one; move to the next */
+ continue;
+ }
+ }
+
+ if(do_jitter) {
+ /* get the jitter */
+ if(verbose) {
+ printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", ntohs(peers[i].assoc));
+ }
+ value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
+ nptr=NULL;
+ /* Convert the value if we have one */
+ if(value != NULL)
+ *jitter = strtod(value, &nptr);
+ /* If value is null or no conversion was performed */
+ if(value == NULL || value==nptr) {
+ if(verbose) printf("error: unable to read server jitter/dispersion response.\n");
+ *jitter = -1;
+ } else if(verbose) {
+ printf("%.10g\n", *jitter);
+ }
+ }
+
+ if(do_stratum) {
+ /* get the stratum */
+ if(verbose) {
+ printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
+ }
+ value = np_extract_ntpvar(data, "stratum");
+ nptr=NULL;
+ /* Convert the value if we have one */
+ if(value != NULL)
+ *stratum = strtol(value, &nptr, 10);
+ if(value == NULL || value==nptr) {
+ if(verbose) printf("error: unable to read server stratum response.\n");
+ *stratum = -1;
+ } else {
+ if(verbose) printf("%i\n", *stratum);
+ }
+ }
+ } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
+ } /* for (i = 0; i < npeers; i++) */
+
+ close(conn);
+ if(peers!=NULL) free(peers);
+
+ return status;
+}
+
+int process_arguments(int argc, char **argv){
+ int c;
+ int option=0;
+ static struct option longopts[] = {
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"quiet", no_argument, 0, 'q'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"swarn", required_argument, 0, 'W'},
+ {"scrit", required_argument, 0, 'C'},
+ {"jwarn", required_argument, 0, 'j'},
+ {"jcrit", required_argument, 0, 'k'},
+ {"twarn", required_argument, 0, 'm'},
+ {"tcrit", required_argument, 0, 'n'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'p'},
+ {0, 0, 0, 0}
+ };
+
+
+ if (argc < 2)
+ usage ("\n");
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(STATE_UNKNOWN);
+ break;
+ case 'V':
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'w':
+ do_offset=1;
+ owarn = optarg;
+ break;
+ case 'c':
+ do_offset=1;
+ ocrit = optarg;
+ break;
+ case 'W':
+ do_stratum=1;
+ swarn = optarg;
+ break;
+ case 'C':
+ do_stratum=1;
+ scrit = optarg;
+ break;
+ case 'j':
+ do_jitter=1;
+ jwarn = optarg;
+ break;
+ case 'k':
+ do_jitter=1;
+ jcrit = optarg;
+ break;
+ case 'm':
+ do_truechimers=1;
+ twarn = optarg;
+ break;
+ case 'n':
+ do_truechimers=1;
+ tcrit = optarg;
+ break;
+ case 'H':
+ if(is_host(optarg) == FALSE)
+ usage2(_("Invalid hostname/address"), optarg);
+ server_address = strdup(optarg);
+ break;
+ case 'p':
+ port=atoi(optarg);
+ break;
+ case 't':
+ socket_timeout=atoi(optarg);
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case '?':
+ /* print short usage statement if args not parsable */
+ usage5 ();
+ break;
+ }
+ }
+
+ if(server_address == NULL){
+ usage4(_("Hostname was not supplied"));
+ }
+
+ return 0;
+}
+
+char *perfd_offset (double offset)
+{
+ return fperfdata ("offset", offset, "s",
+ TRUE, offset_thresholds->warning->end,
+ TRUE, offset_thresholds->critical->end,
+ FALSE, 0, FALSE, 0);
+}
+
+char *perfd_jitter (double jitter)
+{
+ return fperfdata ("jitter", jitter, "",
+ do_jitter, jitter_thresholds->warning->end,
+ do_jitter, jitter_thresholds->critical->end,
+ TRUE, 0, FALSE, 0);
+}
+
+char *perfd_stratum (int stratum)
+{
+ return perfdata ("stratum", stratum, "",
+ do_stratum, (int)stratum_thresholds->warning->end,
+ do_stratum, (int)stratum_thresholds->critical->end,
+ TRUE, 0, TRUE, 16);
+}
+
+char *perfd_truechimers (int num_truechimers)
+{
+ return perfdata ("truechimers", num_truechimers, "",
+ do_truechimers, (int)truechimer_thresholds->warning->end,
+ do_truechimers, (int)truechimer_thresholds->critical->end,
+ TRUE, 0, FALSE, 0);
+}
+
+int main(int argc, char *argv[]){
+ int result, offset_result, stratum, num_truechimers, oresult, jresult, sresult, tresult;
+ double offset=0, jitter=0;
+ char *result_line, *perfdata_line;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ set_thresholds(&offset_thresholds, owarn, ocrit);
+ set_thresholds(&jitter_thresholds, jwarn, jcrit);
+ set_thresholds(&stratum_thresholds, swarn, scrit);
+ set_thresholds(&truechimer_thresholds, twarn, tcrit);
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ /* This returns either OK or WARNING (See comment preceding ntp_request) */
+ result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers);
+
+ if(offset_result == STATE_UNKNOWN) {
+ /* if there's no sync peer (this overrides ntp_request output): */
+ result = (quiet == 1 ? STATE_UNKNOWN : STATE_CRITICAL);
+ } else {
+ /* Be quiet if there's no candidates either */
+ if (quiet == 1 && result == STATE_WARNING)
+ result = STATE_UNKNOWN;
+ result = max_state_alt(result, get_status(fabs(offset), offset_thresholds));
+ }
+ oresult = result;
+
+ if(do_truechimers) {
+ tresult = get_status(num_truechimers, truechimer_thresholds);
+ result = max_state_alt(result, tresult);
+ }
+
+ if(do_stratum) {
+ sresult = get_status(stratum, stratum_thresholds);
+ result = max_state_alt(result, sresult);
+ }
+
+ if(do_jitter) {
+ jresult = get_status(jitter, jitter_thresholds);
+ result = max_state_alt(result, jresult);
+ }
+
+ switch (result) {
+ case STATE_CRITICAL :
+ xasprintf(&result_line, _("NTP CRITICAL:"));
+ break;
+ case STATE_WARNING :
+ xasprintf(&result_line, _("NTP WARNING:"));
+ break;
+ case STATE_OK :
+ xasprintf(&result_line, _("NTP OK:"));
+ break;
+ default :
+ xasprintf(&result_line, _("NTP UNKNOWN:"));
+ break;
+ }
+ if(!syncsource_found)
+ xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
+ else if(li_alarm)
+ xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
+
+ if(offset_result == STATE_UNKNOWN){
+ xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
+ xasprintf(&perfdata_line, "");
+ } else if (oresult == STATE_WARNING) {
+ xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset);
+ } else if (oresult == STATE_CRITICAL) {
+ xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset);
+ } else {
+ xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
+ }
+ xasprintf(&perfdata_line, "%s", perfd_offset(offset));
+
+ if (do_jitter) {
+ if (jresult == STATE_WARNING) {
+ xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter);
+ } else if (jresult == STATE_CRITICAL) {
+ xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter);
+ } else {
+ xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
+ }
+ xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
+ }
+ if (do_stratum) {
+ if (sresult == STATE_WARNING) {
+ xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum);
+ } else if (sresult == STATE_CRITICAL) {
+ xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum);
+ } else {
+ xasprintf(&result_line, "%s, stratum=%i", result_line, stratum);
+ }
+ xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum));
+ }
+ if (do_truechimers) {
+ if (tresult == STATE_WARNING) {
+ xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers);
+ } else if (tresult == STATE_CRITICAL) {
+ xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers);
+ } else {
+ xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
+ }
+ xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers));
+ }
+ printf("%s|%s\n", result_line, perfdata_line);
+
+ if(server_address!=NULL) free(server_address);
+ return result;
+}
+
+void print_help(void){
+ print_revision(progname, NP_VERSION);
+
+ printf ("Copyright (c) 2006 Sean Finney\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin checks the selected ntp server"));
+
+ printf ("\n\n");
+
+ print_usage();
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (UT_IPv46);
+ printf (UT_HOST_PORT, 'p', "123");
+ printf (" %s\n", "-q, --quiet");
+ printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized"));
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("Offset to result in warning status (seconds)"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("Offset to result in critical status (seconds)"));
+ printf (" %s\n", "-W, --swarn=THRESHOLD");
+ printf (" %s\n", _("Warning threshold for stratum of server's synchronization peer"));
+ printf (" %s\n", "-C, --scrit=THRESHOLD");
+ printf (" %s\n", _("Critical threshold for stratum of server's synchronization peer"));
+ printf (" %s\n", "-j, --jwarn=THRESHOLD");
+ printf (" %s\n", _("Warning threshold for jitter"));
+ printf (" %s\n", "-k, --jcrit=THRESHOLD");
+ printf (" %s\n", _("Critical threshold for jitter"));
+ printf (" %s\n", "-m, --twarn=THRESHOLD");
+ printf (" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")"));
+ printf (" %s\n", "-n, --tcrit=THRESHOLD");
+ printf (" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (UT_VERBOSE);
+
+ printf("\n");
+ printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));
+ printf("%s\n\n", _("programs or external libraries."));
+
+ printf("%s\n", _("Notes:"));
+ printf(" %s\n", _("Use this plugin to check the health of an NTP server. It supports"));
+ printf(" %s\n", _("checking the offset with the sync peer, the jitter and stratum. This"));
+ printf(" %s\n", _("plugin will not check the clock offset between the local host and NTP"));
+ printf(" %s\n", _("server; please use check_ntp_time for that purpose."));
+ printf("\n");
+ printf(UT_THRESHOLDS_NOTES);
+
+ printf("\n");
+ printf("%s\n", _("Examples:"));
+ printf(" %s\n", _("Simple NTP server check:"));
+ printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1"));
+ printf("\n");
+ printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available"));
+ printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
+ printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
+ printf("\n");
+ printf(" %s\n", _("Only check the number of usable time sources (\"truechimers\"):"));
+ printf(" %s\n", ("./check_ntp_peer -H ntpserv -m @5 -n @3"));
+ printf("\n");
+ printf(" %s\n", _("Check only stratum:"));
+ printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage(void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname);
+ printf(" [-j <warn>] [-k <crit>] [-v verbose]\n");
+}
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
new file mode 100644
index 0000000..46cc604
--- /dev/null
+++ b/plugins/check_ntp_time.c
@@ -0,0 +1,654 @@
+/*****************************************************************************
+*
+* Monitoring check_ntp_time plugin
+*
+* License: GPL
+* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
+* Copyright (c) 2006-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ntp_time plugin
+*
+* This plugin checks the clock offset between the local host and a
+* remote NTP server. It is independent of any commandline programs or
+* external libraries.
+*
+* If you'd rather want to monitor an NTP server, please use
+* check_ntp_peer.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ntp_time";
+const char *copyright = "2006-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+static char *server_address=NULL;
+static char *port="123";
+static int verbose=0;
+static int quiet=0;
+static char *owarn="60";
+static char *ocrit="120";
+static int time_offset=0;
+
+int process_arguments (int, char **);
+thresholds *offset_thresholds = NULL;
+void print_help (void);
+void print_usage (void);
+
+/* number of times to perform each request to get a good average. */
+#ifndef AVG_NUM
+#define AVG_NUM 4
+#endif
+
+/* max size of control message data */
+#define MAX_CM_SIZE 468
+
+/* this structure holds everything in an ntp request/response as per rfc1305 */
+typedef struct {
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+ uint8_t stratum; /* clock stratum */
+ int8_t poll; /* polling interval */
+ int8_t precision; /* precision of the local clock */
+ int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
+ uint32_t rtdisp; /* like above, but for max err to primary src */
+ uint32_t refid; /* ref clock identifier */
+ uint64_t refts; /* reference timestamp. local time local clock */
+ uint64_t origts; /* time at which request departed client */
+ uint64_t rxts; /* time at which request arrived at server */
+ uint64_t txts; /* time at which request departed server */
+} ntp_message;
+
+/* this structure holds data about results from querying offset from a peer */
+typedef struct {
+ time_t waiting; /* ts set when we started waiting for a response */
+ int num_responses; /* number of successfully received responses */
+ uint8_t stratum; /* copied verbatim from the ntp_message */
+ double rtdelay; /* converted from the ntp_message */
+ double rtdisp; /* converted from the ntp_message */
+ double offset[AVG_NUM]; /* offsets from each response */
+ uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
+} ntp_server_results;
+
+/* bits 1,2 are the leap indicator */
+#define LI_MASK 0xc0
+#define LI(x) ((x&LI_MASK)>>6)
+#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0)
+/* and these are the values of the leap indicator */
+#define LI_NOWARNING 0x00
+#define LI_EXTRASEC 0x01
+#define LI_MISSINGSEC 0x02
+#define LI_ALARM 0x03
+/* bits 3,4,5 are the ntp version */
+#define VN_MASK 0x38
+#define VN(x) ((x&VN_MASK)>>3)
+#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0)
+#define VN_RESERVED 0x02
+/* bits 6,7,8 are the ntp mode */
+#define MODE_MASK 0x07
+#define MODE(x) (x&MODE_MASK)
+#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0)
+/* here are some values */
+#define MODE_CLIENT 0x03
+#define MODE_CONTROLMSG 0x06
+/* In control message, bits 8-10 are R,E,M bits */
+#define REM_MASK 0xe0
+#define REM_RESP 0x80
+#define REM_ERROR 0x40
+#define REM_MORE 0x20
+/* In control message, bits 11 - 15 are opcode */
+#define OP_MASK 0x1f
+#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0)
+#define OP_READSTAT 0x01
+#define OP_READVAR 0x02
+/* In peer status bytes, bits 6,7,8 determine clock selection status */
+#define PEER_SEL(x) ((ntohs(x)>>8)&0x07)
+#define PEER_INCLUDED 0x04
+#define PEER_SYNCSOURCE 0x06
+
+/**
+ ** a note about the 32-bit "fixed point" numbers:
+ **
+ they are divided into halves, each being a 16-bit int in network byte order:
+ - the first 16 bits are an int on the left side of a decimal point.
+ - the second 16 bits represent a fraction n/(2^16)
+ likewise for the 64-bit "fixed point" numbers with everything doubled :)
+ **/
+
+/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
+ number. note that these can be used as lvalues too */
+#define L16(x) (((uint16_t*)&x)[0])
+#define R16(x) (((uint16_t*)&x)[1])
+/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
+ number. these too can be used as lvalues */
+#define L32(x) (((uint32_t*)&x)[0])
+#define R32(x) (((uint32_t*)&x)[1])
+
+/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
+#define EPOCHDIFF 0x83aa7e80UL
+
+/* extract a 32-bit ntp fixed point number into a double */
+#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)
+
+/* likewise for a 64-bit ntp fp number */
+#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\
+ (ntohl(L32(n))-EPOCHDIFF) + \
+ (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
+ 0)
+
+/* convert a struct timeval to a double */
+#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec))
+
+/* convert an ntp 64-bit fp number to a struct timeval */
+#define NTP64toTV(n,t) \
+ do{ if(!n) t.tv_sec = t.tv_usec = 0; \
+ else { \
+ t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \
+ t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \
+ } \
+ }while(0)
+
+/* convert a struct timeval to an ntp 64-bit fp number */
+#define TVtoNTP64(t,n) \
+ do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \
+ else { \
+ L32(n)=htonl(t.tv_sec + EPOCHDIFF); \
+ R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \
+ } \
+ } while(0)
+
+/* NTP control message header is 12 bytes, plus any data in the data
+ * field, plus null padding to the nearest 32-bit boundary per rfc.
+ */
+#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0))
+
+/* finally, a little helper or two for debugging: */
+#define DBG(x) do{if(verbose>1){ x; }}while(0);
+#define PRINTSOCKADDR(x) \
+ do{ \
+ printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\
+ }while(0);
+
+/* calculate the offset of the local clock */
+static inline double calc_offset(const ntp_message *m, const struct timeval *t){
+ double client_tx, peer_rx, peer_tx, client_rx;
+ client_tx = NTP64asDOUBLE(m->origts);
+ peer_rx = NTP64asDOUBLE(m->rxts);
+ peer_tx = NTP64asDOUBLE(m->txts);
+ client_rx=TVasDOUBLE((*t));
+ return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
+}
+
+/* print out a ntp packet in human readable/debuggable format */
+void print_ntp_message(const ntp_message *p){
+ struct timeval ref, orig, rx, tx;
+
+ NTP64toTV(p->refts,ref);
+ NTP64toTV(p->origts,orig);
+ NTP64toTV(p->rxts,rx);
+ NTP64toTV(p->txts,tx);
+
+ printf("packet contents:\n");
+ printf("\tflags: 0x%.2x\n", p->flags);
+ printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
+ printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
+ printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
+ printf("\tstratum = %d\n", p->stratum);
+ printf("\tpoll = %g\n", pow(2, p->poll));
+ printf("\tprecision = %g\n", pow(2, p->precision));
+ printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
+ printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
+ printf("\trefid = %x\n", p->refid);
+ printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
+ printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
+ printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
+ printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
+}
+
+void setup_request(ntp_message *p){
+ struct timeval t;
+
+ memset(p, 0, sizeof(ntp_message));
+ LI_SET(p->flags, LI_ALARM);
+ VN_SET(p->flags, 4);
+ MODE_SET(p->flags, MODE_CLIENT);
+ p->poll=4;
+ p->precision=(int8_t)0xfa;
+ L16(p->rtdelay)=htons(1);
+ L16(p->rtdisp)=htons(1);
+
+ gettimeofday(&t, NULL);
+ TVtoNTP64(t,p->txts);
+}
+
+/* select the "best" server from a list of servers, and return its index.
+ * this is done by filtering servers based on stratum, dispersion, and
+ * finally round-trip delay. */
+int best_offset_server(const ntp_server_results *slist, int nservers){
+ int cserver=0, best_server=-1;
+
+ /* for each server */
+ for(cserver=0; cserver<nservers; cserver++){
+ /* We don't want any servers that fails these tests */
+ /* Sort out servers that didn't respond or responede with a 0 stratum;
+ * stratum 0 is for reference clocks so no NTP server should ever report
+ * a stratum 0 */
+ if ( slist[cserver].stratum == 0){
+ if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
+ continue;
+ }
+ /* Sort out servers with error flags */
+ if ( LI(slist[cserver].flags) == LI_ALARM ){
+ if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
+ continue;
+ }
+
+ /* If we don't have a server yet, use the first one */
+ if (best_server == -1) {
+ best_server = cserver;
+ DBG(printf("using peer %d as our first candidate\n", best_server));
+ continue;
+ }
+
+ /* compare the server to the best one we've seen so far */
+ /* does it have an equal or better stratum? */
+ DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
+ if(slist[cserver].stratum <= slist[best_server].stratum){
+ DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
+ /* does it have an equal or better dispersion? */
+ if(slist[cserver].rtdisp <= slist[best_server].rtdisp){
+ DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
+ /* does it have a better rtdelay? */
+ if(slist[cserver].rtdelay < slist[best_server].rtdelay){
+ DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
+ best_server = cserver;
+ DBG(printf("peer %d is now our best candidate\n", best_server));
+ }
+ }
+ }
+ }
+
+ if(best_server >= 0) {
+ DBG(printf("best server selected: peer %d\n", best_server));
+ return best_server;
+ } else {
+ DBG(printf("no peers meeting synchronization criteria :(\n"));
+ return -1;
+ }
+}
+
+/* do everything we need to get the total average offset
+ * - we use a certain amount of parallelization with poll() to ensure
+ * we don't waste time sitting around waiting for single packets.
+ * - we also "manually" handle resolving host names and connecting, because
+ * we have to do it in a way that our lazy macros don't handle currently :( */
+double offset_request(const char *host, int *status){
+ int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
+ int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
+ time_t now_time=0, start_ts=0;
+ ntp_message *req=NULL;
+ double avg_offset=0.;
+ struct timeval recv_time;
+ struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
+ struct pollfd *ufds=NULL;
+ ntp_server_results *servers=NULL;
+
+ /* setup hints to only return results from getaddrinfo that we'd like */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = address_family;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* fill in ai with the list of hosts resolved by the host name */
+ ga_result = getaddrinfo(host, port, &hints, &ai);
+ if(ga_result!=0){
+ die(STATE_UNKNOWN, "error getting address for %s: %s\n",
+ host, gai_strerror(ga_result));
+ }
+
+ /* count the number of returned hosts, and allocate stuff accordingly */
+ for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; }
+ req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts);
+ if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array");
+ socklist=(int*)malloc(sizeof(int)*num_hosts);
+ if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
+ ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts);
+ if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
+ servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts);
+ if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array");
+ memset(servers, 0, sizeof(ntp_server_results)*num_hosts);
+ DBG(printf("Found %d peers to check\n", num_hosts));
+
+ /* setup each socket for writing, and the corresponding struct pollfd */
+ ai_tmp=ai;
+ for(i=0;ai_tmp;i++){
+ socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+ if(socklist[i] == -1) {
+ perror(NULL);
+ die(STATE_UNKNOWN, "can not create new socket");
+ }
+ if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){
+ /* don't die here, because it is enough if there is one server
+ answering in time. This also would break for dual ipv4/6 stacked
+ ntp servers when the client only supports on of them.
+ */
+ DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
+ } else {
+ ufds[i].fd=socklist[i];
+ ufds[i].events=POLLIN;
+ ufds[i].revents=0;
+ }
+ ai_tmp = ai_tmp->ai_next;
+ }
+
+ /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
+ * have passed in order to ensure post-processing and jitter time. */
+ now_time=start_ts=time(NULL);
+ while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){
+ /* loop through each server and find each one which hasn't
+ * been touched in the past second or so and is still lacking
+ * some responses. For each of these servers, send a new request,
+ * and update the "waiting" timestamp with the current time. */
+ now_time=time(NULL);
+
+ for(i=0; i<num_hosts; i++){
+ if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){
+ if(verbose && servers[i].waiting != 0) printf("re-");
+ if(verbose) printf("sending request to peer %d\n", i);
+ setup_request(&req[i]);
+ write(socklist[i], &req[i], sizeof(ntp_message));
+ servers[i].waiting=now_time;
+ break;
+ }
+ }
+
+ /* quickly poll for any sockets with pending data */
+ servers_readable=poll(ufds, num_hosts, 100);
+ if(servers_readable==-1){
+ perror("polling ntp sockets");
+ die(STATE_UNKNOWN, "communication errors");
+ }
+
+ /* read from any sockets with pending data */
+ for(i=0; servers_readable && i<num_hosts; i++){
+ if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){
+ if(verbose) {
+ printf("response from peer %d: ", i);
+ }
+
+ read(ufds[i].fd, &req[i], sizeof(ntp_message));
+ gettimeofday(&recv_time, NULL);
+ DBG(print_ntp_message(&req[i]));
+ respnum=servers[i].num_responses++;
+ servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset;
+ if(verbose) {
+ printf("offset %.10g\n", servers[i].offset[respnum]);
+ }
+ servers[i].stratum=req[i].stratum;
+ servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp);
+ servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay);
+ servers[i].waiting=0;
+ servers[i].flags=req[i].flags;
+ servers_readable--;
+ one_read = 1;
+ if(servers[i].num_responses==AVG_NUM) servers_completed++;
+ }
+ }
+ /* lather, rinse, repeat. */
+ }
+
+ if (one_read == 0) {
+ die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
+ }
+
+ /* now, pick the best server from the list */
+ best_index=best_offset_server(servers, num_hosts);
+ if(best_index < 0){
+ *status=STATE_UNKNOWN;
+ } else {
+ /* finally, calculate the average offset */
+ for(i=0; i<servers[best_index].num_responses;i++){
+ avg_offset+=servers[best_index].offset[i];
+ }
+ avg_offset/=servers[best_index].num_responses;
+ }
+
+ /* cleanup */
+ for(j=0; j<num_hosts; j++){ close(socklist[j]); }
+ free(socklist);
+ free(ufds);
+ free(servers);
+ free(req);
+ freeaddrinfo(ai);
+
+ if(verbose) printf("overall average offset: %.10g\n", avg_offset);
+ return avg_offset;
+}
+
+int process_arguments(int argc, char **argv){
+ int c;
+ int option=0;
+ static struct option longopts[] = {
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"quiet", no_argument, 0, 'q'},
+ {"time-offset", optional_argument, 0, 'o'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"timeout", required_argument, 0, 't'},
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'p'},
+ {0, 0, 0, 0}
+ };
+
+
+ if (argc < 2)
+ usage ("\n");
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(STATE_UNKNOWN);
+ break;
+ case 'V':
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'w':
+ owarn = optarg;
+ break;
+ case 'c':
+ ocrit = optarg;
+ break;
+ case 'H':
+ if(is_host(optarg) == FALSE)
+ usage2(_("Invalid hostname/address"), optarg);
+ server_address = strdup(optarg);
+ break;
+ case 'p':
+ port = strdup(optarg);
+ break;
+ case 't':
+ socket_timeout=atoi(optarg);
+ break;
+ case 'o':
+ time_offset=atoi(optarg);
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case '?':
+ /* print short usage statement if args not parsable */
+ usage5 ();
+ break;
+ }
+ }
+
+ if(server_address == NULL){
+ usage4(_("Hostname was not supplied"));
+ }
+
+ return 0;
+}
+
+char *perfd_offset (double offset)
+{
+ return fperfdata ("offset", offset, "s",
+ TRUE, offset_thresholds->warning->end,
+ TRUE, offset_thresholds->critical->end,
+ FALSE, 0, FALSE, 0);
+}
+
+int main(int argc, char *argv[]){
+ int result, offset_result;
+ double offset=0;
+ char *result_line, *perfdata_line;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ result = offset_result = STATE_OK;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ set_thresholds(&offset_thresholds, owarn, ocrit);
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ offset = offset_request(server_address, &offset_result);
+ if (offset_result == STATE_UNKNOWN) {
+ result = (quiet == 1 ? STATE_UNKNOWN : STATE_CRITICAL);
+ } else {
+ result = get_status(fabs(offset), offset_thresholds);
+ }
+
+ switch (result) {
+ case STATE_CRITICAL :
+ xasprintf(&result_line, _("NTP CRITICAL:"));
+ break;
+ case STATE_WARNING :
+ xasprintf(&result_line, _("NTP WARNING:"));
+ break;
+ case STATE_OK :
+ xasprintf(&result_line, _("NTP OK:"));
+ break;
+ default :
+ xasprintf(&result_line, _("NTP UNKNOWN:"));
+ break;
+ }
+ if(offset_result == STATE_UNKNOWN){
+ xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
+ xasprintf(&perfdata_line, "");
+ } else {
+ xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
+ xasprintf(&perfdata_line, "%s", perfd_offset(offset));
+ }
+ printf("%s|%s\n", result_line, perfdata_line);
+
+ if(server_address!=NULL) free(server_address);
+ return result;
+}
+
+void print_help(void){
+ print_revision(progname, NP_VERSION);
+
+ printf ("Copyright (c) 2006 Sean Finney\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin checks the clock offset with the ntp server"));
+
+ printf ("\n\n");
+
+ print_usage();
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (UT_IPv46);
+ printf (UT_HOST_PORT, 'p', "123");
+ printf (" %s\n", "-q, --quiet");
+ printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("Offset to result in warning status (seconds)"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("Offset to result in critical status (seconds)"));
+ printf (" %s\n", "-o, --time_offset=INTEGER");
+ printf (" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (UT_VERBOSE);
+
+ printf("\n");
+ printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
+ printf("%s\n", _("remote NTP server. It is independent of any commandline programs or"));
+ printf("%s\n", _("external libraries."));
+
+ printf("\n");
+ printf("%s\n", _("Notes:"));
+ printf(" %s\n", _("If you'd rather want to monitor an NTP server, please use"));
+ printf(" %s\n", _("check_ntp_peer."));
+ printf(" %s\n", _("--time-offset is useful for compensating for servers with known"));
+ printf(" %s\n", _("and expected clock skew."));
+ printf("\n");
+ printf(UT_THRESHOLDS_NOTES);
+
+ printf("\n");
+ printf("%s\n", _("Examples:"));
+ printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage(void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
+}
+
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
new file mode 100644
index 0000000..3c9d23e
--- /dev/null
+++ b/plugins/check_nwstat.c
@@ -0,0 +1,1687 @@
+/*****************************************************************************
+*
+* Monitoring check_nwstat plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_nwstat plugin
+*
+* This plugin attempts to contact the MRTGEXT NLM running on a
+* Novell server to gather the requested system information.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_nwstat";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum checkvar {
+ NONE,
+ LOAD1, /* check 1 minute CPU load */
+ LOAD5, /* check 5 minute CPU load */
+ LOAD15, /* check 15 minute CPU load */
+ CONNS, /* check number of connections */
+ VPF, /* check % free space on volume */
+ VMF, /* check MB free space on volume */
+ VMU, /* check MB used space on volume */
+ VMP, /* check MB purgeable space on volume */
+ VKF, /* check KB free space on volume */
+ LTCH, /* check long-term cache hit percentage */
+ CBUFF, /* check total cache buffers */
+ CDBUFF, /* check dirty cache buffers */
+ LRUM, /* check LRU sitting time in minutes */
+ DSDB, /* check to see if DS Database is open */
+ LOGINS, /* check to see if logins are enabled */
+ NRMH, /* check to see NRM Health Status */
+ PUPRB, /* check % of used packet receive buffers */
+ UPRB, /* check used packet receive buffers */
+ SAPENTRIES, /* check SAP entries */
+ OFILES, /* check number of open files */
+ VKP, /* check KB purgeable space on volume */
+ VPP, /* check % purgeable space on volume */
+ VKNP, /* check KB not yet purgeable space on volume */
+ VPNP, /* check % not yet purgeable space on volume */
+ ABENDS, /* check abended thread count */
+ CSPROCS, /* check number of current service processes */
+ TSYNC, /* check timesync status 0=no 1=yes in sync to the network */
+ LRUS, /* check LRU sitting time in seconds */
+ DCB, /* check dirty cache buffers as a percentage of the total */
+ TCB, /* check total cache buffers as a percentage of the original */
+ DSVER, /* check NDS version */
+ UPTIME, /* check server uptime */
+ NLM, /* check NLM loaded */
+ NRMP, /* check NRM Process Values */
+ NRMM, /* check NRM Memory Values */
+ NRMS, /* check NRM Values */
+ NSS1, /* check Statistics from _Admin:Manage_NSS\GeneralStats.xml */
+ NSS2, /* check Statistics from _Admin:Manage_NSS\BufferCache.xml */
+ NSS3, /* check statistics from _Admin:Manage_NSS\NameCache.xml */
+ NSS4, /* check statistics from _Admin:Manage_NSS\FileStats.xml */
+ NSS5, /* check statistics from _Admin:Manage_NSS\ObjectCache.xml */
+ NSS6, /* check statistics from _Admin:Manage_NSS\Thread.xml */
+ NSS7 /* check statistics from _Admin:Manage_NSS\AuthorizationCache.xml */
+};
+
+enum {
+ PORT = 9999
+};
+
+char *server_address=NULL;
+char *volume_name=NULL;
+char *nlm_name=NULL;
+char *nrmp_name=NULL;
+char *nrmm_name=NULL;
+char *nrms_name=NULL;
+char *nss1_name=NULL;
+char *nss2_name=NULL;
+char *nss3_name=NULL;
+char *nss4_name=NULL;
+char *nss5_name=NULL;
+char *nss6_name=NULL;
+char *nss7_name=NULL;
+int server_port=PORT;
+unsigned long warning_value=0L;
+unsigned long critical_value=0L;
+int check_warning_value=FALSE;
+int check_critical_value=FALSE;
+int check_netware_version=FALSE;
+enum checkvar vars_to_check = NONE;
+int sap_number=-1;
+
+int process_arguments(int, char **);
+void print_help(void);
+void print_usage(void);
+
+
+
+int
+main(int argc, char **argv) {
+ int result = STATE_UNKNOWN;
+ int sd;
+ char *send_buffer=NULL;
+ char recv_buffer[MAX_INPUT_BUFFER];
+ char *output_message=NULL;
+ char *temp_buffer=NULL;
+ char *netware_version=NULL;
+
+ int time_sync_status=0;
+ int nrm_health_status=0;
+ unsigned long total_cache_buffers=0;
+ unsigned long dirty_cache_buffers=0;
+ unsigned long open_files=0;
+ unsigned long abended_threads=0;
+ unsigned long max_service_processes=0;
+ unsigned long current_service_processes=0;
+ unsigned long free_disk_space=0L;
+ unsigned long nrmp_value=0L;
+ unsigned long nrmm_value=0L;
+ unsigned long nrms_value=0L;
+ unsigned long nss1_value=0L;
+ unsigned long nss2_value=0L;
+ unsigned long nss3_value=0L;
+ unsigned long nss4_value=0L;
+ unsigned long nss5_value=0L;
+ unsigned long nss6_value=0L;
+ unsigned long nss7_value=0L;
+ unsigned long total_disk_space=0L;
+ unsigned long purgeable_disk_space=0L;
+ unsigned long non_purgeable_disk_space=0L;
+ unsigned long percent_free_space=0;
+ unsigned long percent_purgeable_space=0;
+ unsigned long percent_non_purgeable_space=0;
+ unsigned long current_connections=0L;
+ unsigned long utilization=0L;
+ unsigned long cache_hits=0;
+ unsigned long cache_buffers=0L;
+ unsigned long lru_time=0L;
+ unsigned long max_packet_receive_buffers=0;
+ unsigned long used_packet_receive_buffers=0;
+ unsigned long percent_used_packet_receive_buffers=0L;
+ unsigned long sap_entries=0;
+ char uptime[MAX_INPUT_BUFFER];
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts(&argc, argv, progname);
+
+ if (process_arguments(argc,argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal(SIGALRM,socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm(socket_timeout);
+
+ /* open connection */
+ my_tcp_connect (server_address, server_port, &sd);
+
+ /* get OS version string */
+ if (check_netware_version==TRUE) {
+ send_buffer = strdup ("S19\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ if (!strcmp(recv_buffer,"-1\n"))
+ netware_version = strdup("");
+ else {
+ recv_buffer[strlen(recv_buffer)-1]=0;
+ xasprintf (&netware_version,_("NetWare %s: "),recv_buffer);
+ }
+ } else
+ netware_version = strdup("");
+
+
+ /* check CPU load */
+ if (vars_to_check==LOAD1 || vars_to_check==LOAD5 || vars_to_check==LOAD15) {
+
+ switch(vars_to_check) {
+ case LOAD1:
+ temp_buffer = strdup ("1");
+ break;
+ case LOAD5:
+ temp_buffer = strdup ("5");
+ break;
+ default:
+ temp_buffer = strdup ("15");
+ break;
+ }
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"UTIL%s\r\n",temp_buffer);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ utilization=strtoul(recv_buffer,NULL,10);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("UPTIME\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ recv_buffer[strlen(recv_buffer)-1]=0;
+ sprintf(uptime,_("Up %s,"),recv_buffer);
+
+ if (check_critical_value==TRUE && utilization >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && utilization >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("Load %s - %s %s-min load average = %lu%%|load%s=%lu;%lu;%lu;0;100"),
+ state_text(result),
+ uptime,
+ temp_buffer,
+ utilization,
+ temp_buffer,
+ utilization,
+ warning_value,
+ critical_value);
+
+ /* check number of user connections */
+ } else if (vars_to_check==CONNS) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("CONNECT\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ current_connections=strtoul(recv_buffer,NULL,10);
+
+ if (check_critical_value==TRUE && current_connections >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && current_connections >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("Conns %s - %lu current connections|Conns=%lu;%lu;%lu;;"),
+ state_text(result),
+ current_connections,
+ current_connections,
+ warning_value,
+ critical_value);
+
+ /* check % long term cache hits */
+ } else if (vars_to_check==LTCH) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S1\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ cache_hits=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && cache_hits <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && cache_hits <= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("%s: Long term cache hits = %lu%%"),
+ state_text(result),
+ cache_hits);
+
+ /* check cache buffers */
+ } else if (vars_to_check==CBUFF) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S2\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ cache_buffers=strtoul(recv_buffer,NULL,10);
+
+ if (check_critical_value==TRUE && cache_buffers <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && cache_buffers <= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("%s: Total cache buffers = %lu|Cachebuffers=%lu;%lu;%lu;;"),
+ state_text(result),
+ cache_buffers,
+ cache_buffers,
+ warning_value,
+ critical_value);
+
+ /* check dirty cache buffers */
+ } else if (vars_to_check==CDBUFF) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S3\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ cache_buffers=strtoul(recv_buffer,NULL,10);
+
+ if (check_critical_value==TRUE && cache_buffers >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && cache_buffers >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("%s: Dirty cache buffers = %lu|Dirty-Cache-Buffers=%lu;%lu;%lu;;"),
+ state_text(result),
+ cache_buffers,
+ cache_buffers,
+ warning_value,
+ critical_value);
+
+ /* check LRU sitting time in minutes */
+ } else if (vars_to_check==LRUM) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S5\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ lru_time=strtoul(recv_buffer,NULL,10);
+
+ if (check_critical_value==TRUE && lru_time <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && lru_time <= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("%s: LRU sitting time = %lu minutes"),
+ state_text(result),
+ lru_time);
+
+
+ /* check KB free space on volume */
+ } else if (vars_to_check==VKF) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ free_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && free_disk_space <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && free_disk_space <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s%lu KB free on volume %s|KBFree%s=%lu;%lu;%lu;;"),
+ (result==STATE_OK)?"":_("Only "),
+ free_disk_space,
+ volume_name,
+ volume_name,
+ free_disk_space,
+ warning_value,
+ critical_value);
+ }
+
+ /* check MB free space on volume */
+ } else if (vars_to_check==VMF) {
+
+ xasprintf (&send_buffer,"VMF%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ free_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && free_disk_space <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && free_disk_space <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s%lu MB free on volume %s|MBFree%s=%lu;%lu;%lu;;"),
+ (result==STATE_OK)?"":_("Only "),
+ free_disk_space,
+ volume_name,
+ volume_name,
+ free_disk_space,
+ warning_value,
+ critical_value);
+ }
+ /* check MB used space on volume */
+ } else if (vars_to_check==VMU) {
+
+ xasprintf (&send_buffer,"VMU%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ free_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && free_disk_space <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && free_disk_space <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s%lu MB used on volume %s|MBUsed%s=%lu;%lu;%lu;;"),
+ (result==STATE_OK)?"":_("Only "),
+ free_disk_space,
+ volume_name,
+ volume_name,
+ free_disk_space,
+ warning_value,
+ critical_value);
+ }
+
+
+ /* check % free space on volume */
+ } else if (vars_to_check==VPF) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+
+ } else {
+
+ free_disk_space=strtoul(recv_buffer,NULL,10);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ total_disk_space=strtoul(recv_buffer,NULL,10);
+
+ percent_free_space=(unsigned long)(((double)free_disk_space/(double)total_disk_space)*100.0);
+
+ if (check_critical_value==TRUE && percent_free_space <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_free_space <= warning_value)
+ result=STATE_WARNING;
+ free_disk_space/=1024;
+ total_disk_space/=1024;
+ xasprintf (&output_message,_("%lu MB (%lu%%) free on volume %s - total %lu MB|FreeMB%s=%lu;%lu;%lu;0;100"),
+ free_disk_space,
+ percent_free_space,
+ volume_name,
+ total_disk_space,
+ volume_name,
+ percent_free_space,
+ warning_value,
+ critical_value
+ );
+ }
+
+ /* check to see if DS Database is open or closed */
+ } else if (vars_to_check==DSDB) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S11\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ if (atoi(recv_buffer)==1)
+ result=STATE_OK;
+ else
+ result=STATE_WARNING;
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S13\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ temp_buffer=strtok(recv_buffer,"\r\n");
+
+ xasprintf (&output_message,_("Directory Services Database is %s (DS version %s)"),(result==STATE_OK)?"open":"closed",temp_buffer);
+
+ /* check to see if logins are enabled */
+ } else if (vars_to_check==LOGINS) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S12\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ if (atoi(recv_buffer)==1)
+ result=STATE_OK;
+ else
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,_("Logins are %s"),(result==STATE_OK)?_("enabled"):_("disabled"));
+
+
+ /* check NRM Health Status Summary*/
+ } else if (vars_to_check==NRMH) {
+
+ xasprintf (&send_buffer,"NRMH\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ nrm_health_status=atoi(recv_buffer);
+
+ if (nrm_health_status==2) {
+ result=STATE_OK;
+ xasprintf (&output_message,_("CRITICAL - NRM Status is bad!"));
+ }
+ else {
+ if (nrm_health_status==1) {
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("Warning - NRM Status is suspect!"));
+ }
+
+ xasprintf (&output_message,_("OK - NRM Status is good!"));
+ }
+
+
+
+ /* check packet receive buffers */
+ } else if (vars_to_check==UPRB || vars_to_check==PUPRB) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S15\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ used_packet_receive_buffers=atoi(recv_buffer);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S16\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ max_packet_receive_buffers=atoi(recv_buffer);
+
+ percent_used_packet_receive_buffers=(unsigned long)(((double)used_packet_receive_buffers/(double)max_packet_receive_buffers)*100.0);
+
+ if (vars_to_check==UPRB) {
+ if (check_critical_value==TRUE && used_packet_receive_buffers >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && used_packet_receive_buffers >= warning_value)
+ result=STATE_WARNING;
+ } else {
+ if (check_critical_value==TRUE && percent_used_packet_receive_buffers >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_used_packet_receive_buffers >= warning_value)
+ result=STATE_WARNING;
+ }
+
+ xasprintf (&output_message,_("%lu of %lu (%lu%%) packet receive buffers used"),used_packet_receive_buffers,max_packet_receive_buffers,percent_used_packet_receive_buffers);
+
+ /* check SAP table entries */
+ } else if (vars_to_check==SAPENTRIES) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ if (sap_number==-1)
+ xasprintf (&send_buffer,"S9\r\n");
+ else
+ xasprintf (&send_buffer,"S9.%d\r\n",sap_number);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ sap_entries=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && sap_entries >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && sap_entries >= warning_value)
+ result=STATE_WARNING;
+
+ if (sap_number==-1)
+ xasprintf (&output_message,_("%lu entries in SAP table"),sap_entries);
+ else
+ xasprintf (&output_message,_("%lu entries in SAP table for SAP type %d"),sap_entries,sap_number);
+
+ /* check KB purgeable space on volume */
+ } else if (vars_to_check==VKP) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ purgeable_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && purgeable_disk_space >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && purgeable_disk_space >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("%s%lu KB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
+ (result==STATE_OK)?"":_("Only "),
+ purgeable_disk_space,
+ volume_name,
+ volume_name,
+ purgeable_disk_space,
+ warning_value,
+ critical_value);
+ }
+ /* check MB purgeable space on volume */
+ } else if (vars_to_check==VMP) {
+
+ xasprintf (&send_buffer,"VMP%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ purgeable_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && purgeable_disk_space >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && purgeable_disk_space >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("%s%lu MB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
+ (result==STATE_OK)?"":_("Only "),
+ purgeable_disk_space,
+ volume_name,
+ volume_name,
+ purgeable_disk_space,
+ warning_value,
+ critical_value);
+ }
+
+ /* check % purgeable space on volume */
+ } else if (vars_to_check==VPP) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+
+ } else {
+
+ purgeable_disk_space=strtoul(recv_buffer,NULL,10);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ total_disk_space=strtoul(recv_buffer,NULL,10);
+
+ percent_purgeable_space=(unsigned long)(((double)purgeable_disk_space/(double)total_disk_space)*100.0);
+
+ if (check_critical_value==TRUE && percent_purgeable_space >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_purgeable_space >= warning_value)
+ result=STATE_WARNING;
+ purgeable_disk_space/=1024;
+ xasprintf (&output_message,_("%lu MB (%lu%%) purgeable on volume %s|Purgeable%s=%lu;%lu;%lu;0;100"),
+ purgeable_disk_space,
+ percent_purgeable_space,
+ volume_name,
+ volume_name,
+ percent_purgeable_space,
+ warning_value,
+ critical_value
+ );
+ }
+
+ /* check KB not yet purgeable space on volume */
+ } else if (vars_to_check==VKNP) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+ } else {
+ non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && non_purgeable_disk_space >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && non_purgeable_disk_space >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("%s%lu KB not yet purgeable on volume %s"),(result==STATE_OK)?"":_("Only "),non_purgeable_disk_space,volume_name);
+ }
+
+ /* check % not yet purgeable space on volume */
+ } else if (vars_to_check==VPNP) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+
+ xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
+ result=STATE_CRITICAL;
+
+ } else {
+
+ non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ total_disk_space=strtoul(recv_buffer,NULL,10);
+
+ percent_non_purgeable_space=(unsigned long)(((double)non_purgeable_disk_space/(double)total_disk_space)*100.0);
+
+ if (check_critical_value==TRUE && percent_non_purgeable_space >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && percent_non_purgeable_space >= warning_value)
+ result=STATE_WARNING;
+ purgeable_disk_space/=1024;
+ xasprintf (&output_message,_("%lu MB (%lu%%) not yet purgeable on volume %s"),non_purgeable_disk_space,percent_non_purgeable_space,volume_name);
+ }
+
+ /* check # of open files */
+ } else if (vars_to_check==OFILES) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S18\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ open_files=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && open_files >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && open_files >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,_("%lu open files|Openfiles=%lu;%lu;%lu;0,0"),
+ open_files,
+ open_files,
+ warning_value,
+ critical_value);
+
+
+ /* check # of abended threads (Netware > 5.x only) */
+ } else if (vars_to_check==ABENDS) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S17\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ abended_threads=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && abended_threads >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && abended_threads >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,_("%lu abended threads|Abends=%lu;%lu;%lu;;"),
+ abended_threads,
+ abended_threads,
+ warning_value,
+ critical_value);
+
+ /* check # of current service processes (Netware 5.x only) */
+ } else if (vars_to_check==CSPROCS) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S20\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ max_service_processes=atoi(recv_buffer);
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S21\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ current_service_processes=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && current_service_processes >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && current_service_processes >= warning_value)
+ result=STATE_WARNING;
+
+ xasprintf (&output_message,
+ _("%lu current service processes (%lu max)|Processes=%lu;%lu;%lu;0;%lu"),
+ current_service_processes,
+ max_service_processes,
+ current_service_processes,
+ warning_value,
+ critical_value,
+ max_service_processes);
+
+ /* check # Timesync Status */
+ } else if (vars_to_check==TSYNC) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S22\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ time_sync_status=atoi(recv_buffer);
+
+ if (time_sync_status==0) {
+ result=STATE_CRITICAL;
+ xasprintf (&output_message,_("CRITICAL - Time not in sync with network!"));
+ }
+ else {
+ xasprintf (&output_message,_("OK - Time in sync with network!"));
+ }
+
+
+
+
+
+ /* check LRU sitting time in secondss */
+ } else if (vars_to_check==LRUS) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S4\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ lru_time=strtoul(recv_buffer,NULL,10);
+
+ if (check_critical_value==TRUE && lru_time <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && lru_time <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("LRU sitting time = %lu seconds"),lru_time);
+
+
+ /* check % dirty cacheobuffers as a percentage of the total*/
+ } else if (vars_to_check==DCB) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S6\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ dirty_cache_buffers=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && dirty_cache_buffers <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && dirty_cache_buffers <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("Dirty cache buffers = %lu%% of the total|DCB=%lu;%lu;%lu;0;100"),
+ dirty_cache_buffers,
+ dirty_cache_buffers,
+ warning_value,
+ critical_value);
+
+ /* check % total cache buffers as a percentage of the original*/
+ } else if (vars_to_check==TCB) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ send_buffer = strdup ("S7\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+ total_cache_buffers=atoi(recv_buffer);
+
+ if (check_critical_value==TRUE && total_cache_buffers <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && total_cache_buffers <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,_("Total cache buffers = %lu%% of the original|TCB=%lu;%lu;%lu;0;100"),
+ total_cache_buffers,
+ total_cache_buffers,
+ warning_value,
+ critical_value);
+
+ } else if (vars_to_check==DSVER) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S13\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ recv_buffer[strlen(recv_buffer)-1]=0;
+
+ xasprintf (&output_message,_("NDS Version %s"),recv_buffer);
+
+ } else if (vars_to_check==UPTIME) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"UPTIME\r\n");
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+
+ recv_buffer[sizeof(recv_buffer)-1]=0;
+ recv_buffer[strlen(recv_buffer)-1]=0;
+
+ xasprintf (&output_message,_("Up %s"),recv_buffer);
+
+ } else if (vars_to_check==NLM) {
+
+ close(sd);
+ my_tcp_connect (server_address, server_port, &sd);
+
+ xasprintf (&send_buffer,"S24:%s\r\n",nlm_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ recv_buffer[strlen(recv_buffer)-1]=0;
+ if (strcmp(recv_buffer,"-1")) {
+ xasprintf (&output_message,_("Module %s version %s is loaded"),nlm_name,recv_buffer);
+ } else {
+ result=STATE_CRITICAL;
+ xasprintf (&output_message,_("Module %s is not loaded"),nlm_name);
+
+ }
+ } else if (vars_to_check==NRMP) {
+
+ xasprintf (&send_buffer,"NRMP:%s\r\n",nrmp_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmp_name);
+ result=STATE_CRITICAL;
+ } else {
+ nrmp_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nrmp_value <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nrmp_value <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nrmp_name,
+ nrmp_value,
+ nrmp_name,
+ nrmp_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NRMM) {
+
+ xasprintf (&send_buffer,"NRMM:%s\r\n",nrmm_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmm_name);
+ result=STATE_CRITICAL;
+ } else {
+ nrmm_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nrmm_value <= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nrmm_value <= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nrmm_name,
+ nrmm_value,
+ nrmm_name,
+ nrmm_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NRMS) {
+
+ xasprintf (&send_buffer,"NRMS:%s\r\n",nrms_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrms_name);
+ result=STATE_CRITICAL;
+ } else {
+ nrms_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nrms_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nrms_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nrms_name,
+ nrms_value,
+ nrms_name,
+ nrms_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS1) {
+
+ xasprintf (&send_buffer,"NSS1:%s\r\n",nss1_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss1_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss1_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss1_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss1_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss1_name,
+ nss1_value,
+ nss1_name,
+ nss1_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS2) {
+
+ xasprintf (&send_buffer,"NSS2:%s\r\n",nss2_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss2_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss2_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss2_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss2_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss2_name,
+ nss2_value,
+ nss2_name,
+ nss2_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS3) {
+
+ xasprintf (&send_buffer,"NSS3:%s\r\n",nss3_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss3_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss3_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss3_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss3_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss3_name,
+ nss3_value,
+ nss3_name,
+ nss3_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS4) {
+
+ xasprintf (&send_buffer,"NSS4:%s\r\n",nss4_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss4_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss4_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss4_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss4_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss4_name,
+ nss4_value,
+ nss4_name,
+ nss4_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS5) {
+
+ xasprintf (&send_buffer,"NSS5:%s\r\n",nss5_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss5_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss5_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss5_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss5_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss5_name,
+ nss5_value,
+ nss5_name,
+ nss5_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS6) {
+
+ xasprintf (&send_buffer,"NSS6:%s\r\n",nss6_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss6_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss6_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss6_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss6_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss6_name,
+ nss6_value,
+ nss6_name,
+ nss6_value,
+ warning_value,
+ critical_value);
+ }
+
+ } else if (vars_to_check==NSS7) {
+
+ xasprintf (&send_buffer,"NSS7:%s\r\n",nss7_name);
+ result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
+ if (result!=STATE_OK)
+ return result;
+
+ if (!strcmp(recv_buffer,"-1\n")) {
+ xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss7_name);
+ result=STATE_CRITICAL;
+ } else {
+ nss7_value=strtoul(recv_buffer,NULL,10);
+ if (check_critical_value==TRUE && nss7_value >= critical_value)
+ result=STATE_CRITICAL;
+ else if (check_warning_value==TRUE && nss7_value >= warning_value)
+ result=STATE_WARNING;
+ xasprintf (&output_message,
+ _("%s is %lu|%s=%lu;%lu;%lu;;"),
+ nss7_name,
+ nss7_value,
+ nss7_name,
+ nss7_value,
+ warning_value,
+ critical_value);
+ }
+
+
+}
+ else {
+
+ output_message = strdup (_("Nothing to check!\n"));
+ result=STATE_UNKNOWN;
+
+ }
+
+ close (sd);
+
+ /* reset timeout */
+ alarm(0);
+
+ printf("%s%s\n",netware_version,output_message);
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int process_arguments(int argc, char **argv) {
+ int c;
+
+ int option = 0;
+ static struct option longopts[] =
+ {
+ {"port", required_argument,0,'p'},
+ {"timeout", required_argument,0,'t'},
+ {"critical", required_argument,0,'c'},
+ {"warning", required_argument,0,'w'},
+ {"variable", required_argument,0,'v'},
+ {"hostname", required_argument,0,'H'},
+ {"osversion",no_argument, 0,'o'},
+ {"version", no_argument, 0,'V'},
+ {"help", no_argument, 0,'h'},
+ {0,0,0,0}
+ };
+
+ /* no options were supplied */
+ if (argc<2) return ERROR;
+
+ /* backwards compatibility */
+ if (! is_option(argv[1])) {
+ server_address=argv[1];
+ argv[1]=argv[0];
+ argv=&argv[1];
+ argc--;
+ }
+
+ for (c=1;c<argc;c++) {
+ if (strcmp("-to",argv[c])==0)
+ strcpy(argv[c],"-t");
+ else if (strcmp("-wv",argv[c])==0)
+ strcpy(argv[c],"-w");
+ else if (strcmp("-cv",argv[c])==0)
+ strcpy(argv[c],"-c");
+ }
+
+ while (1) {
+ c = getopt_long(argc,argv,"+hoVH:t:c:w:p:v:",longopts,&option);
+
+ if (c==-1||c==EOF||c==1)
+ break;
+
+ switch (c)
+ {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help();
+ exit(STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision(progname, NP_VERSION);
+ exit(STATE_UNKNOWN);
+ case 'H': /* hostname */
+ server_address=optarg;
+ break;
+ case 'o': /* display nos version */
+ check_netware_version=TRUE;
+ break;
+ case 'p': /* port */
+ if (is_intnonneg(optarg))
+ server_port=atoi(optarg);
+ else
+ die(STATE_UNKNOWN,_("Server port an integer\n"));
+ break;
+ case 'v':
+ if (strlen(optarg)<3)
+ return ERROR;
+ if (!strcmp(optarg,"LOAD1"))
+ vars_to_check=LOAD1;
+ else if (!strcmp(optarg,"LOAD5"))
+ vars_to_check=LOAD5;
+ else if (!strcmp(optarg,"LOAD15"))
+ vars_to_check=LOAD15;
+ else if (!strcmp(optarg,"CONNS"))
+ vars_to_check=CONNS;
+ else if (!strcmp(optarg,"LTCH"))
+ vars_to_check=LTCH;
+ else if (!strcmp(optarg,"DCB"))
+ vars_to_check=DCB;
+ else if (!strcmp(optarg,"TCB"))
+ vars_to_check=TCB;
+ else if (!strcmp(optarg,"CBUFF"))
+ vars_to_check=CBUFF;
+ else if (!strcmp(optarg,"CDBUFF"))
+ vars_to_check=CDBUFF;
+ else if (!strcmp(optarg,"LRUM"))
+ vars_to_check=LRUM;
+ else if (!strcmp(optarg,"LRUS"))
+ vars_to_check=LRUS;
+ else if (strncmp(optarg,"VPF",3)==0) {
+ vars_to_check=VPF;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VKF",3)==0) {
+ vars_to_check=VKF;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VMF",3)==0) {
+ vars_to_check=VMF;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (!strcmp(optarg,"DSDB"))
+ vars_to_check=DSDB;
+ else if (!strcmp(optarg,"LOGINS"))
+ vars_to_check=LOGINS;
+ else if (!strcmp(optarg,"NRMH"))
+ vars_to_check=NRMH;
+ else if (!strcmp(optarg,"UPRB"))
+ vars_to_check=UPRB;
+ else if (!strcmp(optarg,"PUPRB"))
+ vars_to_check=PUPRB;
+ else if (!strncmp(optarg,"SAPENTRIES",10)) {
+ vars_to_check=SAPENTRIES;
+ if (strlen(optarg)>10)
+ sap_number=atoi(optarg+10);
+ else
+ sap_number=-1;
+ }
+ else if (!strcmp(optarg,"OFILES"))
+ vars_to_check=OFILES;
+ else if (strncmp(optarg,"VKP",3)==0) {
+ vars_to_check=VKP;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VMP",3)==0) {
+ vars_to_check=VMP;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VMU",3)==0) {
+ vars_to_check=VMU;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VPP",3)==0) {
+ vars_to_check=VPP;
+ volume_name = strdup (optarg+3);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VKNP",4)==0) {
+ vars_to_check=VKNP;
+ volume_name = strdup (optarg+4);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup ("SYS");
+ }
+ else if (strncmp(optarg,"VPNP",4)==0) {
+ vars_to_check=VPNP;
+ volume_name = strdup (optarg+4);
+ if (!strcmp(volume_name,""))
+ volume_name = strdup("SYS");
+ }
+ else if (!strcmp(optarg,"ABENDS"))
+ vars_to_check=ABENDS;
+ else if (!strcmp(optarg,"CSPROCS"))
+ vars_to_check=CSPROCS;
+ else if (!strcmp(optarg,"TSYNC"))
+ vars_to_check=TSYNC;
+ else if (!strcmp(optarg,"DSVER"))
+ vars_to_check=DSVER;
+ else if (!strcmp(optarg,"UPTIME")) {
+ vars_to_check=UPTIME;
+ }
+ else if (strncmp(optarg,"NLM:",4)==0) {
+ vars_to_check=NLM;
+ nlm_name=strdup (optarg+4);
+ }
+ else if (strncmp(optarg,"NRMP",4)==0) {
+ vars_to_check=NRMP;
+ nrmp_name = strdup (optarg+4);
+ if (!strcmp(nrmp_name,""))
+ nrmp_name = strdup ("AVAILABLE_MEMORY");
+ }
+ else if (strncmp(optarg,"NRMM",4)==0) {
+ vars_to_check=NRMM;
+ nrmm_name = strdup (optarg+4);
+ if (!strcmp(nrmm_name,""))
+ nrmm_name = strdup ("AVAILABLE_CACHE_MEMORY");
+
+ }
+
+ else if (strncmp(optarg,"NRMS",4)==0) {
+ vars_to_check=NRMS;
+ nrms_name = strdup (optarg+4);
+ if (!strcmp(nrms_name,""))
+ nrms_name = strdup ("USED_SWAP_SPACE");
+
+ }
+
+ else if (strncmp(optarg,"NSS1",4)==0) {
+ vars_to_check=NSS1;
+ nss1_name = strdup (optarg+4);
+ if (!strcmp(nss1_name,""))
+ nss1_name = strdup ("CURRENTBUFFERCACHESIZE");
+
+ }
+
+ else if (strncmp(optarg,"NSS2",4)==0) {
+ vars_to_check=NSS2;
+ nss2_name = strdup (optarg+4);
+ if (!strcmp(nss2_name,""))
+ nss2_name = strdup ("CACHEHITS");
+
+ }
+
+ else if (strncmp(optarg,"NSS3",4)==0) {
+ vars_to_check=NSS3;
+ nss3_name = strdup (optarg+4);
+ if (!strcmp(nss3_name,""))
+ nss3_name = strdup ("CACHEGITPERCENT");
+
+ }
+
+ else if (strncmp(optarg,"NSS4",4)==0) {
+ vars_to_check=NSS4;
+ nss4_name = strdup (optarg+4);
+ if (!strcmp(nss4_name,""))
+ nss4_name = strdup ("CURRENTOPENCOUNT");
+
+ }
+
+ else if (strncmp(optarg,"NSS5",4)==0) {
+ vars_to_check=NSS5;
+ nss5_name = strdup (optarg+4);
+ if (!strcmp(nss5_name,""))
+ nss5_name = strdup ("CACHEMISSES");
+
+ }
+
+
+ else if (strncmp(optarg,"NSS6",4)==0) {
+ vars_to_check=NSS6;
+ nss6_name = strdup (optarg+4);
+ if (!strcmp(nss6_name,""))
+ nss6_name = strdup ("PENDINGWORKSCOUNT");
+
+ }
+
+
+ else if (strncmp(optarg,"NSS7",4)==0) {
+ vars_to_check=NSS7;
+ nss7_name = strdup (optarg+4);
+ if (!strcmp(nss7_name,""))
+ nss7_name = strdup ("CACHESIZE");
+
+ }
+
+
+ else
+ return ERROR;
+ break;
+ case 'w': /* warning threshold */
+ warning_value=strtoul(optarg,NULL,10);
+ check_warning_value=TRUE;
+ break;
+ case 'c': /* critical threshold */
+ critical_value=strtoul(optarg,NULL,10);
+ check_critical_value=TRUE;
+ break;
+ case 't': /* timeout */
+ socket_timeout=atoi(optarg);
+ if (socket_timeout<=0)
+ return ERROR;
+ }
+
+ }
+
+ return OK;
+}
+
+
+
+void print_help(void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin attempts to contact the MRTGEXT NLM running on a"));
+ printf ("%s\n", _("Novell server to gather the requested system information."));
+
+ printf ("\n\n");
+
+ print_usage();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n", "-v, --variable=STRING");
+ printf (" %s\n", _("Variable to check. Valid variables include:"));
+ printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
+ printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
+ printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
+ printf (" %s\n", _("CSPROCS = number of current service processes (NW 5.x only)"));
+ printf (" %s\n", _("ABENDS = number of abended threads (NW 5.x only)"));
+ printf (" %s\n", _("UPTIME = server uptime"));
+ printf (" %s\n", _("LTCH = percent long term cache hits"));
+ printf (" %s\n", _("CBUFF = current number of cache buffers"));
+ printf (" %s\n", _("CDBUFF = current number of dirty cache buffers"));
+ printf (" %s\n", _("DCB = dirty cache buffers as a percentage of the total"));
+ printf (" %s\n", _("TCB = dirty cache buffers as a percentage of the original"));
+ printf (" %s\n", _("OFILES = number of open files"));
+ printf (" %s\n", _(" VMF<vol> = MB of free space on Volume <vol>"));
+ printf (" %s\n", _(" VMU<vol> = MB used space on Volume <vol>"));
+ printf (" %s\n", _(" VMP<vol> = MB of purgeable space on Volume <vol>"));
+ printf (" %s\n", _(" VPF<vol> = percent free space on volume <vol>"));
+ printf (" %s\n", _(" VKF<vol> = KB of free space on volume <vol>"));
+ printf (" %s\n", _(" VPP<vol> = percent purgeable space on volume <vol>"));
+ printf (" %s\n", _(" VKP<vol> = KB of purgeable space on volume <vol>"));
+ printf (" %s\n", _(" VPNP<vol> = percent not yet purgeable space on volume <vol>"));
+ printf (" %s\n", _(" VKNP<vol> = KB of not yet purgeable space on volume <vol>"));
+ printf (" %s\n", _(" LRUM = LRU sitting time in minutes"));
+ printf (" %s\n", _(" LRUS = LRU sitting time in seconds"));
+ printf (" %s\n", _(" DSDB = check to see if DS Database is open"));
+ printf (" %s\n", _(" DSVER = NDS version"));
+ printf (" %s\n", _(" UPRB = used packet receive buffers"));
+ printf (" %s\n", _(" PUPRB = percent (of max) used packet receive buffers"));
+ printf (" %s\n", _(" SAPENTRIES = number of entries in the SAP table"));
+ printf (" %s\n", _(" SAPENTRIES<n> = number of entries in the SAP table for SAP type <n>"));
+ printf (" %s\n", _(" TSYNC = timesync status"));
+ printf (" %s\n", _(" LOGINS = check to see if logins are enabled"));
+ printf (" %s\n", _(" CONNS = number of currently licensed connections"));
+ printf (" %s\n", _(" NRMH = NRM Summary Status"));
+ printf (" %s\n", _(" NRMP<stat> = Returns the current value for a NRM health item"));
+ printf (" %s\n", _(" NRMM<stat> = Returns the current memory stats from NRM"));
+ printf (" %s\n", _(" NRMS<stat> = Returns the current Swapfile stats from NRM"));
+ printf (" %s\n", _(" NSS1<stat> = Statistics from _Admin:Manage_NSS\\GeneralStats.xml"));
+ printf (" %s\n", _(" NSS3<stat> = Statistics from _Admin:Manage_NSS\\NameCache.xml"));
+ printf (" %s\n", _(" NSS4<stat> = Statistics from _Admin:Manage_NSS\\FileStats.xml"));
+ printf (" %s\n", _(" NSS5<stat> = Statistics from _Admin:Manage_NSS\\ObjectCache.xml"));
+ printf (" %s\n", _(" NSS6<stat> = Statistics from _Admin:Manage_NSS\\Thread.xml"));
+ printf (" %s\n", _(" NSS7<stat> = Statistics from _Admin:Manage_NSS\\AuthorizationCache.xml"));
+ printf (" %s\n", _(" NLM:<nlm> = check if NLM is loaded and report version"));
+ printf (" %s\n", _(" (e.g. NLM:TSANDS.NLM)"));
+ printf ("\n");
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a warning status"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a critical status"));
+ printf (" %s\n", "-o, --osversion");
+ printf (" %s\n", _("Include server version string in results"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
+ printf (" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
+ printf (" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
+ printf (" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
+ printf (" %s\n", _(" when the following variables are checked: VPF, VKF, LTCH, CBUFF, DCB, "));
+ printf (" %s\n", _(" TCB, LRUS and LRUM."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void print_usage(void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n",progname);
+}
diff --git a/plugins/check_overcr.c b/plugins/check_overcr.c
new file mode 100644
index 0000000..9a4d25f
--- /dev/null
+++ b/plugins/check_overcr.c
@@ -0,0 +1,469 @@
+/*****************************************************************************
+*
+* Monitoring check_overcr plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_overcr plugin
+*
+* This plugin attempts to contact the Over-CR collector daemon running on the
+* remote UNIX server in order to gather the requested system information.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_overcr";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum checkvar {
+ NONE,
+ LOAD1,
+ LOAD5,
+ LOAD15,
+ DPU,
+ PROCS,
+ NETSTAT,
+ UPTIME
+};
+
+enum {
+ PORT = 2000
+};
+
+char *server_address = NULL;
+int server_port = PORT;
+double warning_value = 0L;
+double critical_value = 0L;
+int check_warning_value = FALSE;
+int check_critical_value = FALSE;
+enum checkvar vars_to_check = NONE;
+int cmd_timeout = 1;
+
+int netstat_port = 0;
+char *disk_name = NULL;
+char *process_name = NULL;
+ char send_buffer[MAX_INPUT_BUFFER];
+
+int process_arguments (int, char **);
+void print_usage (void);
+void print_help (void);
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ char recv_buffer[MAX_INPUT_BUFFER];
+ char temp_buffer[MAX_INPUT_BUFFER];
+ char *temp_ptr = NULL;
+ int found_disk = FALSE;
+ unsigned long percent_used_disk_space = 100;
+ double load;
+ double load_1min;
+ double load_5min;
+ double load_15min;
+ int port_connections = 0;
+ int processes = 0;
+ double uptime_raw_hours;
+ int uptime_raw_minutes = 0;
+ int uptime_days = 0;
+ int uptime_hours = 0;
+ int uptime_minutes = 0;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ result = process_tcp_request2 (server_address,
+ server_port,
+ send_buffer,
+ recv_buffer,
+ sizeof (recv_buffer));
+
+ switch (vars_to_check) {
+
+ case LOAD1:
+ case LOAD5:
+ case LOAD15:
+
+ if (result != STATE_OK)
+ die (result, _("Unknown error fetching load data\n"));
+
+ temp_ptr = (char *) strtok (recv_buffer, "\r\n");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server - no load information\n"));
+ else
+ load_1min = strtod (temp_ptr, NULL);
+
+ temp_ptr = (char *) strtok (NULL, "\r\n");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server after load 1\n"));
+ else
+ load_5min = strtod (temp_ptr, NULL);
+
+ temp_ptr = (char *) strtok (NULL, "\r\n");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server after load 5\n"));
+ else
+ load_15min = strtod (temp_ptr, NULL);
+
+ switch (vars_to_check) {
+ case LOAD1:
+ strcpy (temp_buffer, "1");
+ load = load_1min;
+ break;
+ case LOAD5:
+ strcpy (temp_buffer, "5");
+ load = load_5min;
+ break;
+ default:
+ strcpy (temp_buffer, "15");
+ load = load_15min;
+ break;
+ }
+
+ if (check_critical_value == TRUE && (load >= critical_value))
+ result = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && (load >= warning_value))
+ result = STATE_WARNING;
+
+ die (result,
+ _("Load %s - %s-min load average = %0.2f"),
+ state_text(result),
+ temp_buffer,
+ load);
+
+ break;
+
+ case DPU:
+
+ if (result != STATE_OK)
+ die (result, _("Unknown error fetching disk data\n"));
+
+ for (temp_ptr = (char *) strtok (recv_buffer, " ");
+ temp_ptr != NULL;
+ temp_ptr = (char *) strtok (NULL, " ")) {
+
+ if (!strcmp (temp_ptr, disk_name)) {
+ found_disk = TRUE;
+ temp_ptr = (char *) strtok (NULL, "%");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server\n"));
+ else
+ percent_used_disk_space = strtoul (temp_ptr, NULL, 10);
+ break;
+ }
+
+ temp_ptr = (char *) strtok (NULL, "\r\n");
+ }
+
+ /* error if we couldn't find the info for the disk */
+ if (found_disk == FALSE)
+ die (STATE_CRITICAL,
+ "CRITICAL - Disk '%s' non-existent or not mounted",
+ disk_name);
+
+ if (check_critical_value == TRUE && (percent_used_disk_space >= critical_value))
+ result = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && (percent_used_disk_space >= warning_value))
+ result = STATE_WARNING;
+
+ die (result, "Disk %s - %lu%% used on %s", state_text(result), percent_used_disk_space, disk_name);
+
+ break;
+
+ case NETSTAT:
+
+ if (result != STATE_OK)
+ die (result, _("Unknown error fetching network status\n"));
+ else
+ port_connections = strtod (recv_buffer, NULL);
+
+ if (check_critical_value == TRUE && (port_connections >= critical_value))
+ result = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && (port_connections >= warning_value))
+ result = STATE_WARNING;
+
+ die (result,
+ _("Net %s - %d connection%s on port %d"),
+ state_text(result),
+ port_connections,
+ (port_connections == 1) ? "" : "s",
+ netstat_port);
+
+ break;
+
+ case PROCS:
+
+ if (result != STATE_OK)
+ die (result, _("Unknown error fetching process status\n"));
+
+ temp_ptr = (char *) strtok (recv_buffer, "(");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server\n"));
+
+ temp_ptr = (char *) strtok (NULL, ")");
+ if (temp_ptr == NULL)
+ die (STATE_CRITICAL, _("Invalid response from server\n"));
+ else
+ processes = strtod (temp_ptr, NULL);
+
+ if (check_critical_value == TRUE && (processes >= critical_value))
+ result = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && (processes >= warning_value))
+ result = STATE_WARNING;
+
+ die (result,
+ _("Process %s - %d instance%s of %s running"),
+ state_text(result),
+ processes,
+ (processes == 1) ? "" : "s",
+ process_name);
+ break;
+
+ case UPTIME:
+
+ if (result != STATE_OK)
+ return result;
+
+ uptime_raw_hours = strtod (recv_buffer, NULL);
+ uptime_raw_minutes = (unsigned long) (uptime_raw_hours * 60.0);
+
+ if (check_critical_value == TRUE && (uptime_raw_minutes <= critical_value))
+ result = STATE_CRITICAL;
+ else if (check_warning_value == TRUE && (uptime_raw_minutes <= warning_value))
+ result = STATE_WARNING;
+
+ uptime_days = uptime_raw_minutes / 1440;
+ uptime_raw_minutes %= 1440;
+ uptime_hours = uptime_raw_minutes / 60;
+ uptime_raw_minutes %= 60;
+ uptime_minutes = uptime_raw_minutes;
+
+ die (result,
+ _("Uptime %s - Up %d days %d hours %d minutes"),
+ state_text(result),
+ uptime_days,
+ uptime_hours,
+ uptime_minutes);
+ break;
+
+ default:
+ die (STATE_UNKNOWN, _("Nothing to check!\n"));
+ break;
+ }
+}
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"port", required_argument, 0, 'p'},
+ {"timeout", required_argument, 0, 't'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"variable", required_argument, 0, 'v'},
+ {"hostname", required_argument, 0, 'H'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ /* no options were supplied */
+ if (argc < 2)
+ return ERROR;
+
+ /* backwards compatibility */
+ if (!is_option (argv[1])) {
+ server_address = argv[1];
+ argv[1] = argv[0];
+ argv = &argv[1];
+ argc--;
+ }
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wv", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-cv", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVH:t:c:w:p:v:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'H': /* hostname */
+ server_address = optarg;
+ break;
+ case 'p': /* port */
+ if (is_intnonneg (optarg))
+ server_port = atoi (optarg);
+ else
+ die (STATE_UNKNOWN,
+ _("Server port an integer\n"));
+ break;
+ case 'v': /* variable */
+ if (strcmp (optarg, "LOAD") == 0) {
+ strcpy (send_buffer, "LOAD\r\nQUIT\r\n");
+ if (strcmp (optarg, "LOAD1") == 0)
+ vars_to_check = LOAD1;
+ else if (strcmp (optarg, "LOAD5") == 0)
+ vars_to_check = LOAD5;
+ else if (strcmp (optarg, "LOAD15") == 0)
+ vars_to_check = LOAD15;
+ }
+ else if (strcmp (optarg, "UPTIME") == 0) {
+ vars_to_check = UPTIME;
+ strcpy (send_buffer, "UPTIME\r\n");
+ }
+ else if (strstr (optarg, "PROC") == optarg) {
+ vars_to_check = PROCS;
+ process_name = strscpy (process_name, optarg + 4);
+ sprintf (send_buffer, "PROCESS %s\r\n", process_name);
+ }
+ else if (strstr (optarg, "NET") == optarg) {
+ vars_to_check = NETSTAT;
+ netstat_port = atoi (optarg + 3);
+ sprintf (send_buffer, "NETSTAT %d\r\n", netstat_port);
+ }
+ else if (strstr (optarg, "DPU") == optarg) {
+ vars_to_check = DPU;
+ strcpy (send_buffer, "DISKSPACE\r\n");
+ disk_name = strscpy (disk_name, optarg + 3);
+ }
+ else
+ return ERROR;
+ break;
+ case 'w': /* warning threshold */
+ warning_value = strtoul (optarg, NULL, 10);
+ check_warning_value = TRUE;
+ break;
+ case 'c': /* critical threshold */
+ critical_value = strtoul (optarg, NULL, 10);
+ check_critical_value = TRUE;
+ break;
+ case 't': /* timeout */
+ socket_timeout = atoi (optarg);
+ if (socket_timeout <= 0)
+ return ERROR;
+ }
+
+ }
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin attempts to contact the Over-CR collector daemon running on the"));
+ printf ("%s\n", _("remote UNIX server in order to gather the requested system information."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a warning status"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Threshold which will result in a critical status"));
+ printf (" %s\n", "-v, --variable=STRING");
+ printf (" %s\n", _("Variable to check. Valid variables include:"));
+ printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
+ printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
+ printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
+ printf (" %s\n", _("DPU<filesys> = percent used disk space on filesystem <filesys>"));
+ printf (" %s\n", _("PROC<process> = number of running processes with name <process>"));
+ printf (" %s\n", _("NET<port> = number of active connections on TCP port <port>"));
+ printf (" %s\n", _("UPTIME = system uptime in seconds"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin requires that Eric Molitors' Over-CR collector daemon be"));
+ printf ("%s\n", _("running on the remote server."));
+ printf ("%s\n", _("Over-CR can be downloaded from http://www.molitor.org/overcr"));
+ printf ("%s\n", _("This plugin was tested with version 0.99.53 of the Over-CR collector"));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("For the available options, the critical threshold value should always be"));
+ printf (" %s\n", _("higher than the warning threshold value, EXCEPT with the uptime variable"));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
+}
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
new file mode 100644
index 0000000..6199033
--- /dev/null
+++ b/plugins/check_pgsql.c
@@ -0,0 +1,636 @@
+/*****************************************************************************
+*
+* Monitoring check_pgsql plugin
+*
+* License: GPL
+* Copyright (c) 1999-2011 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_pgsql plugin
+*
+* Test whether a PostgreSQL Database is accepting connections.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_pgsql";
+const char *copyright = "1999-2011";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_cmd.h"
+
+#include "netutils.h"
+#include <libpq-fe.h>
+#include <pg_config_manual.h>
+
+#define DEFAULT_DB "template1"
+#define DEFAULT_HOST "127.0.0.1"
+
+/* return the PSQL server version as a 3-tuple */
+#define PSQL_SERVER_VERSION3(server_version) \
+ (server_version) / 10000, \
+ (server_version) / 100 - (int)((server_version) / 10000) * 100, \
+ (server_version) - (int)((server_version) / 100) * 100
+/* return true if the given host is a UNIX domain socket */
+#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) \
+ ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
+/* return a 3-tuple identifying a host/port independent of the socket type */
+#define PSQL_SOCKET3(host, port) \
+ ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
+ PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \
+ port
+
+enum {
+ DEFAULT_PORT = 5432,
+ DEFAULT_WARN = 2,
+ DEFAULT_CRIT = 8
+};
+
+
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_usage (void);
+void print_help (void);
+int is_pg_logname (char *);
+int do_query (PGconn *, char *);
+
+char *pghost = NULL; /* host name of the backend server */
+char *pgport = NULL; /* port of the backend server */
+int default_port = DEFAULT_PORT;
+char *pgoptions = NULL;
+char *pgtty = NULL;
+char dbName[NAMEDATALEN] = DEFAULT_DB;
+char *pguser = NULL;
+char *pgpasswd = NULL;
+char *pgparams = NULL;
+double twarn = (double)DEFAULT_WARN;
+double tcrit = (double)DEFAULT_CRIT;
+char *pgquery = NULL;
+#define OPTID_QUERYNAME -1000
+char *pgqueryname = NULL;
+char *query_warning = NULL;
+char *query_critical = NULL;
+thresholds *qthresholds = NULL;
+int verbose = 0;
+
+/******************************************************************************
+
+The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
+tags in the comments. With in the tags, the XML is assembled sequentially.
+You can define entities in tags. You also have all the #defines available as
+entities.
+
+Please note that all tags must be lowercase to use the DocBook XML DTD.
+
+@@-<article>
+
+<sect1>
+<title>Quick Reference</title>
+<!-- The refentry forms a manpage -->
+<refentry>
+<refmeta>
+<manvolnum>5<manvolnum>
+</refmeta>
+<refnamdiv>
+<refname>&progname;</refname>
+<refpurpose>&SUMMARY;</refpurpose>
+</refnamdiv>
+</refentry>
+</sect1>
+
+<sect1>
+<title>FAQ</title>
+</sect1>
+
+<sect1>
+<title>Theory, Installation, and Operation</title>
+
+<sect2>
+<title>General Description</title>
+<para>
+&DESCRIPTION;
+</para>
+</sect2>
+
+<sect2>
+<title>Future Enhancements</title>
+<para>ToDo List</para>
+</sect2>
+
+
+<sect2>
+<title>Functions</title>
+-@@
+******************************************************************************/
+
+
+
+int
+main (int argc, char **argv)
+{
+ PGconn *conn;
+ char *conninfo = NULL;
+
+ struct timeval start_timeval;
+ struct timeval end_timeval;
+ double elapsed_time;
+ int status = STATE_UNKNOWN;
+ int query_status = STATE_UNKNOWN;
+
+ /* begin, by setting the parameters for a backend connection if the
+ * parameters are null, then the system will try to use reasonable
+ * defaults by looking up environment variables or, failing that,
+ * using hardwired constants */
+
+ pgoptions = NULL; /* special options to start up the backend server */
+ pgtty = NULL; /* debugging tty for the backend server */
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+ if (verbose > 2)
+ printf("Arguments initialized\n");
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ usage4 (_("Cannot catch SIGALRM"));
+ }
+ alarm (timeout_interval);
+
+ if (pgparams)
+ asprintf (&conninfo, "%s ", pgparams);
+
+ asprintf (&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName);
+ if (pghost)
+ asprintf (&conninfo, "%s host = '%s'", conninfo, pghost);
+ if (pgport)
+ asprintf (&conninfo, "%s port = '%s'", conninfo, pgport);
+ if (pgoptions)
+ asprintf (&conninfo, "%s options = '%s'", conninfo, pgoptions);
+ /* if (pgtty) -- ignored by PQconnectdb */
+ if (pguser)
+ asprintf (&conninfo, "%s user = '%s'", conninfo, pguser);
+
+ if (verbose) /* do not include password (see right below) in output */
+ printf ("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo,
+ pgpasswd ? " password = <hidden>" : "");
+
+ if (pgpasswd)
+ asprintf (&conninfo, "%s password = '%s'", conninfo, pgpasswd);
+
+ /* make a connection to the database */
+ gettimeofday (&start_timeval, NULL);
+ conn = PQconnectdb (conninfo);
+ gettimeofday (&end_timeval, NULL);
+
+ while (start_timeval.tv_usec > end_timeval.tv_usec) {
+ --end_timeval.tv_sec;
+ end_timeval.tv_usec += 1000000;
+ }
+ elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec)
+ + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0;
+
+ if (verbose)
+ printf("Time elapsed: %f\n", elapsed_time);
+
+ /* check to see that the backend connection was successfully made */
+ if (verbose)
+ printf("Verifying connection\n");
+ if (PQstatus (conn) == CONNECTION_BAD) {
+ printf (_("CRITICAL - no connection to '%s' (%s).\n"),
+ dbName, PQerrorMessage (conn));
+ PQfinish (conn);
+ return STATE_CRITICAL;
+ }
+ else if (elapsed_time > tcrit) {
+ status = STATE_CRITICAL;
+ }
+ else if (elapsed_time > twarn) {
+ status = STATE_WARNING;
+ }
+ else {
+ status = STATE_OK;
+ }
+
+ if (verbose) {
+ char *server_host = PQhost (conn);
+ int server_version = PQserverVersion (conn);
+
+ printf ("Successfully connected to database %s (user %s) "
+ "at server %s%s%s (server version: %d.%d.%d, "
+ "protocol version: %d, pid: %d)\n",
+ PQdb (conn), PQuser (conn),
+ PSQL_SOCKET3 (server_host, PQport (conn)),
+ PSQL_SERVER_VERSION3 (server_version),
+ PQprotocolVersion (conn), PQbackendPID (conn));
+ }
+
+ printf (_(" %s - database %s (%f sec.)|%s\n"),
+ state_text(status), dbName, elapsed_time,
+ fperfdata("time", elapsed_time, "s",
+ !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, TRUE, 0, FALSE,0));
+
+ if (pgquery)
+ query_status = do_query (conn, pgquery);
+
+ if (verbose)
+ printf("Closing connection\n");
+ PQfinish (conn);
+ return (pgquery && query_status > status) ? query_status : status;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"timeout", required_argument, 0, 't'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"hostname", required_argument, 0, 'H'},
+ {"logname", required_argument, 0, 'l'},
+ {"password", required_argument, 0, 'p'},
+ {"authorization", required_argument, 0, 'a'},
+ {"port", required_argument, 0, 'P'},
+ {"database", required_argument, 0, 'd'},
+ {"option", required_argument, 0, 'o'},
+ {"query", required_argument, 0, 'q'},
+ {"queryname", required_argument, 0, OPTID_QUERYNAME},
+ {"query_critical", required_argument, 0, 'C'},
+ {"query_warning", required_argument, 0, 'W'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v",
+ longopts, &option);
+
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* usage */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ timeout_interval = atoi (optarg);
+ break;
+ case 'c': /* critical time threshold */
+ if (!is_nonnegative (optarg))
+ usage2 (_("Critical threshold must be a positive integer"), optarg);
+ else
+ tcrit = strtod (optarg, NULL);
+ break;
+ case 'w': /* warning time threshold */
+ if (!is_nonnegative (optarg))
+ usage2 (_("Warning threshold must be a positive integer"), optarg);
+ else
+ twarn = strtod (optarg, NULL);
+ break;
+ case 'C': /* critical query threshold */
+ query_critical = optarg;
+ break;
+ case 'W': /* warning query threshold */
+ query_warning = optarg;
+ break;
+ case 'H': /* host */
+ if ((*optarg != '/') && (!is_host (optarg)))
+ usage2 (_("Invalid hostname/address"), optarg);
+ else
+ pghost = optarg;
+ break;
+ case 'P': /* port */
+ if (!is_integer (optarg))
+ usage2 (_("Port must be a positive integer"), optarg);
+ else
+ pgport = optarg;
+ break;
+ case 'd': /* database name */
+ if (strlen(optarg) >= NAMEDATALEN) {
+ usage2 (_("Database name exceeds the maximum length"), optarg);
+ }
+ snprintf(dbName, NAMEDATALEN, "%s", optarg);
+ break;
+ case 'l': /* login name */
+ if (!is_pg_logname (optarg))
+ usage2 (_("User name is not valid"), optarg);
+ else
+ pguser = optarg;
+ break;
+ case 'p': /* authentication password */
+ case 'a':
+ pgpasswd = optarg;
+ break;
+ case 'o':
+ if (pgparams)
+ asprintf (&pgparams, "%s %s", pgparams, optarg);
+ else
+ asprintf (&pgparams, "%s", optarg);
+ break;
+ case 'q':
+ pgquery = optarg;
+ break;
+ case OPTID_QUERYNAME:
+ pgqueryname = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ }
+ }
+
+ set_thresholds (&qthresholds, query_warning, query_critical);
+
+ return validate_arguments ();
+}
+
+
+/******************************************************************************
+
+@@-
+<sect3>
+<title>validate_arguments</title>
+
+<para>&PROTO_validate_arguments;</para>
+
+<para>Given a database name, this function returns TRUE if the string
+is a valid PostgreSQL database name, and returns false if it is
+not.</para>
+
+<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
+characters long and consist of letters, numbers, and underscores. The
+first character cannot be a number, however.</para>
+
+</sect3>
+-@@
+******************************************************************************/
+
+
+
+int
+validate_arguments ()
+{
+ return OK;
+}
+
+/**
+
+the tango program should eventually create an entity here based on the
+function prototype
+
+@@-
+<sect3>
+<title>is_pg_logname</title>
+
+<para>&PROTO_is_pg_logname;</para>
+
+<para>Given a username, this function returns TRUE if the string is a
+valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
+usernames are less than &NAMEDATALEN; characters long and consist of
+letters, numbers, dashes, and underscores, plus possibly some other
+characters.</para>
+
+<para>Currently this function only checks string length. Additional checks
+should be added.</para>
+
+</sect3>
+-@@
+******************************************************************************/
+
+
+
+int
+is_pg_logname (char *username)
+{
+ if (strlen (username) > NAMEDATALEN - 1)
+ return (FALSE);
+ return (TRUE);
+}
+
+/******************************************************************************
+@@-
+</sect2>
+</sect1>
+</article>
+-@@
+******************************************************************************/
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+
+ xasprintf (&myport, "%d", DEFAULT_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("Test whether a PostgreSQL Database is accepting connections."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'P', myport);
+
+ printf (" %s\n", "-d, --database=STRING");
+ printf (" %s", _("Database to check "));
+ printf (_("(default: %s)\n"), DEFAULT_DB);
+ printf (" %s\n", "-l, --logname = STRING");
+ printf (" %s\n", _("Login name of user"));
+ printf (" %s\n", "-p, --password = STRING");
+ printf (" %s\n", _("Password (BIG SECURITY ISSUE)"));
+ printf (" %s\n", "-o, --option = STRING");
+ printf (" %s\n", _("Connection parameters (keyword = value), see below"));
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (" %s\n", "-q, --query=STRING");
+ printf (" %s\n", _("SQL query to run. Only first column in first row will be read"));
+ printf (" %s\n", "--queryname=STRING");
+ printf (" %s\n", _("A name for the query, this string is used instead of the query"));
+ printf (" %s\n", _("in the long output of the plugin"));
+ printf (" %s\n", "-W, --query-warning=RANGE");
+ printf (" %s\n", _("SQL query value to result in warning status (double)"));
+ printf (" %s\n", "-C, --query-critical=RANGE");
+ printf (" %s\n", _("SQL query value to result in critical status (double)"));
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf (" %s\n", _("All parameters are optional."));
+ printf (" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and"));
+ printf (" %s\n", _("accepting queries. In its current operation, it simply connects to the"));
+ printf (" %s\n", _("specified database, and then disconnects. If no database is specified, it"));
+ printf (" %s\n", _("connects to the template1 database, which is present in every functioning"));
+ printf (" %s\n\n", _("PostgreSQL DBMS."));
+
+ printf (" %s\n", _("If a query is specified using the -q option, it will be executed after"));
+ printf (" %s\n", _("connecting to the server. The result from the query has to be numeric."));
+ printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
+ printf (" %s\n", _("of the last command is taken into account only. The value of the first"));
+ printf (" %s\n", _("column in the first row is used as the check result. If a second column is"));
+ printf (" %s\n", _("present in the result set, this is added to the plugin output with a"));
+ printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system"));
+ printf (" %s\n\n", _("executing the plugin."));
+
+ printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
+ printf (" %s\n\n", _("for details about how to access internal statistics of the database server."));
+
+ printf (" %s\n", _("For a list of available connection parameters which may be used with the -o"));
+ printf (" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter"));
+ printf (" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
+ printf (" %s\n", _("used to specify a service name in pg_service.conf to be used for additional"));
+ printf (" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
+ printf (" %s\n\n", _("-o 'sslmode=require'."));
+
+ printf (" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
+ printf (" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
+ printf (" %s\n\n", _("connections (start the postmaster with the -i option)."));
+
+ printf (" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be"));
+ printf (" %s\n", _("able to connect to the database without a password. The plugin can also send"));
+ printf (" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
+ printf (" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
+ "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
+}
+
+int
+do_query (PGconn *conn, char *query)
+{
+ PGresult *res;
+
+ char *val_str;
+ char *extra_info;
+ double value;
+
+ char *endptr = NULL;
+
+ int my_status = STATE_UNKNOWN;
+
+ if (verbose)
+ printf ("Executing SQL query \"%s\".\n", query);
+ res = PQexec (conn, query);
+
+ if (PGRES_TUPLES_OK != PQresultStatus (res)) {
+ printf (_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"),
+ PQerrorMessage (conn));
+ return STATE_CRITICAL;
+ }
+
+ if (PQntuples (res) < 1) {
+ printf ("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
+ return STATE_WARNING;
+ }
+
+ if (PQnfields (res) < 1) {
+ printf ("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
+ return STATE_WARNING;
+ }
+
+ val_str = PQgetvalue (res, 0, 0);
+ if (! val_str) {
+ printf ("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
+ return STATE_CRITICAL;
+ }
+
+ value = strtod (val_str, &endptr);
+ if (verbose)
+ printf ("Query result: %f\n", value);
+
+ if (endptr == val_str) {
+ printf ("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
+ return STATE_CRITICAL;
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ if (verbose)
+ printf ("Garbage after value: %s.\n", endptr);
+ }
+
+ my_status = get_status (value, qthresholds);
+ printf ("QUERY %s - ",
+ (my_status == STATE_OK)
+ ? _("OK")
+ : (my_status == STATE_WARNING)
+ ? _("WARNING")
+ : (my_status == STATE_CRITICAL)
+ ? _("CRITICAL")
+ : _("UNKNOWN"));
+ if(pgqueryname) {
+ printf (_("%s returned %f"), pgqueryname, value);
+ }
+ else {
+ printf (_("'%s' returned %f"), query, value);
+ }
+
+ printf ("|query=%f;%s;%s;;\n", value,
+ query_warning ? query_warning : "",
+ query_critical ? query_critical : "");
+ if (PQnfields (res) > 1) {
+ extra_info = PQgetvalue (res, 0, 1);
+ if (extra_info != NULL) {
+ printf ("Extra Info: %s\n", extra_info);
+ }
+ }
+ return my_status;
+}
+
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
new file mode 100644
index 0000000..741f732
--- /dev/null
+++ b/plugins/check_ping.c
@@ -0,0 +1,620 @@
+/*****************************************************************************
+*
+* Monitoring check_ping plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ping plugin
+*
+* Use the ping program to check connection statistics for a remote host.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ping";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "popen.h"
+#include "utils.h"
+
+#include <signal.h>
+
+#define WARN_DUPLICATES "DUPLICATES FOUND! "
+#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
+
+enum {
+ UNKNOWN_PACKET_LOSS = 200, /* 200% */
+ DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
+};
+
+int process_arguments (int, char **);
+int get_threshold (char *, float *, int *);
+int validate_arguments (void);
+int run_ping (const char *cmd, const char *addr);
+int error_scan (char buf[MAX_INPUT_BUFFER], const char *addr);
+void print_usage (void);
+void print_help (void);
+
+int display_html = FALSE;
+int wpl = UNKNOWN_PACKET_LOSS;
+int cpl = UNKNOWN_PACKET_LOSS;
+float wrta = UNKNOWN_TRIP_TIME;
+float crta = UNKNOWN_TRIP_TIME;
+char **addresses = NULL;
+int n_addresses = 0;
+int max_addr = 1;
+int max_packets = -1;
+int verbose = 0;
+
+float rta = UNKNOWN_TRIP_TIME;
+int pl = UNKNOWN_PACKET_LOSS;
+
+char *warn_text;
+
+
+
+int
+main (int argc, char **argv)
+{
+ char *cmd = NULL;
+ char *rawcmd = NULL;
+ int result = STATE_UNKNOWN;
+ int this_result = STATE_UNKNOWN;
+ int i;
+
+ setlocale (LC_ALL, "");
+ setlocale (LC_NUMERIC, "C");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ addresses = malloc (sizeof(char*) * max_addr);
+ addresses[0] = NULL;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
+ usage4 (_("Cannot catch SIGALRM"));
+ }
+
+ /* If ./configure finds ping has timeout values, set plugin alarm slightly
+ * higher so that we can use response from command line ping */
+#if defined(PING_PACKETS_FIRST) && defined(PING_HAS_TIMEOUT)
+ alarm (timeout_interval + 1);
+#else
+ alarm (timeout_interval);
+#endif
+
+ for (i = 0 ; i < n_addresses ; i++) {
+
+#ifdef PING6_COMMAND
+ if (address_family != AF_INET && is_inet6_addr(addresses[i]))
+ rawcmd = strdup(PING6_COMMAND);
+ else
+ rawcmd = strdup(PING_COMMAND);
+#else
+ rawcmd = strdup(PING_COMMAND);
+#endif
+
+ /* does the host address of number of packets argument come first? */
+#ifdef PING_PACKETS_FIRST
+# ifdef PING_HAS_TIMEOUT
+ xasprintf (&cmd, rawcmd, timeout_interval, max_packets, addresses[i]);
+# else
+ xasprintf (&cmd, rawcmd, max_packets, addresses[i]);
+# endif
+#else
+ xasprintf (&cmd, rawcmd, addresses[i], max_packets);
+#endif
+
+ if (verbose >= 2)
+ printf ("CMD: %s\n", cmd);
+
+ /* run the command */
+ this_result = run_ping (cmd, addresses[i]);
+
+ if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) {
+ printf ("%s\n", cmd);
+ die (STATE_UNKNOWN,
+ _("CRITICAL - Could not interpret output from ping command\n"));
+ }
+
+ if (pl >= cpl || rta >= crta || rta < 0)
+ this_result = STATE_CRITICAL;
+ else if (pl >= wpl || rta >= wrta)
+ this_result = STATE_WARNING;
+ else if (pl >= 0 && rta >= 0)
+ this_result = max_state (STATE_OK, this_result);
+
+ if (n_addresses > 1 && this_result != STATE_UNKNOWN)
+ die (STATE_OK, "%s is alive\n", addresses[i]);
+
+ if (display_html == TRUE)
+ printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]);
+ if (pl == 100)
+ printf (_("PING %s - %sPacket loss = %d%%"), state_text (this_result), warn_text,
+ pl);
+ else
+ printf (_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"),
+ state_text (this_result), warn_text, pl, rta);
+ if (display_html == TRUE)
+ printf ("</A>");
+
+ /* Print performance data */
+ if (pl != 100) {
+ printf("|%s", fperfdata ("rta", (double) rta, "ms",
+ wrta>0?TRUE:FALSE, wrta,
+ crta>0?TRUE:FALSE, crta,
+ TRUE, 0, FALSE, 0));
+ } else {
+ printf("| rta=U;%f;%f;;", wrta, crta);
+ }
+ printf(" %s\n", perfdata ("pl", (long) pl, "%",
+ wpl>0?TRUE:FALSE, wpl,
+ cpl>0?TRUE:FALSE, cpl,
+ TRUE, 0, FALSE, 0));
+
+ if (verbose >= 2)
+ printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl);
+
+ result = max_state (result, this_result);
+ free (rawcmd);
+ free (cmd);
+ }
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c = 1;
+ char *ptr;
+
+ int option = 0;
+ static struct option longopts[] = {
+ STD_LONG_OPTS,
+ {"packets", required_argument, 0, 'p'},
+ {"nohtml", no_argument, 0, 'n'},
+ {"link", no_argument, 0, 'L'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ if (strcmp ("-nohtml", argv[c]) == 0)
+ strcpy (argv[c], "-n");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* usage */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ break;
+ case 't': /* timeout period */
+ timeout_interval = atoi (optarg);
+ break;
+ case 'v': /* verbose mode */
+ verbose++;
+ break;
+ case '4': /* IPv4 only */
+ address_family = AF_INET;
+ break;
+ case '6': /* IPv6 only */
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage (_("IPv6 support not available\n"));
+#endif
+ break;
+ case 'H': /* hostname */
+ ptr=optarg;
+ while (1) {
+ n_addresses++;
+ if (n_addresses > max_addr) {
+ max_addr *= 2;
+ addresses = realloc (addresses, sizeof(char*) * max_addr);
+ if (addresses == NULL)
+ die (STATE_UNKNOWN, _("Could not realloc() addresses\n"));
+ }
+ addresses[n_addresses-1] = ptr;
+ if ((ptr = index (ptr, ','))) {
+ strcpy (ptr, "");
+ ptr += sizeof(char);
+ } else {
+ break;
+ }
+ }
+ break;
+ case 'p': /* number of packets to send */
+ if (is_intnonneg (optarg))
+ max_packets = atoi (optarg);
+ else
+ usage2 (_("<max_packets> (%s) must be a non-negative number\n"), optarg);
+ break;
+ case 'n': /* no HTML */
+ display_html = FALSE;
+ break;
+ case 'L': /* show HTML */
+ display_html = TRUE;
+ break;
+ case 'c':
+ get_threshold (optarg, &crta, &cpl);
+ break;
+ case 'w':
+ get_threshold (optarg, &wrta, &wpl);
+ break;
+ }
+ }
+
+ c = optind;
+ if (c == argc)
+ return validate_arguments ();
+
+ if (addresses[0] == NULL) {
+ if (is_host (argv[c]) == FALSE) {
+ usage2 (_("Invalid hostname/address"), argv[c]);
+ } else {
+ addresses[0] = argv[c++];
+ n_addresses++;
+ if (c == argc)
+ return validate_arguments ();
+ }
+ }
+
+ if (wpl == UNKNOWN_PACKET_LOSS) {
+ if (is_intpercent (argv[c]) == FALSE) {
+ printf (_("<wpl> (%s) must be an integer percentage\n"), argv[c]);
+ return ERROR;
+ } else {
+ wpl = atoi (argv[c++]);
+ if (c == argc)
+ return validate_arguments ();
+ }
+ }
+
+ if (cpl == UNKNOWN_PACKET_LOSS) {
+ if (is_intpercent (argv[c]) == FALSE) {
+ printf (_("<cpl> (%s) must be an integer percentage\n"), argv[c]);
+ return ERROR;
+ } else {
+ cpl = atoi (argv[c++]);
+ if (c == argc)
+ return validate_arguments ();
+ }
+ }
+
+ if (wrta < 0.0) {
+ if (is_negative (argv[c])) {
+ printf (_("<wrta> (%s) must be a non-negative number\n"), argv[c]);
+ return ERROR;
+ } else {
+ wrta = atof (argv[c++]);
+ if (c == argc)
+ return validate_arguments ();
+ }
+ }
+
+ if (crta < 0.0) {
+ if (is_negative (argv[c])) {
+ printf (_("<crta> (%s) must be a non-negative number\n"), argv[c]);
+ return ERROR;
+ } else {
+ crta = atof (argv[c++]);
+ if (c == argc)
+ return validate_arguments ();
+ }
+ }
+
+ if (max_packets == -1) {
+ if (is_intnonneg (argv[c])) {
+ max_packets = atoi (argv[c++]);
+ } else {
+ printf (_("<max_packets> (%s) must be a non-negative number\n"), argv[c]);
+ return ERROR;
+ }
+ }
+
+ return validate_arguments ();
+}
+
+
+
+int
+get_threshold (char *arg, float *trta, int *tpl)
+{
+ if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1)
+ return OK;
+ else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2)
+ return OK;
+ else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1)
+ return OK;
+
+ usage2 (_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
+ return STATE_UNKNOWN;
+}
+
+
+
+int
+validate_arguments ()
+{
+ float max_seconds;
+ int i;
+
+ if (wrta < 0.0) {
+ printf (_("<wrta> was not set\n"));
+ return ERROR;
+ }
+ else if (crta < 0.0) {
+ printf (_("<crta> was not set\n"));
+ return ERROR;
+ }
+ else if (wpl == UNKNOWN_PACKET_LOSS) {
+ printf (_("<wpl> was not set\n"));
+ return ERROR;
+ }
+ else if (cpl == UNKNOWN_PACKET_LOSS) {
+ printf (_("<cpl> was not set\n"));
+ return ERROR;
+ }
+ else if (wrta > crta) {
+ printf (_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta);
+ return ERROR;
+ }
+ else if (wpl > cpl) {
+ printf (_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl);
+ return ERROR;
+ }
+
+ if (max_packets == -1)
+ max_packets = DEFAULT_MAX_PACKETS;
+
+ max_seconds = crta / 1000.0 * max_packets + max_packets;
+ if (max_seconds > timeout_interval)
+ timeout_interval = (int)max_seconds;
+
+ for (i=0; i<n_addresses; i++) {
+ if (is_host(addresses[i]) == FALSE)
+ usage2 (_("Invalid hostname/address"), addresses[i]);
+ }
+
+ if (n_addresses == 0) {
+ usage (_("You must specify a server address or host name"));
+ }
+
+ return OK;
+}
+
+
+
+int
+run_ping (const char *cmd, const char *addr)
+{
+ char buf[MAX_INPUT_BUFFER];
+ int result = STATE_UNKNOWN;
+ int match;
+
+ if ((child_process = spopen (cmd)) == NULL)
+ die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL)
+ printf (_("Cannot open stderr for %s\n"), cmd);
+
+ while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) {
+
+ if (verbose >= 3)
+ printf("Output: %s", buf);
+
+ result = max_state (result, error_scan (buf, addr));
+
+ /* get the percent loss statistics */
+ match = 0;
+ if((sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% loss, time%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, time%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d received, %d%% packet loss, time%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) ||
+ (sscanf(buf,"%*[^(](%d%% %*[^)])%n",&pl,&match) && match)
+ )
+ continue;
+
+ /* get the round trip average */
+ else
+ if((sscanf(buf,"round-trip min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip (ms) min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) ||
+ (sscanf(buf,"rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n",&rta,&match) && match) ||
+ (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)
+ )
+ continue;
+ }
+
+ /* this is needed because there is no rta if all packets are lost */
+ if (pl == 100)
+ rta = crta;
+
+ /* check stderr, setting at least WARNING if there is output here */
+ /* Add warning into warn_text */
+ while (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
+ if (
+ ! strstr(buf,"WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP")
+ && ! strstr(buf,"Warning: time of day goes back")
+
+ ) {
+ if (verbose >= 3) {
+ printf("Got stderr: %s", buf);
+ }
+ if ((result=error_scan(buf, addr)) == STATE_OK) {
+ result = STATE_WARNING;
+ if (warn_text == NULL) {
+ warn_text = strdup(_("System call sent warnings to stderr "));
+ } else {
+ xasprintf(&warn_text, "%s %s", warn_text, _("System call sent warnings to stderr "));
+ }
+ }
+ }
+ }
+
+ (void) fclose (child_stderr);
+
+
+ spclose (child_process);
+
+ if (warn_text == NULL)
+ warn_text = strdup("");
+
+ return result;
+}
+
+
+
+int
+error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
+{
+ if (strstr (buf, "Network is unreachable") ||
+ strstr (buf, "Destination Net Unreachable") ||
+ strstr (buf, "No route")
+ )
+ die (STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
+ else if (strstr (buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable"))
+ die (STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
+ else if (strstr (buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable"))
+ die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
+ else if (strstr (buf, "Destination Protocol Unreachable"))
+ die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
+ else if (strstr (buf, "Destination Net Prohibited"))
+ die (STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
+ else if (strstr (buf, "Destination Host Prohibited"))
+ die (STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
+ else if (strstr (buf, "Packet filtered") || strstr(buf, "Administratively prohibited"))
+ die (STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
+ else if (strstr (buf, "unknown host" ))
+ die (STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
+ else if (strstr (buf, "Time to live exceeded") || strstr(buf, "Time exceeded"))
+ die (STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
+ else if (strstr (buf, "Destination unreachable: "))
+ die (STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
+
+ if (strstr (buf, "(DUP!)") || strstr (buf, "DUPLICATES FOUND")) {
+ if (warn_text == NULL)
+ warn_text = strdup (_(WARN_DUPLICATES));
+ else if (! strstr (warn_text, _(WARN_DUPLICATES)) &&
+ xasprintf (&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1)
+ die (STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
+ return (STATE_WARNING);
+ }
+
+ return (STATE_OK);
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("Use ping to check connection statistics for a remote host."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-H, --hostname=HOST");
+ printf (" %s\n", _("host to ping"));
+ printf (" %s\n", "-w, --warning=THRESHOLD");
+ printf (" %s\n", _("warning threshold pair"));
+ printf (" %s\n", "-c, --critical=THRESHOLD");
+ printf (" %s\n", _("critical threshold pair"));
+ printf (" %s\n", "-p, --packets=INTEGER");
+ printf (" %s ", _("number of ICMP ECHO packets to send"));
+ printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS);
+ printf (" %s\n", "-L, --link");
+ printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf ("\n");
+ printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel"));
+ printf ("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the"));
+ printf ("%s\n", _("percentage of packet loss to trigger an alarm state."));
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
+ printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output"));
+ printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
+ printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
+ printf (" [-p packets] [-t timeout] [-4|-6]\n");
+}
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
new file mode 100644
index 0000000..1637e3e
--- /dev/null
+++ b/plugins/check_procs.c
@@ -0,0 +1,834 @@
+/*****************************************************************************
+*
+* Monitoring check_procs plugin
+*
+* License: GPL
+* Copyright (c) 2000-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_procs plugin
+*
+* Checks all processes and generates WARNING or CRITICAL states if the
+* specified metric is outside the required threshold ranges. The metric
+* defaults to number of processes. Search filters can be applied to limit
+* the processes to check.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_procs";
+const char *program_name = "check_procs"; /* Required for coreutils libs */
+const char *copyright = "2000-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "utils_cmd.h"
+#include "regex.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+int convert_to_seconds (char *);
+void print_help (void);
+void print_usage (void);
+
+char *warning_range = NULL;
+char *critical_range = NULL;
+thresholds *procs_thresholds = NULL;
+
+int options = 0; /* bitmask of filter criteria to test against */
+#define ALL 1
+#define STAT 2
+#define PPID 4
+#define USER 8
+#define PROG 16
+#define ARGS 32
+#define VSZ 64
+#define RSS 128
+#define PCPU 256
+#define ELAPSED 512
+#define EREG_ARGS 1024
+#define EXCLUDE_PROGS 2048
+
+#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads:
+ ppid of procs are compared to pid of this proc*/
+
+/* Different metrics */
+char *metric_name;
+enum metric {
+ METRIC_PROCS,
+ METRIC_VSZ,
+ METRIC_RSS,
+ METRIC_CPU,
+ METRIC_ELAPSED
+};
+enum metric metric = METRIC_PROCS;
+
+int verbose = 0;
+int uid;
+pid_t ppid;
+int vsz;
+int rss;
+float pcpu;
+char *statopts;
+char *prog;
+char *exclude_progs;
+char **exclude_progs_arr = NULL;
+char exclude_progs_counter = 0;
+char *args;
+char *input_filename = NULL;
+regex_t re_args;
+char *fmt;
+char *fails;
+char tmp[MAX_INPUT_BUFFER];
+int kthread_filter = 0;
+int usepid = 0; /* whether to test for pid or /proc/pid/exe */
+
+FILE *ps_input = NULL;
+
+static int
+stat_exe (const pid_t pid, struct stat *buf) {
+ char *path;
+ int ret;
+ xasprintf(&path, "/proc/%d/exe", pid);
+ ret = stat(path, buf);
+ free(path);
+ return ret;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ char *input_buffer;
+ char *input_line;
+ char *procprog;
+
+ pid_t mypid = 0;
+ pid_t myppid = 0;
+ struct stat statbuf;
+ dev_t mydev = 0;
+ ino_t myino = 0;
+ int procuid = 0;
+ pid_t procpid = 0;
+ pid_t procppid = 0;
+ pid_t kthread_ppid = 0;
+ int procvsz = 0;
+ int procrss = 0;
+ int procseconds = 0;
+ float procpcpu = 0;
+ char procstat[8];
+ char procetime[MAX_INPUT_BUFFER] = { '\0' };
+ char *procargs;
+
+ const char *zombie = "Z";
+
+ int resultsum = 0; /* bitmask of the filter criteria met by a process */
+ int found = 0; /* counter for number of lines returned in `ps` output */
+ int procs = 0; /* counter for number of processes meeting filter criteria */
+ int pos; /* number of spaces before 'args' in `ps` output */
+ int cols; /* number of columns in ps output */
+ int expected_cols = PS_COLS - 1;
+ int warn = 0; /* number of processes in warn state */
+ int crit = 0; /* number of processes in crit state */
+ int i = 0, j = 0;
+ int result = STATE_UNKNOWN;
+ int ret = 0;
+ output chld_out, chld_err;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ setlocale(LC_NUMERIC, "POSIX");
+
+ input_buffer = malloc (MAX_INPUT_BUFFER);
+ procprog = malloc (MAX_INPUT_BUFFER);
+
+ xasprintf (&metric_name, "PROCS");
+ metric = METRIC_PROCS;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* find ourself */
+ mypid = getpid();
+ myppid = getppid();
+ if (usepid || stat_exe(mypid, &statbuf) == -1) {
+ /* usepid might have been set by -T */
+ usepid = 1;
+ } else {
+ usepid = 0;
+ mydev = statbuf.st_dev;
+ myino = statbuf.st_ino;
+ }
+
+ /* Set signal handling and alarm timeout */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
+ die (STATE_UNKNOWN, _("Cannot catch SIGALRM"));
+ }
+ (void) alarm ((unsigned) timeout_interval);
+
+ if (verbose >= 2)
+ printf (_("CMD: %s\n"), PS_COMMAND);
+
+ if (input_filename == NULL) {
+ result = cmd_run( PS_COMMAND, &chld_out, &chld_err, 0);
+ if (chld_err.lines > 0) {
+ printf ("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]);
+ exit(STATE_WARNING);
+ }
+ } else {
+ result = cmd_file_read( input_filename, &chld_out, 0);
+ }
+
+ /* flush first line: j starts at 1 */
+ for (j = 1; j < chld_out.lines; j++) {
+ input_line = chld_out.line[j];
+
+ if (verbose >= 3)
+ printf ("%s", input_line);
+
+ strcpy (procprog, "");
+ xasprintf (&procargs, "%s", "");
+
+ cols = sscanf (input_line, PS_FORMAT, PS_VARLIST);
+
+ /* Zombie processes do not give a procprog command */
+ if ( cols < expected_cols && strstr(procstat, zombie) ) {
+ cols = expected_cols;
+ }
+ if ( cols >= expected_cols ) {
+ resultsum = 0;
+ xasprintf (&procargs, "%s", input_line + pos);
+ strip (procargs);
+
+ /* Some ps return full pathname for command. This removes path */
+ strcpy(procprog, base_name(procprog));
+
+ /* we need to convert the elapsed time to seconds */
+ procseconds = convert_to_seconds(procetime);
+
+ if (verbose >= 3)
+ printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
+ procs, procuid, procvsz, procrss,
+ procpid, procppid, procpcpu, procstat,
+ procetime, procprog, procargs);
+
+ /* Ignore self */
+ if ((usepid && mypid == procpid) ||
+ ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
+ (ret == -1 && errno == ENOENT))
+ ) {
+ if (verbose >= 3)
+ printf("not considering - is myself or gone\n");
+ continue;
+ }
+ /* Ignore parent*/
+ else if (myppid == procpid) {
+ if (verbose >= 3)
+ printf("not considering - is parent\n");
+ continue;
+ }
+
+ /* Ignore excluded processes by name */
+ if(options & EXCLUDE_PROGS) {
+ int found = 0;
+ int i = 0;
+
+ for(i=0; i < (exclude_progs_counter); i++) {
+ if(!strcmp(procprog, exclude_progs_arr[i])) {
+ found = 1;
+ }
+ }
+ if(found == 0) {
+ resultsum |= EXCLUDE_PROGS;
+ } else
+ {
+ if(verbose >= 3)
+ printf("excluding - by ignorelist\n");
+ }
+ }
+
+ /* filter kernel threads (children of KTHREAD_PARENT)*/
+ /* TODO adapt for other OSes than GNU/Linux
+ sorry for not doing that, but I've no other OSes to test :-( */
+ if (kthread_filter == 1) {
+ /* get pid KTHREAD_PARENT */
+ if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) )
+ kthread_ppid = procpid;
+
+ if (kthread_ppid == procppid) {
+ if (verbose >= 2)
+ printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
+ continue;
+ }
+ }
+
+ if ((options & STAT) && (strstr (procstat, statopts)))
+ resultsum |= STAT;
+ if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
+ resultsum |= ARGS;
+ if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0))
+ resultsum |= EREG_ARGS;
+ if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
+ resultsum |= PROG;
+ if ((options & PPID) && (procppid == ppid))
+ resultsum |= PPID;
+ if ((options & USER) && (procuid == uid))
+ resultsum |= USER;
+ if ((options & VSZ) && (procvsz >= vsz))
+ resultsum |= VSZ;
+ if ((options & RSS) && (procrss >= rss))
+ resultsum |= RSS;
+ if ((options & PCPU) && (procpcpu >= pcpu))
+ resultsum |= PCPU;
+
+ found++;
+
+ /* Next line if filters not matched */
+ if (!(options == resultsum || options == ALL))
+ continue;
+
+ procs++;
+ if (verbose >= 2) {
+ printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
+ procuid, procvsz, procrss,
+ procpid, procppid, procpcpu, procstat,
+ procetime, procprog, procargs);
+ }
+
+ if (metric == METRIC_VSZ)
+ i = get_status ((double)procvsz, procs_thresholds);
+ else if (metric == METRIC_RSS)
+ i = get_status ((double)procrss, procs_thresholds);
+ /* TODO? float thresholds for --metric=CPU */
+ else if (metric == METRIC_CPU)
+ i = get_status (procpcpu, procs_thresholds);
+ else if (metric == METRIC_ELAPSED)
+ i = get_status ((double)procseconds, procs_thresholds);
+
+ if (metric != METRIC_PROCS) {
+ if (i == STATE_WARNING) {
+ warn++;
+ xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
+ result = max_state (result, i);
+ }
+ if (i == STATE_CRITICAL) {
+ crit++;
+ xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
+ result = max_state (result, i);
+ }
+ }
+ }
+ /* This should not happen */
+ else if (verbose) {
+ printf(_("Not parseable: %s"), input_buffer);
+ }
+ }
+
+ if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
+ printf (_("Unable to read output\n"));
+ return STATE_UNKNOWN;
+ }
+
+ if ( result == STATE_UNKNOWN )
+ result = STATE_OK;
+
+ /* Needed if procs found, but none match filter */
+ if ( metric == METRIC_PROCS ) {
+ result = max_state (result, get_status ((double)procs, procs_thresholds) );
+ }
+
+ if ( result == STATE_OK ) {
+ printf ("%s %s: ", metric_name, _("OK"));
+ } else if (result == STATE_WARNING) {
+ printf ("%s %s: ", metric_name, _("WARNING"));
+ if ( metric != METRIC_PROCS ) {
+ printf (_("%d warn out of "), warn);
+ }
+ } else if (result == STATE_CRITICAL) {
+ printf ("%s %s: ", metric_name, _("CRITICAL"));
+ if (metric != METRIC_PROCS) {
+ printf (_("%d crit, %d warn out of "), crit, warn);
+ }
+ }
+ printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs);
+
+ if (strcmp(fmt,"") != 0) {
+ printf (_(" with %s"), fmt);
+ }
+
+ if ( verbose >= 1 && strcmp(fails,"") )
+ printf (" [%s]", fails);
+
+ if (metric == METRIC_PROCS)
+ printf (" | procs=%d;%s;%s;0;", procs,
+ warning_range ? warning_range : "",
+ critical_range ? critical_range : "");
+ else
+ printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
+
+ printf ("\n");
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c = 1;
+ char *user;
+ struct passwd *pw;
+ int option = 0;
+ int err;
+ int cflags = REG_NOSUB | REG_EXTENDED;
+ char errbuf[MAX_INPUT_BUFFER];
+ char *temp_string;
+ int i=0;
+ static struct option longopts[] = {
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"metric", required_argument, 0, 'm'},
+ {"timeout", required_argument, 0, 't'},
+ {"status", required_argument, 0, 's'},
+ {"ppid", required_argument, 0, 'p'},
+ {"user", required_argument, 0, 'u'},
+ {"command", required_argument, 0, 'C'},
+ {"vsz", required_argument, 0, 'z'},
+ {"rss", required_argument, 0, 'r'},
+ {"pcpu", required_argument, 0, 'P'},
+ {"elapsed", required_argument, 0, 'e'},
+ {"argument-array", required_argument, 0, 'a'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
+ {"input-file", required_argument, 0, CHAR_MAX+2},
+ {"no-kthreads", required_argument, 0, 'k'},
+ {"traditional-filter", no_argument, 0, 'T'},
+ {"exclude-process", required_argument, 0, 'X'},
+ {0, 0, 0, 0}
+ };
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ while (1) {
+ c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:",
+ longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* help */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ timeout_interval = atoi (optarg);
+ break;
+ case 'c': /* critical threshold */
+ critical_range = optarg;
+ break;
+ case 'w': /* warning threshold */
+ warning_range = optarg;
+ break;
+ case 'p': /* process id */
+ if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
+ xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
+ options |= PPID;
+ break;
+ }
+ usage4 (_("Parent Process ID must be an integer!"));
+ case 's': /* status */
+ if (statopts)
+ break;
+ else
+ statopts = optarg;
+ xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
+ options |= STAT;
+ break;
+ case 'u': /* user or user id */
+ if (is_integer (optarg)) {
+ uid = atoi (optarg);
+ pw = getpwuid ((uid_t) uid);
+ /* check to be sure user exists */
+ if (pw == NULL)
+ usage2 (_("UID was not found"), optarg);
+ }
+ else {
+ pw = getpwnam (optarg);
+ /* check to be sure user exists */
+ if (pw == NULL)
+ usage2 (_("User name was not found"), optarg);
+ /* then get uid */
+ uid = pw->pw_uid;
+ }
+ user = pw->pw_name;
+ xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
+ uid, user);
+ options |= USER;
+ break;
+ case 'C': /* command */
+ /* TODO: allow this to be passed in with --metric */
+ if (prog)
+ break;
+ else
+ prog = optarg;
+ xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
+ prog);
+ options |= PROG;
+ break;
+ case 'X':
+ if(exclude_progs)
+ break;
+ else
+ exclude_progs = optarg;
+ xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
+ exclude_progs);
+ char *p = strtok(exclude_progs, ",");
+
+ while(p){
+ exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter);
+ exclude_progs_arr[exclude_progs_counter-1] = p;
+ p = strtok(NULL, ",");
+ }
+
+ options |= EXCLUDE_PROGS;
+ break;
+ case 'a': /* args (full path name with args) */
+ /* TODO: allow this to be passed in with --metric */
+ if (args)
+ break;
+ else
+ args = optarg;
+ xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
+ options |= ARGS;
+ break;
+ case CHAR_MAX+1:
+ err = regcomp(&re_args, optarg, cflags);
+ if (err != 0) {
+ regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER);
+ die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
+ }
+ /* Strip off any | within the regex optarg */
+ temp_string = strdup(optarg);
+ while(temp_string[i]!='\0'){
+ if(temp_string[i]=='|')
+ temp_string[i]=',';
+ i++;
+ }
+ xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string);
+ options |= EREG_ARGS;
+ break;
+ case 'r': /* RSS */
+ if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) {
+ xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
+ options |= RSS;
+ break;
+ }
+ usage4 (_("RSS must be an integer!"));
+ case 'z': /* VSZ */
+ if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) {
+ xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
+ options |= VSZ;
+ break;
+ }
+ usage4 (_("VSZ must be an integer!"));
+ case 'P': /* PCPU */
+ /* TODO: -P 1.5.5 is accepted */
+ if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) {
+ xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
+ options |= PCPU;
+ break;
+ }
+ usage4 (_("PCPU must be a float!"));
+ case 'm':
+ xasprintf (&metric_name, "%s", optarg);
+ if ( strcmp(optarg, "PROCS") == 0) {
+ metric = METRIC_PROCS;
+ break;
+ }
+ else if ( strcmp(optarg, "VSZ") == 0) {
+ metric = METRIC_VSZ;
+ break;
+ }
+ else if ( strcmp(optarg, "RSS") == 0 ) {
+ metric = METRIC_RSS;
+ break;
+ }
+ else if ( strcmp(optarg, "CPU") == 0 ) {
+ metric = METRIC_CPU;
+ break;
+ }
+ else if ( strcmp(optarg, "ELAPSED") == 0) {
+ metric = METRIC_ELAPSED;
+ break;
+ }
+
+ usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
+ case 'k': /* linux kernel thread filter */
+ kthread_filter = 1;
+ break;
+ case 'v': /* command */
+ verbose++;
+ break;
+ case 'T':
+ usepid = 1;
+ break;
+ case CHAR_MAX+2:
+ input_filename = optarg;
+ break;
+ }
+ }
+
+ c = optind;
+ if ((! warning_range) && argv[c])
+ warning_range = argv[c++];
+ if ((! critical_range) && argv[c])
+ critical_range = argv[c++];
+ if (statopts == NULL && argv[c]) {
+ xasprintf (&statopts, "%s", argv[c++]);
+ xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
+ options |= STAT;
+ }
+
+ /* this will abort in case of invalid ranges */
+ set_thresholds (&procs_thresholds, warning_range, critical_range);
+
+ return validate_arguments ();
+}
+
+
+
+int
+validate_arguments ()
+{
+ if (options == 0)
+ options = ALL;
+
+ if (statopts==NULL)
+ statopts = strdup("");
+
+ if (prog==NULL)
+ prog = strdup("");
+
+ if (args==NULL)
+ args = strdup("");
+
+ if (fmt==NULL)
+ fmt = strdup("");
+
+ if (fails==NULL)
+ fails = strdup("");
+
+ return options;
+}
+
+
+/* convert the elapsed time to seconds */
+int
+convert_to_seconds(char *etime) {
+
+ char *ptr;
+ int total;
+
+ int hyphcnt;
+ int coloncnt;
+ int days;
+ int hours;
+ int minutes;
+ int seconds;
+
+ hyphcnt = 0;
+ coloncnt = 0;
+ days = 0;
+ hours = 0;
+ minutes = 0;
+ seconds = 0;
+
+ for (ptr = etime; *ptr != '\0'; ptr++) {
+
+ if (*ptr == '-') {
+ hyphcnt++;
+ continue;
+ }
+ if (*ptr == ':') {
+ coloncnt++;
+ continue;
+ }
+ }
+
+ if (hyphcnt > 0) {
+ sscanf(etime, "%d-%d:%d:%d",
+ &days, &hours, &minutes, &seconds);
+ /* linux 2.6.5/2.6.6 reporting some processes with infinite
+ * elapsed times for some reason */
+ if (days == 49710) {
+ return 0;
+ }
+ } else {
+ if (coloncnt == 2) {
+ sscanf(etime, "%d:%d:%d",
+ &hours, &minutes, &seconds);
+ } else if (coloncnt == 1) {
+ sscanf(etime, "%d:%d",
+ &minutes, &seconds);
+ }
+ }
+
+ total = (days * 86400) +
+ (hours * 3600) +
+ (minutes * 60) +
+ seconds;
+
+ if (verbose >= 3 && metric == METRIC_ELAPSED) {
+ printf("seconds: %d\n", total);
+ }
+ return total;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
+ printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number"));
+ printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (" %s\n", "-w, --warning=RANGE");
+ printf (" %s\n", _("Generate warning state if metric is outside this range"));
+ printf (" %s\n", "-c, --critical=RANGE");
+ printf (" %s\n", _("Generate critical state if metric is outside this range"));
+ printf (" %s\n", "-m, --metric=TYPE");
+ printf (" %s\n", _("Check thresholds against metric. Valid types:"));
+ printf (" %s\n", _("PROCS - number of processes (default)"));
+ printf (" %s\n", _("VSZ - virtual memory size"));
+ printf (" %s\n", _("RSS - resident set memory size"));
+ printf (" %s\n", _("CPU - percentage CPU"));
+/* only linux etime is support currently */
+#if defined( __linux__ )
+ printf (" %s\n", _("ELAPSED - time elapsed in seconds"));
+#endif /* defined(__linux__) */
+ printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (" %s\n", "-v, --verbose");
+ printf (" %s\n", _("Extra information. Up to 3 verbosity levels"));
+
+ printf (" %s\n", "-T, --traditional");
+ printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
+
+ printf ("\n");
+ printf ("%s\n", "Filters:");
+ printf (" %s\n", "-s, --state=STATUSFLAGS");
+ printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
+ printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
+ printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
+ printf (" %s\n", "-p, --ppid=PPID");
+ printf (" %s\n", _("Only scan for children of the parent process ID indicated."));
+ printf (" %s\n", "-z, --vsz=VSZ");
+ printf (" %s\n", _("Only scan for processes with VSZ higher than indicated."));
+ printf (" %s\n", "-r, --rss=RSS");
+ printf (" %s\n", _("Only scan for processes with RSS higher than indicated."));
+ printf (" %s\n", "-P, --pcpu=PCPU");
+ printf (" %s\n", _("Only scan for processes with PCPU higher than indicated."));
+ printf (" %s\n", "-u, --user=USER");
+ printf (" %s\n", _("Only scan for processes with user name or ID indicated."));
+ printf (" %s\n", "-a, --argument-array=STRING");
+ printf (" %s\n", _("Only scan for processes with args that contain STRING."));
+ printf (" %s\n", "--ereg-argument-array=STRING");
+ printf (" %s\n", _("Only scan for processes with args that contain the regex STRING."));
+ printf (" %s\n", "-C, --command=COMMAND");
+ printf (" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
+ printf (" %s\n", "-X, --exclude-process");
+ printf (" %s\n", _("Exclude processes which match this comma separated list"));
+ printf (" %s\n", "-k, --no-kthreads");
+ printf (" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
+
+ printf(_("\n\
+RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
+specified 'max:min', a warning status will be generated if the\n\
+count is inside the specified range\n\n"));
+
+ printf(_("\
+This plugin checks the number of currently running processes and\n\
+generates WARNING or CRITICAL states if the process count is outside\n\
+the specified threshold ranges. The process count can be filtered by\n\
+process owner, parent process PID, current state (e.g., 'Z'), or may\n\
+be the total number of running processes\n\n"));
+
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
+ printf (" %s\n", _("Warning if not two processes with command name portsentry."));
+ printf (" %s\n\n", _("Critical if < 2 or > 1024 processes"));
+ printf (" %s\n", "check_procs -c 1: -C sshd");
+ printf (" %s\n", _("Critical if not at least 1 process with command sshd"));
+ printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd");
+ printf (" %s\n", _("Warning if > 1024 processes with command name sshd."));
+ printf (" %s\n\n", _("Critical if < 1 processes with command name sshd."));
+ printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
+ printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
+ printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
+ printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
+ printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
+ printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
+ printf (" %s\n", _("Alert if CPU of any processes over 10\% or 20\%"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
+ printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
+ printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
+}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
new file mode 100644
index 0000000..b1b4938
--- /dev/null
+++ b/plugins/check_radius.c
@@ -0,0 +1,416 @@
+/*****************************************************************************
+*
+* Monitoring check_radius plugin
+*
+* License: GPL
+* Copyright (c) 1999-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_radius plugin
+*
+* Tests to see if a radius server is accepting connections.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_radius";
+const char *copyright = "2000-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "netutils.h"
+
+#if defined(HAVE_LIBRADCLI)
+#include <radcli/radcli.h>
+#elif defined(HAVE_LIBFREERADIUS_CLIENT)
+#include <freeradius-client.h>
+#elif defined(HAVE_LIBRADIUSCLIENT_NG)
+#include <radiusclient-ng.h>
+#else
+#include <radiusclient.h>
+#endif
+
+int process_arguments (int, char **);
+void print_help (void);
+void print_usage (void);
+
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
+#define my_rc_conf_str(a) rc_conf_str(rch,a)
+#if defined(HAVE_LIBRADCLI)
+#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH)
+#else
+#define my_rc_send_server(a,b) rc_send_server(rch,a,b)
+#endif
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
+#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f)
+#else
+#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f)
+#endif
+#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d)
+#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
+#else
+#define my_rc_conf_str(a) rc_conf_str(a)
+#define my_rc_send_server(a,b) rc_send_server(a, b)
+#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f)
+#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d)
+#define my_rc_read_dictionary(a) rc_read_dictionary(a)
+#endif
+
+/* REJECT_RC is only defined in some version of radiusclient. It has
+ * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
+#ifndef REJECT_RC
+#define REJECT_RC BADRESP_RC
+#endif
+
+int my_rc_read_config(char *);
+
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
+rc_handle *rch = NULL;
+#endif
+
+char *server = NULL;
+char *username = NULL;
+char *password = NULL;
+char *nasid = NULL;
+char *nasipaddress = NULL;
+char *expect = NULL;
+char *config_file = NULL;
+unsigned short port = PW_AUTH_UDP_PORT;
+int retries = 1;
+int verbose = FALSE;
+
+/******************************************************************************
+
+The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
+tags in the comments. With in the tags, the XML is assembled sequentially.
+You can define entities in tags. You also have all the #defines available as
+entities.
+
+Please note that all tags must be lowercase to use the DocBook XML DTD.
+
+@@-<article>
+
+<sect1>
+<title>Quick Reference</title>
+<!-- The refentry forms a manpage -->
+<refentry>
+<refmeta>
+<manvolnum>5<manvolnum>
+</refmeta>
+<refnamdiv>
+<refname>&progname;</refname>
+<refpurpose>&SUMMARY;</refpurpose>
+</refnamdiv>
+</refentry>
+</sect1>
+
+<sect1>
+<title>FAQ</title>
+</sect1>
+
+<sect1>
+<title>Theory, Installation, and Operation</title>
+
+<sect2>
+<title>General Description</title>
+<para>
+&DESCRIPTION;
+</para>
+</sect2>
+
+<sect2>
+<title>Future Enhancements</title>
+<para>Todo List</para>
+<itemizedlist>
+<listitem>Add option to get password from a secured file rather than the command line</listitem>
+</itemizedlist>
+</sect2>
+
+
+<sect2>
+<title>Functions</title>
+-@@
+******************************************************************************/
+
+
+
+int
+main (int argc, char **argv)
+{
+ struct sockaddr_storage ss;
+ char name[HOST_NAME_MAX];
+#ifdef RC_BUFFER_LEN
+ char msg[RC_BUFFER_LEN];
+#else
+ char msg[BUFFER_LEN];
+#endif
+ SEND_DATA data;
+ int result = STATE_UNKNOWN;
+ uint32_t client_id, service;
+ char *str;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ str = strdup ("dictionary");
+ if ((config_file && my_rc_read_config (config_file)) ||
+ my_rc_read_dictionary (my_rc_conf_str (str)))
+ die (STATE_UNKNOWN, _("Config file error\n"));
+
+ service = PW_AUTHENTICATE_ONLY;
+
+ memset (&data, 0, sizeof(data));
+ if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
+ my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) &&
+ my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0)
+ ))
+ die (STATE_UNKNOWN, _("Out of Memory?\n"));
+
+ if (nasid != NULL) {
+ if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0)))
+ die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
+ }
+
+ if (nasipaddress == NULL) {
+ if (gethostname (name, sizeof(name)) != 0)
+ die (STATE_UNKNOWN, _("gethostname() failed!\n"));
+ nasipaddress = name;
+ }
+ if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */
+ die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
+ client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
+ if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
+ die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
+
+ my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
+ retries);
+
+ result = my_rc_send_server (&data, msg);
+ rc_avpair_free (data.send_pairs);
+ if (data.receive_pairs)
+ rc_avpair_free (data.receive_pairs);
+
+ if (result == TIMEOUT_RC)
+ die (STATE_CRITICAL, _("Timeout\n"));
+ if (result == ERROR_RC)
+ die (STATE_CRITICAL, _("Auth Error\n"));
+ if (result == REJECT_RC)
+ die (STATE_WARNING, _("Auth Failed\n"));
+ if (result == BADRESP_RC)
+ die (STATE_WARNING, _("Bad Response\n"));
+ if (expect && !strstr (msg, expect))
+ die (STATE_WARNING, "%s\n", msg);
+ if (result == OK_RC)
+ die (STATE_OK, _("Auth OK\n"));
+ (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
+ die (STATE_UNKNOWN, "%s\n", msg);
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'P'},
+ {"username", required_argument, 0, 'u'},
+ {"password", required_argument, 0, 'p'},
+ {"nas-id", required_argument, 0, 'n'},
+ {"nas-ip-address", required_argument, 0, 'N'},
+ {"filename", required_argument, 0, 'F'},
+ {"expect", required_argument, 0, 'e'},
+ {"retries", required_argument, 0, 'r'},
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* verbose mode */
+ verbose = TRUE;
+ break;
+ case 'H': /* hostname */
+ if (is_host (optarg) == FALSE) {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ server = optarg;
+ break;
+ case 'P': /* port */
+ if (is_intnonneg (optarg))
+ port = (unsigned short)atoi (optarg);
+ else
+ usage4 (_("Port must be a positive integer"));
+ break;
+ case 'u': /* username */
+ username = optarg;
+ break;
+ case 'p': /* password */
+ password = strdup(optarg);
+
+ /* Delete the password from process list */
+ while (*optarg != '\0') {
+ *optarg = 'X';
+ optarg++;
+ }
+ break;
+ case 'n': /* nas id */
+ nasid = optarg;
+ break;
+ case 'N': /* nas ip address */
+ nasipaddress = optarg;
+ break;
+ case 'F': /* configuration file */
+ config_file = optarg;
+ break;
+ case 'e': /* expect */
+ expect = optarg;
+ break;
+ case 'r': /* retries */
+ if (is_intpos (optarg))
+ retries = atoi (optarg);
+ else
+ usage4 (_("Number of retries must be a positive integer"));
+ break;
+ case 't': /* timeout */
+ if (is_intpos (optarg))
+ timeout_interval = (unsigned)atoi (optarg);
+ else
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ break;
+ }
+ }
+
+ if (server == NULL)
+ usage4 (_("Hostname was not supplied"));
+ if (username == NULL)
+ usage4 (_("User not specified"));
+ if (password == NULL)
+ usage4 (_("Password not specified"));
+ if (config_file == NULL)
+ usage4 (_("Configuration file not specified"));
+
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", PW_AUTH_UDP_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Robert August Vincent II\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'P', myport);
+
+ printf (" %s\n", "-u, --username=STRING");
+ printf (" %s\n", _("The user to authenticate"));
+ printf (" %s\n", "-p, --password=STRING");
+ printf (" %s\n", _("Password for authentication (SECURITY RISK)"));
+ printf (" %s\n", "-n, --nas-id=STRING");
+ printf (" %s\n", _("NAS identifier"));
+ printf (" %s\n", "-N, --nas-ip-address=STRING");
+ printf (" %s\n", _("NAS IP Address"));
+ printf (" %s\n", "-F, --filename=STRING");
+ printf (" %s\n", _("Configuration file"));
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (" %s\n", _("Response string to expect from the server"));
+ printf (" %s\n", "-r, --retries=INTEGER");
+ printf (" %s\n", _("Number of times to retry a failed connection"));
+
+ printf (UT_CONN_TIMEOUT, timeout_interval);
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
+ printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
+ printf ("%s\n", _("name and password. A configuration file must be present. The format of"));
+ printf ("%s\n", _("the configuration file is described in the radiusclient library sources."));
+ printf ("%s\n", _("The password option presents a substantial security issue because the"));
+ printf ("%s\n", _("password can possibly be determined by careful watching of the command line"));
+ printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
+ printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
+ printf ("%s\n", _("the password used does not allow access to sensitive system resources."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host -F config_file -u username -p password\n\
+ [-P port] [-t timeout] [-r retries] [-e expect]\n\
+ [-n nas-id] [-N nas-ip-addr]\n", progname);
+}
+
+
+
+int my_rc_read_config(char * a)
+{
+#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
+ rch = rc_read_config(a);
+ return (rch == NULL) ? 1 : 0;
+#else
+ return rc_read_config(a);
+#endif
+}
diff --git a/plugins/check_real.c b/plugins/check_real.c
new file mode 100644
index 0000000..fbdb70f
--- /dev/null
+++ b/plugins/check_real.c
@@ -0,0 +1,454 @@
+/*****************************************************************************
+*
+* Monitoring check_real plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_real plugin
+*
+* This plugin tests the REAL service on the specified host.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_real";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum {
+ PORT = 554
+};
+
+#define EXPECT "RTSP/1."
+#define URL ""
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+int server_port = PORT;
+char *server_address;
+char *host_name;
+char *server_url = NULL;
+char *server_expect;
+int warning_time = 0;
+int check_warning_time = FALSE;
+int critical_time = 0;
+int check_critical_time = FALSE;
+int verbose = FALSE;
+
+
+
+int
+main (int argc, char **argv)
+{
+ int sd;
+ int result = STATE_UNKNOWN;
+ char buffer[MAX_INPUT_BUFFER];
+ char *status_line = NULL;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+ time (&start_time);
+
+ /* try to connect to the host at the given port number */
+ if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
+ die (STATE_CRITICAL, _("Unable to connect to %s on port %d\n"),
+ server_address, server_port);
+
+ /* Part I - Server Check */
+
+ /* send the OPTIONS request */
+ sprintf (buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port);
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* send the header sync */
+ sprintf (buffer, "CSeq: 1\r\n");
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* send a newline so the server knows we're done with the request */
+ sprintf (buffer, "\r\n");
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* watch for the REAL connection string */
+ result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
+
+ /* return a CRITICAL status if we couldn't read any data */
+ if (result == -1)
+ die (STATE_CRITICAL, _("No data received from %s\n"), host_name);
+
+ /* make sure we find the response we are looking for */
+ if (!strstr (buffer, server_expect)) {
+ if (server_port == PORT)
+ printf ("%s\n", _("Invalid REAL response received from host"));
+ else
+ printf (_("Invalid REAL response received from host on port %d\n"),
+ server_port);
+ }
+ else {
+ /* else we got the REAL string, so check the return code */
+
+ time (&end_time);
+
+ result = STATE_OK;
+
+ status_line = (char *) strtok (buffer, "\n");
+
+ if (strstr (status_line, "200"))
+ result = STATE_OK;
+
+ /* client errors result in a warning state */
+ else if (strstr (status_line, "400"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "401"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "402"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "403"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "404"))
+ result = STATE_WARNING;
+
+ /* server errors result in a critical state */
+ else if (strstr (status_line, "500"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "501"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "502"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "503"))
+ result = STATE_CRITICAL;
+
+ else
+ result = STATE_UNKNOWN;
+ }
+
+ /* Part II - Check stream exists and is ok */
+ if ((result == STATE_OK )&& (server_url != NULL) ) {
+
+ /* Part I - Server Check */
+
+ /* send the DESCRIBE request */
+ sprintf (buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name,
+ server_port, server_url);
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* send the header sync */
+ sprintf (buffer, "CSeq: 2\r\n");
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* send a newline so the server knows we're done with the request */
+ sprintf (buffer, "\r\n");
+ result = send (sd, buffer, strlen (buffer), 0);
+
+ /* watch for the REAL connection string */
+ result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
+ buffer[result] = '\0'; /* null terminate received buffer */
+
+ /* return a CRITICAL status if we couldn't read any data */
+ if (result == -1) {
+ printf (_("No data received from host\n"));
+ result = STATE_CRITICAL;
+ }
+ else {
+ /* make sure we find the response we are looking for */
+ if (!strstr (buffer, server_expect)) {
+ if (server_port == PORT)
+ printf ("%s\n", _("Invalid REAL response received from host"));
+ else
+ printf (_("Invalid REAL response received from host on port %d\n"),
+ server_port);
+ }
+ else {
+
+ /* else we got the REAL string, so check the return code */
+
+ time (&end_time);
+
+ result = STATE_OK;
+
+ status_line = (char *) strtok (buffer, "\n");
+
+ if (strstr (status_line, "200"))
+ result = STATE_OK;
+
+ /* client errors result in a warning state */
+ else if (strstr (status_line, "400"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "401"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "402"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "403"))
+ result = STATE_WARNING;
+ else if (strstr (status_line, "404"))
+ result = STATE_WARNING;
+
+ /* server errors result in a critical state */
+ else if (strstr (status_line, "500"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "501"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "502"))
+ result = STATE_CRITICAL;
+ else if (strstr (status_line, "503"))
+ result = STATE_CRITICAL;
+
+ else
+ result = STATE_UNKNOWN;
+ }
+ }
+ }
+
+ /* Return results */
+ if (result == STATE_OK) {
+
+ if (check_critical_time == TRUE
+ && (end_time - start_time) > critical_time) result = STATE_CRITICAL;
+ else if (check_warning_time == TRUE
+ && (end_time - start_time) > warning_time) result =
+ STATE_WARNING;
+
+ /* Put some HTML in here to create a dynamic link */
+ printf (_("REAL %s - %d second response time\n"),
+ state_text (result),
+ (int) (end_time - start_time));
+ }
+ else
+ printf ("%s\n", status_line);
+
+ /* close the connection */
+ close (sd);
+
+ /* reset the alarm */
+ alarm (0);
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"IPaddress", required_argument, 0, 'I'},
+ {"expect", required_argument, 0, 'e'},
+ {"url", required_argument, 0, 'u'},
+ {"port", required_argument, 0, 'p'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'I': /* hostname */
+ case 'H': /* hostname */
+ if (server_address)
+ break;
+ else if (is_host (optarg))
+ server_address = optarg;
+ else
+ usage2 (_("Invalid hostname/address"), optarg);
+ break;
+ case 'e': /* string to expect in response header */
+ server_expect = optarg;
+ break;
+ case 'u': /* server URL */
+ server_url = optarg;
+ break;
+ case 'p': /* port */
+ if (is_intpos (optarg)) {
+ server_port = atoi (optarg);
+ }
+ else {
+ usage4 (_("Port must be a positive integer"));
+ }
+ break;
+ case 'w': /* warning time threshold */
+ if (is_intnonneg (optarg)) {
+ warning_time = atoi (optarg);
+ check_warning_time = TRUE;
+ }
+ else {
+ usage4 (_("Warning time must be a positive integer"));
+ }
+ break;
+ case 'c': /* critical time threshold */
+ if (is_intnonneg (optarg)) {
+ critical_time = atoi (optarg);
+ check_critical_time = TRUE;
+ }
+ else {
+ usage4 (_("Critical time must be a positive integer"));
+ }
+ break;
+ case 'v': /* verbose */
+ verbose = TRUE;
+ break;
+ case 't': /* timeout */
+ if (is_intnonneg (optarg)) {
+ socket_timeout = atoi (optarg);
+ }
+ else {
+ usage4 (_("Timeout interval must be a positive integer"));
+ }
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* usage */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (server_address==NULL && argc>c) {
+ if (is_host (argv[c])) {
+ server_address = argv[c++];
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), argv[c]);
+ }
+ }
+
+ if (server_address==NULL)
+ usage4 (_("You must provide a server to check"));
+
+ if (host_name==NULL)
+ host_name = strdup (server_address);
+
+ if (server_expect == NULL)
+ server_expect = strdup(EXPECT);
+
+ return validate_arguments ();
+}
+
+
+
+int
+validate_arguments (void)
+{
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin tests the REAL service on the specified host."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n", "-u, --url=STRING");
+ printf (" %s\n", _("Connect to this url"));
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (_("String to expect in first line of server response (default: %s)\n"),
+ EXPECT);
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
+ printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
+ printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
+ printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return"));
+ printf ("%s\n", _("values."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n", progname);
+}
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
new file mode 100644
index 0000000..fc0ae2c
--- /dev/null
+++ b/plugins/check_smtp.c
@@ -0,0 +1,929 @@
+/*****************************************************************************
+*
+* Monitoring check_smtp plugin
+*
+* License: GPL
+* Copyright (c) 2000-2023 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_smtp plugin
+*
+* This plugin will attempt to open an SMTP connection with the host.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_smtp";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+#include "base64.h"
+
+#include <ctype.h>
+
+#ifdef HAVE_SSL
+int check_cert = FALSE;
+int days_till_exp_warn, days_till_exp_crit;
+# define my_recv(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
+# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
+#else /* ifndef HAVE_SSL */
+# define my_recv(buf, len) read(sd, buf, len)
+# define my_send(buf, len) send(sd, buf, len, 0)
+#endif
+
+enum {
+ SMTP_PORT = 25,
+ SMTPS_PORT = 465
+};
+#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
+#define SMTP_EXPECT "220"
+#define SMTP_HELO "HELO "
+#define SMTP_EHLO "EHLO "
+#define SMTP_LHLO "LHLO "
+#define SMTP_QUIT "QUIT\r\n"
+#define SMTP_STARTTLS "STARTTLS\r\n"
+#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
+
+#define EHLO_SUPPORTS_STARTTLS 1
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+void smtp_quit(void);
+int recvline(char *, size_t);
+int recvlines(char *, size_t);
+int my_close(void);
+
+#include "regex.h"
+char regex_expect[MAX_INPUT_BUFFER] = "";
+regex_t preg;
+regmatch_t pmatch[10];
+char timestamp[20] = "";
+char errbuf[MAX_INPUT_BUFFER];
+int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+int eflags = 0;
+int errcode, excode;
+
+int server_port = SMTP_PORT;
+int server_port_option = 0;
+char *server_address = NULL;
+char *server_expect = NULL;
+char *mail_command = NULL;
+char *from_arg = NULL;
+int send_mail_from=0;
+int ncommands=0;
+int command_size=0;
+int nresponses=0;
+int response_size=0;
+char **commands = NULL;
+char **responses = NULL;
+char *authtype = NULL;
+char *authuser = NULL;
+char *authpass = NULL;
+double warning_time = 0;
+int check_warning_time = FALSE;
+double critical_time = 0;
+int check_critical_time = FALSE;
+int verbose = 0;
+int use_ssl = FALSE;
+int use_starttls = FALSE;
+int use_sni = FALSE;
+short use_proxy_prefix = FALSE;
+short use_ehlo = FALSE;
+short use_lhlo = FALSE;
+short ssl_established = 0;
+char *localhostname = NULL;
+int sd;
+char buffer[MAX_INPUT_BUFFER];
+enum {
+ TCP_PROTOCOL = 1,
+ UDP_PROTOCOL = 2,
+};
+int ignore_send_quit_failure = FALSE;
+
+
+int
+main (int argc, char **argv)
+{
+ short supports_tls=FALSE;
+ int n = 0;
+ double elapsed_time;
+ long microsec;
+ int result = STATE_UNKNOWN;
+ char *cmd_str = NULL;
+ char *helocmd = NULL;
+ char *error_msg = "";
+ char *server_response = NULL;
+ struct timeval tv;
+
+ /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
+ (void) signal (SIGPIPE, SIG_IGN);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* If localhostname not set on command line, use gethostname to set */
+ if(! localhostname){
+ localhostname = malloc (HOST_MAX_BYTES);
+ if(!localhostname){
+ printf(_("malloc() failed!\n"));
+ return STATE_CRITICAL;
+ }
+ if(gethostname(localhostname, HOST_MAX_BYTES)){
+ printf(_("gethostname() failed!\n"));
+ return STATE_CRITICAL;
+ }
+ }
+ if(use_lhlo)
+ xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
+ else if(use_ehlo)
+ xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
+ else
+ xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
+
+ if (verbose)
+ printf("HELOCMD: %s", helocmd);
+
+ /* initialize the MAIL command with optional FROM command */
+ xasprintf (&cmd_str, "%sFROM:<%s>%s", mail_command, from_arg, "\r\n");
+
+ if (verbose && send_mail_from)
+ printf ("FROM CMD: %s", cmd_str);
+
+ /* initialize alarm signal handling */
+ (void) signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ (void) alarm (socket_timeout);
+
+ /* start timer */
+ gettimeofday (&tv, NULL);
+
+ /* try to connect to the host at the given port number */
+ result = my_tcp_connect (server_address, server_port, &sd);
+
+ if (result == STATE_OK) { /* we connected */
+ /* If requested, send PROXY header */
+ if (use_proxy_prefix) {
+ if (verbose)
+ printf ("Sending header %s\n", PROXY_PREFIX);
+ my_send(PROXY_PREFIX, strlen(PROXY_PREFIX));
+ }
+
+#ifdef HAVE_SSL
+ if (use_ssl) {
+ result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
+ if (result != STATE_OK) {
+ printf (_("CRITICAL - Cannot create SSL context.\n"));
+ close(sd);
+ np_net_ssl_cleanup();
+ return STATE_CRITICAL;
+ } else {
+ ssl_established = 1;
+ }
+ }
+#endif
+
+ /* watch for the SMTP connection string and */
+ /* return a WARNING status if we couldn't read any data */
+ if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
+ printf (_("recv() failed\n"));
+ return STATE_WARNING;
+ }
+
+ /* save connect return (220 hostname ..) for later use */
+ xasprintf(&server_response, "%s", buffer);
+
+ /* send the HELO/EHLO command */
+ my_send(helocmd, strlen(helocmd));
+
+ /* allow for response to helo command to reach us */
+ if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
+ printf (_("recv() failed\n"));
+ return STATE_WARNING;
+ } else if(use_ehlo || use_lhlo){
+ if(strstr(buffer, "250 STARTTLS") != NULL ||
+ strstr(buffer, "250-STARTTLS") != NULL){
+ supports_tls=TRUE;
+ }
+ }
+
+ if(use_starttls && ! supports_tls){
+ printf(_("WARNING - TLS not supported by server\n"));
+ smtp_quit();
+ return STATE_WARNING;
+ }
+
+#ifdef HAVE_SSL
+ if(use_starttls) {
+ /* send the STARTTLS command */
+ send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
+
+ recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */
+ if (!strstr (buffer, SMTP_EXPECT)) {
+ printf (_("Server does not support STARTTLS\n"));
+ smtp_quit();
+ return STATE_UNKNOWN;
+ }
+ result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
+ if(result != STATE_OK) {
+ printf (_("CRITICAL - Cannot create SSL context.\n"));
+ close(sd);
+ np_net_ssl_cleanup();
+ return STATE_CRITICAL;
+ } else {
+ ssl_established = 1;
+ }
+
+ /*
+ * Resend the EHLO command.
+ *
+ * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
+ * obtained from the server, such as the list of SMTP service
+ * extensions, which was not obtained from the TLS negotiation
+ * itself. The client SHOULD send an EHLO command as the first
+ * command after a successful TLS negotiation.'' For this
+ * reason, some MTAs will not allow an AUTH LOGIN command before
+ * we resent EHLO via TLS.
+ */
+ if (my_send(helocmd, strlen(helocmd)) <= 0) {
+ printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
+ my_close();
+ return STATE_UNKNOWN;
+ }
+ if (verbose)
+ printf(_("sent %s"), helocmd);
+ if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
+ printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
+ my_close();
+ return STATE_UNKNOWN;
+ }
+ if (verbose) {
+ printf("%s", buffer);
+ }
+
+# ifdef USE_OPENSSL
+ if ( check_cert ) {
+ result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
+ smtp_quit();
+ my_close();
+ return result;
+ }
+# endif /* USE_OPENSSL */
+ }
+#endif
+
+ if (verbose)
+ printf ("%s", buffer);
+
+ /* save buffer for later use */
+ xasprintf(&server_response, "%s%s", server_response, buffer);
+ /* strip the buffer of carriage returns */
+ strip (server_response);
+
+ /* make sure we find the droids we are looking for */
+ if (!strstr (server_response, server_expect)) {
+ if (server_port == SMTP_PORT)
+ printf (_("Invalid SMTP response received from host: %s\n"), server_response);
+ else
+ printf (_("Invalid SMTP response received from host on port %d: %s\n"),
+ server_port, server_response);
+ return STATE_WARNING;
+ }
+
+ if (send_mail_from) {
+ my_send(cmd_str, strlen(cmd_str));
+ if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
+ printf("%s", buffer);
+ }
+
+ n = 0;
+ while (n < ncommands) {
+ xasprintf (&cmd_str, "%s%s", commands[n], "\r\n");
+ my_send(cmd_str, strlen(cmd_str));
+ if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
+ printf("%s", buffer);
+ strip (buffer);
+ if (n < nresponses) {
+ cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+ errcode = regcomp (&preg, responses[n], cflags);
+ if (errcode != 0) {
+ regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Could Not Compile Regular Expression"));
+ return ERROR;
+ }
+ excode = regexec (&preg, buffer, 10, pmatch, eflags);
+ if (excode == 0) {
+ result = STATE_OK;
+ }
+ else if (excode == REG_NOMATCH) {
+ result = STATE_WARNING;
+ printf (_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text (result), buffer, commands[n]);
+ }
+ else {
+ regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Execute Error: %s\n"), errbuf);
+ result = STATE_UNKNOWN;
+ }
+ }
+ n++;
+ }
+
+ if (authtype != NULL) {
+ if (strcmp (authtype, "LOGIN") == 0) {
+ char *abuf;
+ int ret;
+ do {
+ if (authuser == NULL) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("no authuser specified, "));
+ break;
+ }
+ if (authpass == NULL) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("no authpass specified, "));
+ break;
+ }
+
+ /* send AUTH LOGIN */
+ my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN));
+ if (verbose)
+ printf (_("sent %s\n"), "AUTH LOGIN");
+
+ if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
+ xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
+ result = STATE_WARNING;
+ break;
+ }
+ if (verbose)
+ printf (_("received %s\n"), buffer);
+
+ if (strncmp (buffer, "334", 3) != 0) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
+ break;
+ }
+
+ /* encode authuser with base64 */
+ base64_encode_alloc (authuser, strlen(authuser), &abuf);
+ xasprintf(&abuf, "%s\r\n", abuf);
+ my_send(abuf, strlen(abuf));
+ if (verbose)
+ printf (_("sent %s\n"), abuf);
+
+ if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("recv() failed after sending authuser, "));
+ break;
+ }
+ if (verbose) {
+ printf (_("received %s\n"), buffer);
+ }
+ if (strncmp (buffer, "334", 3) != 0) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("invalid response received after authuser, "));
+ break;
+ }
+ /* encode authpass with base64 */
+ base64_encode_alloc (authpass, strlen(authpass), &abuf);
+ xasprintf(&abuf, "%s\r\n", abuf);
+ my_send(abuf, strlen(abuf));
+ if (verbose) {
+ printf (_("sent %s\n"), abuf);
+ }
+ if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("recv() failed after sending authpass, "));
+ break;
+ }
+ if (verbose) {
+ printf (_("received %s\n"), buffer);
+ }
+ if (strncmp (buffer, "235", 3) != 0) {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("invalid response received after authpass, "));
+ break;
+ }
+ break;
+ } while (0);
+ } else {
+ result = STATE_CRITICAL;
+ xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
+ }
+ }
+
+ /* tell the server we're done */
+ smtp_quit();
+
+ /* finally close the connection */
+ close (sd);
+ }
+
+ /* reset the alarm */
+ alarm (0);
+
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ if (result == STATE_OK) {
+ if (check_critical_time && elapsed_time > critical_time)
+ result = STATE_CRITICAL;
+ else if (check_warning_time && elapsed_time > warning_time)
+ result = STATE_WARNING;
+ }
+
+ printf (_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"),
+ state_text (result),
+ error_msg,
+ elapsed_time,
+ verbose?", ":"", verbose?buffer:"",
+ fperfdata ("time", elapsed_time, "s",
+ (int)check_warning_time, warning_time,
+ (int)check_critical_time, critical_time,
+ TRUE, 0, FALSE, 0));
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ char* temp;
+
+ enum {
+ SNI_OPTION
+ };
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"expect", required_argument, 0, 'e'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"timeout", required_argument, 0, 't'},
+ {"port", required_argument, 0, 'p'},
+ {"from", required_argument, 0, 'f'},
+ {"fqdn", required_argument, 0, 'F'},
+ {"authtype", required_argument, 0, 'A'},
+ {"authuser", required_argument, 0, 'U'},
+ {"authpass", required_argument, 0, 'P'},
+ {"command", required_argument, 0, 'C'},
+ {"response", required_argument, 0, 'R'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"help", no_argument, 0, 'h'},
+ {"lmtp", no_argument, 0, 'L'},
+ {"ssl", no_argument, 0, 's'},
+ {"tls", no_argument, 0, 's'},
+ {"starttls",no_argument,0,'S'},
+ {"sni", no_argument, 0, SNI_OPTION},
+ {"certificate",required_argument,0,'D'},
+ {"ignore-quit-failure",no_argument,0,'q'},
+ {"proxy",no_argument,0,'r'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q",
+ longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'H': /* hostname */
+ if (is_host (optarg)) {
+ server_address = optarg;
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ break;
+ case 'p': /* port */
+ if (is_intpos (optarg))
+ server_port_option = atoi (optarg);
+ else
+ usage4 (_("Port must be a positive integer"));
+ break;
+ case 'F':
+ /* localhostname */
+ localhostname = strdup(optarg);
+ break;
+ case 'f': /* from argument */
+ from_arg = optarg + strspn(optarg, "<");
+ from_arg = strndup(from_arg, strcspn(from_arg, ">"));
+ send_mail_from = 1;
+ break;
+ case 'A':
+ authtype = optarg;
+ use_ehlo = TRUE;
+ break;
+ case 'U':
+ authuser = optarg;
+ break;
+ case 'P':
+ authpass = optarg;
+ break;
+ case 'e': /* server expect string on 220 */
+ server_expect = optarg;
+ break;
+ case 'C': /* commands */
+ if (ncommands >= command_size) {
+ command_size+=8;
+ commands = realloc (commands, sizeof(char *) * command_size);
+ if (commands == NULL)
+ die (STATE_UNKNOWN,
+ _("Could not realloc() units [%d]\n"), ncommands);
+ }
+ commands[ncommands] = (char *) malloc (sizeof(char) * 255);
+ strncpy (commands[ncommands], optarg, 255);
+ ncommands++;
+ break;
+ case 'R': /* server responses */
+ if (nresponses >= response_size) {
+ response_size += 8;
+ responses = realloc (responses, sizeof(char *) * response_size);
+ if (responses == NULL)
+ die (STATE_UNKNOWN,
+ _("Could not realloc() units [%d]\n"), nresponses);
+ }
+ responses[nresponses] = (char *) malloc (sizeof(char) * 255);
+ strncpy (responses[nresponses], optarg, 255);
+ nresponses++;
+ break;
+ case 'c': /* critical time threshold */
+ if (!is_nonnegative (optarg))
+ usage4 (_("Critical time must be a positive"));
+ else {
+ critical_time = strtod (optarg, NULL);
+ check_critical_time = TRUE;
+ }
+ break;
+ case 'w': /* warning time threshold */
+ if (!is_nonnegative (optarg))
+ usage4 (_("Warning time must be a positive"));
+ else {
+ warning_time = strtod (optarg, NULL);
+ check_warning_time = TRUE;
+ }
+ break;
+ case 'v': /* verbose */
+ verbose++;
+ break;
+ case 'q':
+ ignore_send_quit_failure++; /* ignore problem sending QUIT */
+ break;
+ case 't': /* timeout */
+ if (is_intnonneg (optarg)) {
+ socket_timeout = atoi (optarg);
+ }
+ else {
+ usage4 (_("Timeout interval must be a positive integer"));
+ }
+ break;
+ case 'D':
+ /* Check SSL cert validity */
+#ifdef USE_OPENSSL
+ if ((temp=strchr(optarg,','))!=NULL) {
+ *temp='\0';
+ if (!is_intnonneg (optarg))
+ usage2 ("Invalid certificate expiration period", optarg);
+ days_till_exp_warn = atoi(optarg);
+ *temp=',';
+ temp++;
+ if (!is_intnonneg (temp))
+ usage2 (_("Invalid certificate expiration period"), temp);
+ days_till_exp_crit = atoi (temp);
+ }
+ else {
+ days_till_exp_crit=0;
+ if (!is_intnonneg (optarg))
+ usage2 ("Invalid certificate expiration period", optarg);
+ days_till_exp_warn = atoi (optarg);
+ }
+ check_cert = TRUE;
+ ignore_send_quit_failure = TRUE;
+#else
+ usage (_("SSL support not available - install OpenSSL and recompile"));
+#endif
+ case 's':
+ /* ssl */
+ use_ssl = TRUE;
+ server_port = SMTPS_PORT;
+ break;
+ case 'S':
+ /* starttls */
+ use_starttls = TRUE;
+ use_ehlo = TRUE;
+ break;
+ case SNI_OPTION:
+#ifdef HAVE_SSL
+ use_sni = TRUE;
+#else
+ usage (_("SSL support not available - install OpenSSL and recompile"));
+#endif
+ break;
+ case 'r':
+ use_proxy_prefix = TRUE;
+ break;
+ case 'L':
+ use_lhlo = TRUE;
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* help */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (server_address == NULL) {
+ if (argv[c]) {
+ if (is_host (argv[c]))
+ server_address = argv[c];
+ else
+ usage2 (_("Invalid hostname/address"), argv[c]);
+ }
+ else {
+ xasprintf (&server_address, "127.0.0.1");
+ }
+ }
+
+ if (server_expect == NULL)
+ server_expect = strdup (SMTP_EXPECT);
+
+ if (mail_command == NULL)
+ mail_command = strdup("MAIL ");
+
+ if (from_arg==NULL)
+ from_arg = strdup(" ");
+
+ if (use_starttls && use_ssl) {
+ usage4 (_("Set either -s/--ssl/--tls or -S/--starttls"));
+ }
+
+ if (server_port_option != 0) {
+ server_port = server_port_option;
+ }
+
+ return validate_arguments ();
+}
+
+
+
+int
+validate_arguments (void)
+{
+ return OK;
+}
+
+
+void
+smtp_quit(void)
+{
+ int bytes;
+ int n;
+
+ n = my_send(SMTP_QUIT, strlen(SMTP_QUIT));
+ if(n < 0) {
+ if(ignore_send_quit_failure) {
+ if(verbose) {
+ printf(_("Connection closed by server before sending QUIT command\n"));
+ }
+ return;
+ }
+ die (STATE_UNKNOWN,
+ _("Connection closed by server before sending QUIT command\n"));
+ }
+
+ if (verbose)
+ printf(_("sent %s\n"), "QUIT");
+
+ /* read the response but don't care about problems */
+ bytes = recvlines(buffer, MAX_INPUT_BUFFER);
+ if (verbose) {
+ if (bytes < 0)
+ printf(_("recv() failed after QUIT."));
+ else if (bytes == 0)
+ printf(_("Connection reset by peer."));
+ else {
+ buffer[bytes] = '\0';
+ printf(_("received %s\n"), buffer);
+ }
+ }
+}
+
+
+/*
+ * Receive one line, copy it into buf and nul-terminate it. Returns the
+ * number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
+ * error.
+ *
+ * TODO: Reading one byte at a time is very inefficient. Replace this by a
+ * function which buffers the data, move that to netutils.c and change
+ * check_smtp and other plugins to use that. Also, remove (\r)\n.
+ */
+int
+recvline(char *buf, size_t bufsize)
+{
+ int result;
+ unsigned i;
+
+ for (i = result = 0; i < bufsize - 1; i++) {
+ if ((result = my_recv(&buf[i], 1)) != 1)
+ break;
+ if (buf[i] == '\n') {
+ buf[++i] = '\0';
+ return i;
+ }
+ }
+ return (result == 1 || i == 0) ? -2 : result; /* -2 if out of space */
+}
+
+
+/*
+ * Receive one or more lines, copy them into buf and nul-terminate it. Returns
+ * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
+ * error. Works for all protocols which format multiline replies as follows:
+ *
+ * ``The format for multiline replies requires that every line, except the last,
+ * begin with the reply code, followed immediately by a hyphen, `-' (also known
+ * as minus), followed by text. The last line will begin with the reply code,
+ * followed immediately by <SP>, optionally some text, and <CRLF>. As noted
+ * above, servers SHOULD send the <SP> if subsequent text is not sent, but
+ * clients MUST be prepared for it to be omitted.'' (RFC 2821, 4.2.1)
+ *
+ * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
+ */
+int
+recvlines(char *buf, size_t bufsize)
+{
+ int result, i;
+
+ for (i = 0; /* forever */; i += result)
+ if (!((result = recvline(buf + i, bufsize - i)) > 3 &&
+ isdigit((int)buf[i]) &&
+ isdigit((int)buf[i + 1]) &&
+ isdigit((int)buf[i + 2]) &&
+ buf[i + 3] == '-'))
+ break;
+
+ return (result <= 0) ? result : result + i;
+}
+
+
+int
+my_close (void)
+{
+ int result;
+ result = close(sd);
+#ifdef HAVE_SSL
+ np_net_ssl_cleanup();
+#endif
+ return result;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", SMTP_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT);
+ printf (" %s\n", "-C, --command=STRING");
+ printf (" %s\n", _("SMTP command (may be used repeatedly)"));
+ printf (" %s\n", "-R, --response=STRING");
+ printf (" %s\n", _("Expected response to command (may be used repeatedly)"));
+ printf (" %s\n", "-f, --from=STRING");
+ printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
+ printf (" %s\n", "-F, --fqdn=STRING");
+ printf (" %s\n", _("FQDN used for HELO"));
+ printf (" %s\n", "-r, --proxy");
+ printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
+#ifdef HAVE_SSL
+ printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
+ printf (" %s\n", _("Minimum number of days a certificate has to be valid."));
+ printf (" %s\n", "-s, --ssl, --tls");
+ printf (" %s\n", _("Use SSL/TLS for the connection."));
+ printf (_(" Sets default port to %d.\n"), SMTPS_PORT);
+ printf (" %s\n", "-S, --starttls");
+ printf (" %s\n", _("Use STARTTLS for the connection."));
+ printf (" %s\n", "--sni");
+ printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
+#endif
+
+ printf (" %s\n", "-A, --authtype=STRING");
+ printf (" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)"));
+ printf (" %s\n", "-U, --authuser=STRING");
+ printf (" %s\n", _("SMTP AUTH username"));
+ printf (" %s\n", "-P, --authpass=STRING");
+ printf (" %s\n", _("SMTP AUTH password"));
+ printf (" %s\n", "-L, --lmtp");
+ printf (" %s\n", _("Send LHLO instead of HELO/EHLO"));
+ printf (" %s\n", "-q, --ignore-quit-failure");
+ printf (" %s\n", _("Ignore failure when sending QUIT command to server"));
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf("\n");
+ printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
+ printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
+ printf ("%s\n", _("connects, but incorrect response messages from the host result in"));
+ printf ("%s\n", _("STATE_WARNING return values."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
+ printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
+ printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
+}
+
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
new file mode 100644
index 0000000..56a586a
--- /dev/null
+++ b/plugins/check_snmp.c
@@ -0,0 +1,1379 @@
+/*****************************************************************************
+*
+* Monitoring check_snmp plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_snmp plugin
+*
+* Check status of remote machines and obtain system information via SNMP
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_snmp";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "runcmd.h"
+#include "utils.h"
+#include "utils_cmd.h"
+
+#define DEFAULT_COMMUNITY "public"
+#define DEFAULT_PORT "161"
+#define DEFAULT_MIBLIST "ALL"
+#define DEFAULT_PROTOCOL "1"
+#define DEFAULT_RETRIES 5
+#define DEFAULT_AUTH_PROTOCOL "MD5"
+#define DEFAULT_PRIV_PROTOCOL "DES"
+#define DEFAULT_DELIMITER "="
+#define DEFAULT_OUTPUT_DELIMITER " "
+#define DEFAULT_BUFFER_SIZE 100
+
+#define mark(a) ((a)!=0?"*":"")
+
+#define CHECK_UNDEF 0
+#define CRIT_PRESENT 1
+#define CRIT_STRING 2
+#define CRIT_REGEX 4
+#define WARN_PRESENT 8
+#define WARN_STRING 16
+#define WARN_REGEX 32
+
+#define OID_COUNT_STEP 8
+
+/* Longopts only arguments */
+#define L_CALCULATE_RATE CHAR_MAX+1
+#define L_RATE_MULTIPLIER CHAR_MAX+2
+#define L_INVERT_SEARCH CHAR_MAX+3
+#define L_OFFSET CHAR_MAX+4
+#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5
+
+/* Gobble to string - stop incrementing c when c[0] match one of the
+ * characters in s */
+#define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
+/* Given c, keep track of backslashes (bk) and double-quotes (dq)
+ * from c[0] */
+#define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
+ case '\\': \
+ if (bk) bk--; \
+ else bk++; \
+ break; \
+ case '"': \
+ if (!dq) { dq++; } \
+ else if(!bk) { dq--; } \
+ else { bk--; } \
+ break; \
+ }
+
+
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+char *thisarg (char *str);
+char *nextarg (char *str);
+void print_usage (void);
+void print_help (void);
+char *multiply (char *str);
+
+#include "regex.h"
+char regex_expect[MAX_INPUT_BUFFER] = "";
+regex_t preg;
+regmatch_t pmatch[10];
+char errbuf[MAX_INPUT_BUFFER] = "";
+char perfstr[MAX_INPUT_BUFFER] = "| ";
+int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+int eflags = 0;
+int errcode, excode;
+
+char *server_address = NULL;
+char *community = NULL;
+char **contextargs = NULL;
+char *context = NULL;
+char **authpriv = NULL;
+char *proto = NULL;
+char *seclevel = NULL;
+char *secname = NULL;
+char *authproto = NULL;
+char *privproto = NULL;
+char *authpasswd = NULL;
+char *privpasswd = NULL;
+int nulloid = STATE_UNKNOWN;
+char **oids = NULL;
+size_t oids_size = 0;
+char *label;
+char *units;
+char *port;
+char *snmpcmd;
+char string_value[MAX_INPUT_BUFFER] = "";
+int invert_search=0;
+char **labels = NULL;
+char **unitv = NULL;
+size_t nlabels = 0;
+size_t labels_size = OID_COUNT_STEP;
+size_t nunits = 0;
+size_t unitv_size = OID_COUNT_STEP;
+int numoids = 0;
+int numauthpriv = 0;
+int numcontext = 0;
+int verbose = 0;
+int usesnmpgetnext = FALSE;
+char *warning_thresholds = NULL;
+char *critical_thresholds = NULL;
+thresholds **thlds;
+size_t thlds_size = OID_COUNT_STEP;
+double *response_value;
+size_t response_size = OID_COUNT_STEP;
+int retries = 0;
+int *eval_method;
+size_t eval_size = OID_COUNT_STEP;
+char *delimiter;
+char *output_delim;
+char *miblist = NULL;
+int needmibs = FALSE;
+int calculate_rate = 0;
+double offset = 0.0;
+int rate_multiplier = 1;
+state_data *previous_state;
+double *previous_value;
+size_t previous_size = OID_COUNT_STEP;
+int perf_labels = 1;
+char* ip_version = "";
+double multiplier = 1.0;
+char *fmtstr = "";
+bool fmtstr_set = false;
+char buffer[DEFAULT_BUFFER_SIZE];
+bool ignore_mib_parsing_errors = false;
+
+static char *fix_snmp_range(char *th)
+{
+ double left, right;
+ char *colon, *ret;
+
+ if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
+ return th;
+
+ left = strtod(th, NULL);
+ right = strtod(colon + 1, NULL);
+ if (right >= left)
+ return th;
+
+ if ((ret = malloc(strlen(th) + 2)) == NULL)
+ die(STATE_UNKNOWN, _("Cannot malloc"));
+ *colon = '\0';
+ sprintf(ret, "@%s:%s", colon + 1, th);
+ free(th);
+ return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ int i, len, line, total_oids;
+ unsigned int bk_count = 0, dq_count = 0;
+ int iresult = STATE_UNKNOWN;
+ int result = STATE_UNKNOWN;
+ int return_code = 0;
+ int external_error = 0;
+ char **command_line = NULL;
+ char *cl_hidden_auth = NULL;
+ char *oidname = NULL;
+ char *response = NULL;
+ char *mult_resp = NULL;
+ char *outbuff;
+ char *ptr = NULL;
+ char *show = NULL;
+ char *th_warn=NULL;
+ char *th_crit=NULL;
+ char type[8] = "";
+ output chld_out, chld_err;
+ char *previous_string=NULL;
+ char *ap=NULL;
+ char *state_string=NULL;
+ size_t response_length, current_length, string_length;
+ char *temp_string=NULL;
+ char *quote_string=NULL;
+ time_t current_time;
+ double temp_double;
+ time_t duration;
+ char *conv = "12345678";
+ int is_counter=0;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ labels = malloc (labels_size * sizeof(*labels));
+ unitv = malloc (unitv_size * sizeof(*unitv));
+ thlds = malloc (thlds_size * sizeof(*thlds));
+ response_value = malloc (response_size * sizeof(*response_value));
+ previous_value = malloc (previous_size * sizeof(*previous_value));
+ eval_method = calloc (eval_size, sizeof(*eval_method));
+ oids = calloc(oids_size, sizeof (char *));
+
+ label = strdup ("SNMP");
+ units = strdup ("");
+ port = strdup (DEFAULT_PORT);
+ outbuff = strdup ("");
+ delimiter = strdup (" = ");
+ output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
+ timeout_interval = DEFAULT_SOCKET_TIMEOUT;
+ retries = DEFAULT_RETRIES;
+
+ np_init( (char *) progname, argc, argv );
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ np_set_args(argc, argv);
+
+ time(&current_time);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ if(calculate_rate) {
+ if (!strcmp(label, "SNMP"))
+ label = strdup("SNMP RATE");
+ i=0;
+ previous_state = np_state_read();
+ if(previous_state!=NULL) {
+ /* Split colon separated values */
+ previous_string = strdup((char *) previous_state->data);
+ while((ap = strsep(&previous_string, ":")) != NULL) {
+ if(verbose>2)
+ printf("State for %d=%s\n", i, ap);
+ while (i >= previous_size) {
+ previous_size += OID_COUNT_STEP;
+ previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
+ }
+ previous_value[i++]=strtod(ap,NULL);
+ }
+ }
+ }
+
+ /* Populate the thresholds */
+ th_warn=warning_thresholds;
+ th_crit=critical_thresholds;
+ for (i=0; i<numoids; i++) {
+ char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
+ char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
+ /* translate "2:1" to "@1:2" for backwards compatibility */
+ w = w ? fix_snmp_range(w) : NULL;
+ c = c ? fix_snmp_range(c) : NULL;
+
+ while (i >= thlds_size) {
+ thlds_size += OID_COUNT_STEP;
+ thlds = realloc(thlds, thlds_size * sizeof(*thlds));
+ }
+
+ /* Skip empty thresholds, while avoiding segfault */
+ set_thresholds(&thlds[i],
+ w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
+ c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
+ if (w) {
+ th_warn=strchr(th_warn, ',');
+ if (th_warn) th_warn++;
+ free(w);
+ }
+ if (c) {
+ th_crit=strchr(th_crit, ',');
+ if (th_crit) th_crit++;
+ free(c);
+ }
+ }
+
+ /* Create the command array to execute */
+ if(usesnmpgetnext == TRUE) {
+ snmpcmd = strdup (PATH_TO_SNMPGETNEXT);
+ }else{
+ snmpcmd = strdup (PATH_TO_SNMPGET);
+ }
+
+ /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
+
+ unsigned index = 0;
+ command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *));
+
+ command_line[index++] = snmpcmd;
+ command_line[index++] = strdup ("-Le");
+ command_line[index++] = strdup ("-t");
+ xasprintf (&command_line[index++], "%d", timeout_interval);
+ command_line[index++] = strdup ("-r");
+ xasprintf (&command_line[index++], "%d", retries);
+ command_line[index++] = strdup ("-m");
+ command_line[index++] = strdup (miblist);
+ command_line[index++] = "-v";
+ command_line[index++] = strdup (proto);
+
+ xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s",
+ snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto);
+
+ if (ignore_mib_parsing_errors) {
+ command_line[index++] = "-Pe";
+ xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
+ }
+
+
+ for (i = 0; i < numcontext; i++) {
+ command_line[index++] = contextargs[i];
+ }
+
+ for (i = 0; i < numauthpriv; i++) {
+ command_line[index++] = authpriv[i];
+ }
+
+ xasprintf (&command_line[index++], "%s:%s", server_address, port);
+
+ xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s",
+ cl_hidden_auth,
+ server_address,
+ port);
+
+ for (i = 0; i < numoids; i++) {
+ command_line[index++] = oids[i];
+ xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
+ }
+
+ command_line[index++] = NULL;
+
+ if (verbose) {
+ printf ("%s\n", cl_hidden_auth);
+ }
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
+ usage4 (_("Cannot catch SIGALRM"));
+ }
+ alarm(timeout_interval * retries + 5);
+
+ /* Run the command */
+ return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
+
+ /* disable alarm again */
+ alarm(0);
+
+ /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
+ only return state unknown if return code is non zero or there is no stdout.
+ Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
+ */
+ if (return_code != 0)
+ external_error=1;
+ if (chld_out.lines == 0)
+ external_error=1;
+ if (external_error) {
+ if (chld_err.lines > 0) {
+ printf (_("External command error: %s\n"), chld_err.line[0]);
+ for (i = 1; i < chld_err.lines; i++) {
+ printf ("%s\n", chld_err.line[i]);
+ }
+ } else {
+ printf(_("External command error with no output (return code: %d)\n"), return_code);
+ }
+ exit (STATE_UNKNOWN);
+ }
+
+ if (verbose) {
+ for (i = 0; i < chld_out.lines; i++) {
+ printf ("%s\n", chld_out.line[i]);
+ }
+ }
+
+ for (line=0, i=0; line < chld_out.lines && i < numoids ; line++, i++) {
+ if(calculate_rate)
+ conv = "%.10g";
+ else
+ conv = "%.0f";
+
+ ptr = chld_out.line[line];
+ oidname = strpcpy (oidname, ptr, delimiter);
+ response = strstr (ptr, delimiter);
+ if (response == NULL)
+ break;
+
+ if (verbose > 2) {
+ printf("Processing oid %i (line %i)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response);
+ }
+
+ /* Clean up type array - Sol10 does not necessarily zero it out */
+ bzero(type, sizeof(type));
+
+ is_counter=0;
+ /* We strip out the datatype indicator for PHBs */
+ if (strstr (response, "Gauge: ")) {
+ show = multiply (strstr (response, "Gauge: ") + 7);
+ }
+ else if (strstr (response, "Gauge32: ")) {
+ show = multiply (strstr (response, "Gauge32: ") + 9);
+ }
+ else if (strstr (response, "Counter32: ")) {
+ show = strstr (response, "Counter32: ") + 11;
+ is_counter=1;
+ if(!calculate_rate)
+ strcpy(type, "c");
+ }
+ else if (strstr (response, "Counter64: ")) {
+ show = strstr (response, "Counter64: ") + 11;
+ is_counter=1;
+ if(!calculate_rate)
+ strcpy(type, "c");
+ }
+ else if (strstr (response, "INTEGER: ")) {
+ show = multiply (strstr (response, "INTEGER: ") + 9);
+
+ if (fmtstr_set) {
+ conv = fmtstr;
+ }
+ }
+ else if (strstr (response, "OID: ")) {
+ show = strstr (response, "OID: ") + 5;
+ }
+ else if (strstr (response, "STRING: ")) {
+ show = strstr (response, "STRING: ") + 8;
+ conv = "%.10g";
+
+ /* Get the rest of the string on multi-line strings */
+ ptr = show;
+ COUNT_SEQ(ptr, bk_count, dq_count)
+ while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
+ ptr++;
+ GOBBLE_TOS(ptr, "\n\"\\")
+ COUNT_SEQ(ptr, bk_count, dq_count)
+ }
+
+ if (dq_count) { /* unfinished line */
+ /* copy show verbatim first */
+ if (!mult_resp) mult_resp = strdup("");
+ xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
+ /* then strip out unmatched double-quote from single-line output */
+ if (show[0] == '"') show++;
+
+ /* Keep reading until we match end of double-quoted string */
+ for (line++; line < chld_out.lines; line++) {
+ ptr = chld_out.line[line];
+ xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr);
+
+ COUNT_SEQ(ptr, bk_count, dq_count)
+ while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
+ ptr++;
+ GOBBLE_TOS(ptr, "\n\"\\")
+ COUNT_SEQ(ptr, bk_count, dq_count)
+ }
+ /* Break for loop before next line increment when done */
+ if (!dq_count) break;
+ }
+ }
+
+ }
+ else if (strstr (response, "Timeticks: ")) {
+ show = strstr (response, "Timeticks: ");
+ }
+ else
+ show = response + 3;
+
+ iresult = STATE_DEPENDENT;
+
+ /* Process this block for numeric comparisons */
+ /* Make some special values,like Timeticks numeric only if a threshold is defined */
+ if (thlds[i]->warning || thlds[i]->critical || calculate_rate) {
+ if (verbose > 2) {
+ print_thresholds(" thresholds", thlds[i]);
+ }
+ ptr = strpbrk (show, "-0123456789");
+ if (ptr == NULL){
+ if (nulloid == 3)
+ die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show);
+ else if (nulloid == 0)
+ die (STATE_OK,_("No valid data returned (%s)\n"), show);
+ else if (nulloid == 1)
+ die (STATE_WARNING,_("No valid data returned (%s)\n"), show);
+ else if (nulloid == 2)
+ die (STATE_CRITICAL,_("No valid data returned (%s)\n"), show);
+ }
+ while (i >= response_size) {
+ response_size += OID_COUNT_STEP;
+ response_value = realloc(response_value, response_size * sizeof(*response_value));
+ }
+ response_value[i] = strtod (ptr, NULL) + offset;
+
+ if(calculate_rate) {
+ if (previous_state!=NULL) {
+ duration = current_time-previous_state->time;
+ if(duration<=0)
+ die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
+ temp_double = response_value[i]-previous_value[i];
+ /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
+ if(is_counter) {
+ if(temp_double<(double)0.0)
+ temp_double+=(double)4294967296.0; /* 2^32 */
+ if(temp_double<(double)0.0)
+ temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
+ }
+ /* Convert to per second, then use multiplier */
+ temp_double = temp_double/duration*rate_multiplier;
+ iresult = get_status(temp_double, thlds[i]);
+ xasprintf (&show, conv, temp_double);
+ }
+ } else {
+ iresult = get_status(response_value[i], thlds[i]);
+ xasprintf (&show, conv, response_value[i]);
+ }
+ }
+
+ /* Process this block for string matching */
+ else if (eval_size > i && eval_method[i] & CRIT_STRING) {
+ if (strcmp (show, string_value))
+ iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
+ else
+ iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
+ }
+
+ /* Process this block for regex matching */
+ else if (eval_size > i && eval_method[i] & CRIT_REGEX) {
+ excode = regexec (&preg, response, 10, pmatch, eflags);
+ if (excode == 0) {
+ iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
+ }
+ else if (excode != REG_NOMATCH) {
+ regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Execute Error: %s\n"), errbuf);
+ exit (STATE_CRITICAL);
+ }
+ else {
+ iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
+ }
+ }
+
+ /* Process this block for existence-nonexistence checks */
+ /* TV: Should this be outside of this else block? */
+ else {
+ if (eval_size > i && eval_method[i] & CRIT_PRESENT)
+ iresult = STATE_CRITICAL;
+ else if (eval_size > i && eval_method[i] & WARN_PRESENT)
+ iresult = STATE_WARNING;
+ else if (response && iresult == STATE_DEPENDENT)
+ iresult = STATE_OK;
+ }
+
+ /* Result is the worst outcome of all the OIDs tested */
+ result = max_state (result, iresult);
+
+ /* Prepend a label for this OID if there is one */
+ if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
+ xasprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
+ (i == 0) ? " " : output_delim,
+ labels[i], mark (iresult), show, mark (iresult));
+ else
+ xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
+ mark (iresult), show, mark (iresult));
+
+ /* Append a unit string for this OID if there is one */
+ if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
+ xasprintf (&outbuff, "%s %s", outbuff, unitv[i]);
+
+ /* Write perfdata with whatever can be parsed by strtod, if possible */
+ ptr = NULL;
+ strtod(show, &ptr);
+ if (ptr > show) {
+ if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
+ temp_string=labels[i];
+ else
+ temp_string=oidname;
+ if (strpbrk (temp_string, " ='\"") == NULL) {
+ strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
+ } else {
+ if (strpbrk (temp_string, "'") == NULL) {
+ quote_string="'";
+ } else {
+ quote_string="\"";
+ }
+ strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
+ strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
+ strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
+ }
+ strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
+ len = sizeof(perfstr)-strlen(perfstr)-1;
+ strncat(perfstr, show, len>ptr-show ? ptr-show : len);
+
+ if (strcmp(type, "") != 0) {
+ strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
+ }
+
+ if (warning_thresholds) {
+ strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
+ if(thlds[i]->warning && thlds[i]->warning->text)
+ strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr)-strlen(perfstr)-1);
+ }
+
+ if (critical_thresholds) {
+ if (!warning_thresholds)
+ strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
+ strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
+ if(thlds[i]->critical && thlds[i]->critical->text)
+ strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr)-strlen(perfstr)-1);
+ }
+
+ strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1);
+ }
+ }
+ total_oids=i;
+
+ /* Save state data, as all data collected now */
+ if(calculate_rate) {
+ string_length=1024;
+ state_string=malloc(string_length);
+ if(state_string==NULL)
+ die(STATE_UNKNOWN, _("Cannot malloc"));
+
+ current_length=0;
+ for(i=0; i<total_oids; i++) {
+ xasprintf(&temp_string,"%.0f",response_value[i]);
+ if(temp_string==NULL)
+ die(STATE_UNKNOWN,_("Cannot asprintf()"));
+ response_length = strlen(temp_string);
+ if(current_length+response_length>string_length) {
+ string_length=current_length+1024;
+ state_string=realloc(state_string,string_length);
+ if(state_string==NULL)
+ die(STATE_UNKNOWN, _("Cannot realloc()"));
+ }
+ strcpy(&state_string[current_length],temp_string);
+ current_length=current_length+response_length;
+ state_string[current_length]=':';
+ current_length++;
+ free(temp_string);
+ }
+ state_string[--current_length]='\0';
+ if (verbose > 2)
+ printf("State string=%s\n",state_string);
+
+ /* This is not strictly the same as time now, but any subtle variations will cancel out */
+ np_state_write_string(current_time, state_string );
+ if(previous_state==NULL) {
+ /* Or should this be highest state? */
+ die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
+ }
+ }
+
+ printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr);
+ if (mult_resp) printf ("%s", mult_resp);
+
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ char *ptr;
+ int c = 1;
+ int j = 0, jj = 0, ii = 0;
+
+ int option = 0;
+ static struct option longopts[] = {
+ STD_LONG_OPTS,
+ {"community", required_argument, 0, 'C'},
+ {"oid", required_argument, 0, 'o'},
+ {"object", required_argument, 0, 'o'},
+ {"delimiter", required_argument, 0, 'd'},
+ {"nulloid", required_argument, 0, 'z'},
+ {"output-delimiter", required_argument, 0, 'D'},
+ {"string", required_argument, 0, 's'},
+ {"timeout", required_argument, 0, 't'},
+ {"regex", required_argument, 0, 'r'},
+ {"ereg", required_argument, 0, 'r'},
+ {"eregi", required_argument, 0, 'R'},
+ {"label", required_argument, 0, 'l'},
+ {"units", required_argument, 0, 'u'},
+ {"port", required_argument, 0, 'p'},
+ {"retries", required_argument, 0, 'e'},
+ {"miblist", required_argument, 0, 'm'},
+ {"protocol", required_argument, 0, 'P'},
+ {"context", required_argument, 0, 'N'},
+ {"seclevel", required_argument, 0, 'L'},
+ {"secname", required_argument, 0, 'U'},
+ {"authproto", required_argument, 0, 'a'},
+ {"privproto", required_argument, 0, 'x'},
+ {"authpasswd", required_argument, 0, 'A'},
+ {"privpasswd", required_argument, 0, 'X'},
+ {"next", no_argument, 0, 'n'},
+ {"rate", no_argument, 0, L_CALCULATE_RATE},
+ {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
+ {"offset", required_argument, 0, L_OFFSET},
+ {"invert-search", no_argument, 0, L_INVERT_SEARCH},
+ {"perf-oids", no_argument, 0, 'O'},
+ {"ipv4", no_argument, 0, '4'},
+ {"ipv6", no_argument, 0, '6'},
+ {"multiplier", required_argument, 0, 'M'},
+ {"fmtstr", required_argument, 0, 'f'},
+ {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ /* reverse compatibility for very old non-POSIX usage forms */
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ if (strcmp ("-wv", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ if (strcmp ("-cv", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:",
+ longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* usage */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* verbose */
+ verbose++;
+ break;
+
+ /* Connection info */
+ case 'C': /* group or community */
+ community = optarg;
+ break;
+ case 'H': /* Host or server */
+ server_address = optarg;
+ break;
+ case 'p': /* TCP port number */
+ port = optarg;
+ break;
+ case 'm': /* List of MIBS */
+ miblist = optarg;
+ break;
+ case 'n': /* usesnmpgetnext */
+ usesnmpgetnext = TRUE;
+ break;
+ case 'P': /* SNMP protocol version */
+ proto = optarg;
+ break;
+ case 'N': /* SNMPv3 context */
+ context = optarg;
+ break;
+ case 'L': /* security level */
+ seclevel = optarg;
+ break;
+ case 'U': /* security username */
+ secname = optarg;
+ break;
+ case 'a': /* auth protocol */
+ authproto = optarg;
+ break;
+ case 'x': /* priv protocol */
+ privproto = optarg;
+ break;
+ case 'A': /* auth passwd */
+ authpasswd = optarg;
+ break;
+ case 'X': /* priv passwd */
+ privpasswd = optarg;
+ break;
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ timeout_interval = atoi (optarg);
+ break;
+
+ /* Test parameters */
+ case 'c': /* critical threshold */
+ critical_thresholds = optarg;
+ break;
+ case 'w': /* warning threshold */
+ warning_thresholds = optarg;
+ break;
+ case 'e': /* PRELIMINARY - may change */
+ case 'E': /* PRELIMINARY - may change */
+ if (!is_integer (optarg))
+ usage2 (_("Retries interval must be a positive integer"), optarg);
+ else
+ retries = atoi(optarg);
+ break;
+ case 'o': /* object identifier */
+ if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) {
+ /*
+ * we have something other than digits, periods and comas,
+ * so we have a mib variable, rather than just an SNMP OID,
+ * so we have to actually read the mib files
+ */
+ needmibs = TRUE;
+ }
+ for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
+ while (j >= oids_size) {
+ oids_size += OID_COUNT_STEP;
+ oids = realloc(oids, oids_size * sizeof (*oids));
+ }
+ oids[j] = strdup(ptr);
+ }
+ numoids = j;
+ if (c == 'E' || c == 'e') {
+ jj++;
+ ii++;
+ while (j+1 >= eval_size) {
+ eval_size += OID_COUNT_STEP;
+ eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
+ memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
+ }
+ if (c == 'E')
+ eval_method[j+1] |= WARN_PRESENT;
+ else if (c == 'e')
+ eval_method[j+1] |= CRIT_PRESENT;
+ }
+ break;
+ case 'z': /* Null OID Return Check */
+ if (!is_integer (optarg))
+ usage2 (_("Exit status must be a positive integer"), optarg);
+ else
+ nulloid = atoi(optarg);
+ break;
+ case 's': /* string or substring */
+ strncpy (string_value, optarg, sizeof (string_value) - 1);
+ string_value[sizeof (string_value) - 1] = 0;
+ while (jj >= eval_size) {
+ eval_size += OID_COUNT_STEP;
+ eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
+ memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
+ }
+ eval_method[jj++] = CRIT_STRING;
+ ii++;
+ break;
+ case 'R': /* regex */
+ cflags = REG_ICASE;
+ // fall through
+ case 'r': /* regex */
+ cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
+ strncpy (regex_expect, optarg, sizeof (regex_expect) - 1);
+ regex_expect[sizeof (regex_expect) - 1] = 0;
+ errcode = regcomp (&preg, regex_expect, cflags);
+ if (errcode != 0) {
+ regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
+ printf (_("Could Not Compile Regular Expression"));
+ return ERROR;
+ }
+ while (jj >= eval_size) {
+ eval_size += OID_COUNT_STEP;
+ eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
+ memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
+ }
+ eval_method[jj++] = CRIT_REGEX;
+ ii++;
+ break;
+
+ /* Format */
+ case 'd': /* delimiter */
+ delimiter = strscpy (delimiter, optarg);
+ break;
+ case 'D': /* output-delimiter */
+ output_delim = strscpy (output_delim, optarg);
+ break;
+ case 'l': /* label */
+ nlabels++;
+ if (nlabels > labels_size) {
+ labels_size += 8;
+ labels = realloc (labels, labels_size * sizeof(*labels));
+ if (labels == NULL)
+ die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
+ }
+ labels[nlabels - 1] = optarg;
+ ptr = thisarg (optarg);
+ labels[nlabels - 1] = ptr;
+ if (ptr[0] == '\'')
+ labels[nlabels - 1] = ptr + 1;
+ while (ptr && (ptr = nextarg (ptr))) {
+ nlabels++;
+ if (nlabels > labels_size) {
+ labels_size += 8;
+ labels = realloc (labels, labels_size * sizeof(*labels));
+ if (labels == NULL)
+ die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
+ }
+ ptr = thisarg (ptr);
+ if (ptr[0] == '\'')
+ labels[nlabels - 1] = ptr + 1;
+ else
+ labels[nlabels - 1] = ptr;
+ }
+ break;
+ case 'u': /* units */
+ units = optarg;
+ nunits++;
+ if (nunits > unitv_size) {
+ unitv_size += 8;
+ unitv = realloc (unitv, unitv_size * sizeof(*unitv));
+ if (unitv == NULL)
+ die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
+ }
+ unitv[nunits - 1] = optarg;
+ ptr = thisarg (optarg);
+ unitv[nunits - 1] = ptr;
+ if (ptr[0] == '\'')
+ unitv[nunits - 1] = ptr + 1;
+ while (ptr && (ptr = nextarg (ptr))) {
+ if (nunits > unitv_size) {
+ unitv_size += 8;
+ unitv = realloc (unitv, unitv_size * sizeof(*unitv));
+ if (units == NULL)
+ die (STATE_UNKNOWN, _("Could not realloc() units\n"));
+ }
+ nunits++;
+ ptr = thisarg (ptr);
+ if (ptr[0] == '\'')
+ unitv[nunits - 1] = ptr + 1;
+ else
+ unitv[nunits - 1] = ptr;
+ }
+ break;
+ case L_CALCULATE_RATE:
+ if(calculate_rate==0)
+ np_enable_state(NULL, 1);
+ calculate_rate = 1;
+ break;
+ case L_RATE_MULTIPLIER:
+ if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
+ usage2(_("Rate multiplier must be a positive integer"),optarg);
+ break;
+ case L_OFFSET:
+ offset=strtod(optarg,NULL);
+ break;
+ case L_INVERT_SEARCH:
+ invert_search=1;
+ break;
+ case 'O':
+ perf_labels=0;
+ break;
+ case '4':
+ break;
+ case '6':
+ xasprintf(&ip_version, "udp6:");
+ if(verbose>2)
+ printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
+ break;
+ case 'M':
+ if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) {
+ multiplier=strtod(optarg,NULL);
+ }
+ break;
+ case 'f':
+ if (multiplier != 1.0) {
+ fmtstr=optarg;
+ fmtstr_set = true;
+ }
+ break;
+ case L_IGNORE_MIB_PARSING_ERRORS:
+ ignore_mib_parsing_errors = true;
+ }
+ }
+
+ if (server_address == NULL)
+ server_address = argv[optind];
+
+ if (community == NULL)
+ community = strdup (DEFAULT_COMMUNITY);
+
+ return validate_arguments ();
+}
+
+
+/******************************************************************************
+
+@@-
+<sect3>
+<title>validate_arguments</title>
+
+<para>&PROTO_validate_arguments;</para>
+
+<para>Checks to see if the default miblist needs to be loaded. Also verifies
+the authentication and authorization combinations based on protocol version
+selected.</para>
+
+<para></para>
+
+</sect3>
+-@@
+******************************************************************************/
+
+
+
+int
+validate_arguments ()
+{
+ /* check whether to load locally installed MIBS (CPU/disk intensive) */
+ if (miblist == NULL) {
+ if ( needmibs == TRUE ) {
+ miblist = strdup (DEFAULT_MIBLIST);
+ }else{
+ miblist = ""; /* don't read any mib files for numeric oids */
+ }
+ }
+
+ /* Check server_address is given */
+ if (server_address == NULL)
+ die(STATE_UNKNOWN, _("No host specified\n"));
+
+ /* Check oid is given */
+ if (numoids == 0)
+ die(STATE_UNKNOWN, _("No OIDs specified\n"));
+
+ if (proto == NULL)
+ xasprintf(&proto, DEFAULT_PROTOCOL);
+
+ if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
+ numauthpriv = 2;
+ authpriv = calloc (numauthpriv, sizeof (char *));
+ authpriv[0] = strdup ("-c");
+ authpriv[1] = strdup (community);
+ }
+ else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
+ if (!(context == NULL)) {
+ numcontext = 2;
+ contextargs = calloc (numcontext, sizeof (char *));
+ contextargs[0] = strdup ("-n");
+ contextargs[1] = strdup (context);
+ }
+
+ if (seclevel == NULL)
+ xasprintf(&seclevel, "noAuthNoPriv");
+
+ if (secname == NULL)
+ die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
+
+ if (strcmp(seclevel, "noAuthNoPriv") == 0) {
+ numauthpriv = 4;
+ authpriv = calloc (numauthpriv, sizeof (char *));
+ authpriv[0] = strdup ("-l");
+ authpriv[1] = strdup ("noAuthNoPriv");
+ authpriv[2] = strdup ("-u");
+ authpriv[3] = strdup (secname);
+ } else {
+ if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
+ usage2 (_("Invalid seclevel"), seclevel);
+ }
+
+ if (authproto == NULL )
+ xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
+
+ if (authpasswd == NULL)
+ die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
+
+ if ( strcmp(seclevel, "authNoPriv") == 0 ) {
+ numauthpriv = 8;
+ authpriv = calloc (numauthpriv, sizeof (char *));
+ authpriv[0] = strdup ("-l");
+ authpriv[1] = strdup ("authNoPriv");
+ authpriv[2] = strdup ("-a");
+ authpriv[3] = strdup (authproto);
+ authpriv[4] = strdup ("-u");
+ authpriv[5] = strdup (secname);
+ authpriv[6] = strdup ("-A");
+ authpriv[7] = strdup (authpasswd);
+ } else if ( strcmp(seclevel, "authPriv") == 0 ) {
+ if (privproto == NULL )
+ xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
+
+ if (privpasswd == NULL)
+ die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
+
+ numauthpriv = 12;
+ authpriv = calloc (numauthpriv, sizeof (char *));
+ authpriv[0] = strdup ("-l");
+ authpriv[1] = strdup ("authPriv");
+ authpriv[2] = strdup ("-a");
+ authpriv[3] = strdup (authproto);
+ authpriv[4] = strdup ("-u");
+ authpriv[5] = strdup (secname);
+ authpriv[6] = strdup ("-A");
+ authpriv[7] = strdup (authpasswd);
+ authpriv[8] = strdup ("-x");
+ authpriv[9] = strdup (privproto);
+ authpriv[10] = strdup ("-X");
+ authpriv[11] = strdup (privpasswd);
+ }
+ }
+
+ }
+ else {
+ usage2 (_("Invalid SNMP version"), proto);
+ }
+
+ return OK;
+}
+
+
+
+/* trim leading whitespace
+ if there is a leading quote, make sure it balances */
+
+char *
+thisarg (char *str)
+{
+ str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
+ if (str[0] == '\'') { /* handle SIMPLE quoted strings */
+ if (strlen (str) == 1 || !strstr (str + 1, "'"))
+ die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
+ }
+ return str;
+}
+
+
+
+/* if there's a leading quote, advance to the trailing quote
+ set the trailing quote to '\x0'
+ if the string continues, advance beyond the comma */
+
+char *
+nextarg (char *str)
+{
+ if (str[0] == '\'') {
+ str[0] = 0;
+ if (strlen (str) > 1) {
+ str = strstr (str + 1, "'");
+ return (++str);
+ }
+ else {
+ return NULL;
+ }
+ }
+ if (str[0] == ',') {
+ str[0] = 0;
+ if (strlen (str) > 1) {
+ return (++str);
+ }
+ else {
+ return NULL;
+ }
+ }
+ if ((str = strstr (str, ",")) && strlen (str) > 1) {
+ str[0] = 0;
+ return (++str);
+ }
+ return NULL;
+}
+
+
+
+/* multiply result (values 0 < n < 1 work as divider) */
+char *
+multiply (char *str)
+{
+ char *endptr;
+ double val;
+ char *conv = "%f";
+
+ if(multiplier == 1)
+ return(str);
+
+ if(verbose>2)
+ printf(" multiply input: %s\n", str);
+
+ val = strtod (str, &endptr);
+ if ((val == 0.0) && (endptr == str)) {
+ die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
+ }
+
+ if(verbose>2)
+ printf(" multiply extracted double: %f\n", val);
+ val *= multiplier;
+ if (fmtstr_set) {
+ conv = fmtstr;
+ }
+ if (val == (int)val) {
+ snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
+ } else {
+ if(verbose>2)
+ printf(" multiply using format: %s\n", conv);
+ snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
+ }
+ if(verbose>2)
+ printf(" multiply result: %s\n", buffer);
+ return buffer;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+ printf (UT_IPv46);
+
+ printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
+
+ /* SNMP and Authentication Protocol */
+ printf (" %s\n", "-n, --next");
+ printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
+ printf (" %s\n", "-P, --protocol=[1|2c|3]");
+ printf (" %s\n", _("SNMP protocol version"));
+ printf (" %s\n", "-N, --context=CONTEXT");
+ printf (" %s\n", _("SNMPv3 context"));
+ printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
+ printf (" %s\n", _("SNMPv3 securityLevel"));
+ printf (" %s\n", "-a, --authproto=[MD5|SHA]");
+ printf (" %s\n", _("SNMPv3 auth proto"));
+ printf (" %s\n", "-x, --privproto=[DES|AES]");
+ printf (" %s\n", _("SNMPv3 priv proto (default DES)"));
+
+ /* Authentication Tokens*/
+ printf (" %s\n", "-C, --community=STRING");
+ printf (" %s ", _("Optional community string for SNMP communication"));
+ printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY);
+ printf (" %s\n", "-U, --secname=USERNAME");
+ printf (" %s\n", _("SNMPv3 username"));
+ printf (" %s\n", "-A, --authpasswd=PASSWORD");
+ printf (" %s\n", _("SNMPv3 authentication password"));
+ printf (" %s\n", "-X, --privpasswd=PASSWORD");
+ printf (" %s\n", _("SNMPv3 privacy password"));
+
+ /* OID Stuff */
+ printf (" %s\n", "-o, --oid=OID(s)");
+ printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
+ printf (" %s\n", "-m, --miblist=STRING");
+ printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
+ printf (" %s\n", _("for symbolic OIDs.)"));
+ printf (" %s\n", "-d, --delimiter=STRING");
+ printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
+ printf (" %s\n", _("Any data on the right hand side of the delimiter is considered"));
+ printf (" %s\n", _("to be the data that should be used in the evaluation."));
+ printf (" %s\n", "-z, --nulloid=#");
+ printf (" %s\n", _("If the check returns a 0 length string or NULL value"));
+ printf (" %s\n", _("This option allows you to choose what status you want it to exit"));
+ printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
+ printf (" %s\n", _("0 = OK"));
+ printf (" %s\n", _("1 = WARNING"));
+ printf (" %s\n", _("2 = CRITICAL"));
+ printf (" %s\n", _("3 = UNKNOWN"));
+
+ /* Tests Against Integers */
+ printf (" %s\n", "-w, --warning=THRESHOLD(s)");
+ printf (" %s\n", _("Warning threshold range(s)"));
+ printf (" %s\n", "-c, --critical=THRESHOLD(s)");
+ printf (" %s\n", _("Critical threshold range(s)"));
+ printf (" %s\n", "--rate");
+ printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
+ printf (" %s\n", "--rate-multiplier");
+ printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
+ printf (" %s\n", "--offset=OFFSET");
+ printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
+
+ /* Tests Against Strings */
+ printf (" %s\n", "-s, --string=STRING");
+ printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
+ printf (" %s\n", "-r, --ereg=REGEX");
+ printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
+ printf (" %s\n", "-R, --eregi=REGEX");
+ printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
+ printf (" %s\n", "--invert-search");
+ printf (" %s\n", _("Invert search result (CRITICAL if found)"));
+
+ /* Output Formatting */
+ printf (" %s\n", "-l, --label=STRING");
+ printf (" %s\n", _("Prefix label for output from plugin"));
+ printf (" %s\n", "-u, --units=STRING");
+ printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
+ printf (" %s\n", "-D, --output-delimiter=STRING");
+ printf (" %s\n", _("Separates output on multiple OID requests"));
+ printf (" %s\n", "-M, --multiplier=FLOAT");
+ printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
+ printf (" %s\n", "-f, --fmtstr=STRING");
+ printf (" %s\n", _("C-style format string for float values (see option -M)"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+ printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
+ printf (" %s\n", "-e, --retries=INTEGER");
+ printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
+
+ printf (" %s\n", "-O, --perf-oids");
+ printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
+
+ printf (" %s\n", "--ignore-mib-parsing-errors");
+ printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
+
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
+ printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
+ printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
+ printf (" %s\n", _("list (lists with internal spaces must be quoted)."));
+
+ printf(" -%s", UT_THRESHOLDS_NOTES);
+
+ printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
+ printf (" %s\n", _("- Note that only one string and one regex may be checked at present"));
+ printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
+ printf (" %s\n", _("returned from the SNMP query is an unsigned integer."));
+
+ printf("\n");
+ printf("%s\n", _("Rate Calculation:"));
+ printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when"));
+ printf(" %s\n", _("calculating the counter difference since the last check. check_snmp"));
+ printf(" %s\n", _("saves the last state information in a file so that the rate per second"));
+ printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
+ printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
+ printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
+ printf(" %s\n", _("changing the arguments will create a new state file."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname);
+ printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
+ printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
+ printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
+ printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
+ printf ("[-M multiplier [-f format]]\n");
+}
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
new file mode 100644
index 0000000..8ccbd5a
--- /dev/null
+++ b/plugins/check_ssh.c
@@ -0,0 +1,328 @@
+/*****************************************************************************
+*
+* Monitoring check_ssh plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_ssh plugin
+*
+* Try to connect to an SSH server at specified server and port
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ssh";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#define SSH_DFL_PORT 22
+#define BUFF_SZ 256
+
+int port = -1;
+char *server_name = NULL;
+char *remote_version = NULL;
+char *remote_protocol = NULL;
+int verbose = FALSE;
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol);
+
+
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ alarm (socket_timeout);
+
+ /* ssh_connect exits if error is found */
+ result = ssh_connect (server_name, port, remote_version, remote_protocol);
+
+ alarm (0);
+
+ return (result);
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"host", required_argument, 0, 'H'}, /* backward compatibility */
+ {"hostname", required_argument, 0, 'H'},
+ {"port", required_argument, 0, 'p'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"remote-version", required_argument, 0, 'r'},
+ {"remote-protcol", required_argument, 0, 'P'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ while (1) {
+ c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* help */
+ usage5 ();
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'v': /* verbose */
+ verbose = TRUE;
+ break;
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ socket_timeout = atoi (optarg);
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case 'r': /* remote version */
+ remote_version = optarg;
+ break;
+ case 'P': /* remote version */
+ remote_protocol = optarg;
+ break;
+ case 'H': /* host */
+ if (is_host (optarg) == FALSE)
+ usage2 (_("Invalid hostname/address"), optarg);
+ server_name = optarg;
+ break;
+ case 'p': /* port */
+ if (is_intpos (optarg)) {
+ port = atoi (optarg);
+ }
+ else {
+ usage2 (_("Port number must be a positive integer"), optarg);
+ }
+ }
+ }
+
+ c = optind;
+ if (server_name == NULL && c < argc) {
+ if (is_host (argv[c])) {
+ server_name = argv[c++];
+ }
+ }
+
+ if (port == -1 && c < argc) {
+ if (is_intpos (argv[c])) {
+ port = atoi (argv[c++]);
+ }
+ else {
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ }
+
+ return validate_arguments ();
+}
+
+int
+validate_arguments (void)
+{
+ if (server_name == NULL)
+ return ERROR;
+ if (port == -1) /* funky, but allows -p to override stray integer in args */
+ port = SSH_DFL_PORT;
+ return OK;
+}
+
+
+/************************************************************************
+*
+* Try to connect to SSH server at specified server and port
+*
+*-----------------------------------------------------------------------*/
+
+
+int
+ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
+{
+ int sd;
+ int result;
+ char *output = NULL;
+ char *buffer = NULL;
+ char *ssh_proto = NULL;
+ char *ssh_server = NULL;
+ static char *rev_no = VERSION;
+ struct timeval tv;
+ double elapsed_time;
+
+ gettimeofday(&tv, NULL);
+
+ result = my_tcp_connect (haddr, hport, &sd);
+
+ if (result != STATE_OK)
+ return result;
+
+ output = (char *) malloc (BUFF_SZ + 1);
+ memset (output, 0, BUFF_SZ + 1);
+ recv (sd, output, BUFF_SZ, 0);
+ if (strncmp (output, "SSH", 3)) {
+ printf (_("Server answer: %s"), output);
+ close(sd);
+ exit (STATE_CRITICAL);
+ }
+ else {
+ strip (output);
+ if (verbose)
+ printf ("%s\n", output);
+ ssh_proto = output + 4;
+ ssh_server = ssh_proto + strspn (ssh_proto, "-0123456789. ");
+ ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0;
+
+ xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
+ send (sd, buffer, strlen (buffer), MSG_DONTWAIT);
+ if (verbose)
+ printf ("%s\n", buffer);
+
+ if (remote_version && strcmp(remote_version, ssh_server)) {
+ printf
+ (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"),
+ ssh_server, ssh_proto, remote_version);
+ close(sd);
+ exit (STATE_CRITICAL);
+ }
+
+ if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
+ printf
+ (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s'\n"),
+ ssh_server, ssh_proto, remote_protocol);
+ close(sd);
+ exit (STATE_CRITICAL);
+ }
+
+ elapsed_time = (double)deltime(tv) / 1.0e6;
+
+ printf
+ (_("SSH OK - %s (protocol %s) | %s\n"),
+ ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
+ FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
+ close(sd);
+ exit (STATE_OK);
+ }
+}
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", SSH_DFL_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("Try to connect to an SSH server at specified server and port"));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (UT_IPv46);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (" %s\n", "-r, --remote-version=STRING");
+ printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
+
+ printf (" %s\n", "-P, --remote-protocol=STRING");
+ printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
+
+ printf (UT_VERBOSE);
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
+}
+
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
new file mode 100644
index 0000000..cd965e3
--- /dev/null
+++ b/plugins/check_swap.c
@@ -0,0 +1,610 @@
+/*****************************************************************************
+*
+* Monitoring check_swap plugin
+*
+* License: GPL
+* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_swap plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_swap";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "popen.h"
+#include "utils.h"
+
+#ifdef HAVE_DECL_SWAPCTL
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef HAVE_SYS_SWAP_H
+# include <sys/swap.h>
+# endif
+# ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+# endif
+#endif
+
+#ifndef SWAP_CONVERSION
+# define SWAP_CONVERSION 1
+#endif
+
+typedef struct {
+ int is_percentage;
+ uint64_t value;
+} threshold_t;
+
+int check_swap (float free_swap_mb, float total_swap_mb);
+int process_arguments (int argc, char **argv);
+int validate_arguments (void);
+void print_usage (void);
+void print_help (void);
+
+threshold_t warn;
+threshold_t crit;
+int verbose;
+int allswaps;
+int no_swap_state = STATE_CRITICAL;
+
+int
+main (int argc, char **argv)
+{
+ unsigned int percent_used, percent;
+ uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
+ uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
+ uint64_t tmp_KB = 0;
+ int result = STATE_UNKNOWN;
+ char input_buffer[MAX_INPUT_BUFFER];
+#ifdef HAVE_PROC_MEMINFO
+ FILE *fp;
+#else
+ int conv_factor = SWAP_CONVERSION;
+# ifdef HAVE_SWAP
+ char *temp_buffer;
+ char *swap_command;
+ char *swap_format;
+# else
+# ifdef HAVE_DECL_SWAPCTL
+ int i=0, nswaps=0, swapctl_res=0;
+# ifdef CHECK_SWAP_SWAPCTL_SVR4
+ swaptbl_t *tbl=NULL;
+ swapent_t *ent=NULL;
+# else
+# ifdef CHECK_SWAP_SWAPCTL_BSD
+ struct swapent *ent;
+# endif /* CHECK_SWAP_SWAPCTL_BSD */
+# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
+# endif /* HAVE_DECL_SWAPCTL */
+# endif
+#endif
+ char str[32];
+ char *status;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ status = strdup ("");
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+#ifdef HAVE_PROC_MEMINFO
+ if (verbose >= 3) {
+ printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
+ }
+ fp = fopen (PROC_MEMINFO, "r");
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
+ /*
+ * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
+ * On which kind of system this format exists, I can not say, but I wanted to
+ * document this for people who are not adapt with sscanf anymore, like me
+ */
+ if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
+ dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
+ dskused_mb = dskused_mb / (1024 * 1024);
+ dskfree_mb = dskfree_mb / (1024 * 1024);
+ total_swap_mb += dsktotal_mb;
+ used_swap_mb += dskused_mb;
+ free_swap_mb += dskfree_mb;
+ if (allswaps) {
+ if (dsktotal_mb == 0)
+ percent=100.0;
+ else
+ percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
+ result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
+ if (verbose)
+ xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
+ }
+ }
+
+ /*
+ * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123"
+ * This format exists at least on Debian Linux with a 5.* kernel
+ */
+ else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
+ if (verbose >= 3) {
+ printf("Got %s with %lu\n", str, tmp_KB);
+ }
+ /* I think this part is always in Kb, so convert to mb */
+ if (strcmp ("Total", str) == 0) {
+ dsktotal_mb = tmp_KB / 1024;
+ }
+ else if (strcmp ("Free", str) == 0) {
+ dskfree_mb = dskfree_mb + tmp_KB / 1024;
+ }
+ else if (strcmp ("Cached", str) == 0) {
+ dskfree_mb = dskfree_mb + tmp_KB / 1024;
+ }
+ }
+ }
+ fclose(fp);
+ dskused_mb = dsktotal_mb - dskfree_mb;
+ total_swap_mb = dsktotal_mb;
+ used_swap_mb = dskused_mb;
+ free_swap_mb = dskfree_mb;
+#else
+# ifdef HAVE_SWAP
+ xasprintf(&swap_command, "%s", SWAP_COMMAND);
+ xasprintf(&swap_format, "%s", SWAP_FORMAT);
+
+/* These override the command used if a summary (and thus ! allswaps) is required */
+/* The summary flag returns more accurate information about swap usage on these OSes */
+# ifdef _AIX
+ if (!allswaps) {
+ xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
+ xasprintf(&swap_format, "%s", "%lu%*s %lu");
+ conv_factor = 1;
+ }
+# endif
+
+ if (verbose >= 2)
+ printf (_("Command: %s\n"), swap_command);
+ if (verbose >= 3)
+ printf (_("Format: %s\n"), swap_format);
+
+ child_process = spopen (swap_command);
+ if (child_process == NULL) {
+ printf (_("Could not open pipe: %s\n"), swap_command);
+ return STATE_UNKNOWN;
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL)
+ printf (_("Could not open stderr for %s\n"), swap_command);
+
+ sprintf (str, "%s", "");
+ /* read 1st line */
+ fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
+ if (strcmp (swap_format, "") == 0) {
+ temp_buffer = strtok (input_buffer, " \n");
+ while (temp_buffer) {
+ if (strstr (temp_buffer, "blocks"))
+ sprintf (str, "%s %s", str, "%lu");
+ else if (strstr (temp_buffer, "dskfree"))
+ sprintf (str, "%s %s", str, "%lu");
+ else
+ sprintf (str, "%s %s", str, "%*s");
+ temp_buffer = strtok (NULL, " \n");
+ }
+ }
+
+/* If different swap command is used for summary switch, need to read format differently */
+# ifdef _AIX
+ if (!allswaps) {
+ fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
+ sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
+ free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
+ used_swap_mb = total_swap_mb - free_swap_mb;
+ if (verbose >= 3)
+ printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
+ } else {
+# endif
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+ sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
+
+ dsktotal_mb = dsktotal_mb / conv_factor;
+ /* AIX lists percent used, so this converts to dskfree in MBs */
+# ifdef _AIX
+ dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
+# else
+ dskfree_mb = dskfree_mb / conv_factor;
+# endif
+ if (verbose >= 3)
+ printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
+
+ dskused_mb = dsktotal_mb - dskfree_mb;
+ total_swap_mb += dsktotal_mb;
+ used_swap_mb += dskused_mb;
+ free_swap_mb += dskfree_mb;
+ if (allswaps) {
+ percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
+ result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
+ if (verbose)
+ xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
+ }
+ }
+# ifdef _AIX
+ }
+# endif
+
+ /* If we get anything on STDERR, at least set warning */
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
+ result = max_state (result, STATE_WARNING);
+
+ /* close stderr */
+ (void) fclose (child_stderr);
+
+ /* close the pipe */
+ if (spclose (child_process))
+ result = max_state (result, STATE_WARNING);
+# else
+# ifdef CHECK_SWAP_SWAPCTL_SVR4
+
+ /* get the number of active swap devices */
+ if((nswaps=swapctl(SC_GETNSWP, NULL))== -1)
+ die(STATE_UNKNOWN, _("Error getting swap devices\n") );
+
+ if(nswaps == 0)
+ die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
+
+ if(verbose >= 3)
+ printf("Found %d swap device(s)\n", nswaps);
+
+ /* initialize swap table + entries */
+ tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
+
+ if(tbl==NULL)
+ die(STATE_UNKNOWN, _("malloc() failed!\n"));
+
+ memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
+ tbl->swt_n=nswaps;
+ for(i=0;i<nswaps;i++){
+ if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
+ die(STATE_UNKNOWN, _("malloc() failed!\n"));
+ }
+
+ /* and now, tally 'em up */
+ swapctl_res=swapctl(SC_LIST, tbl);
+ if(swapctl_res < 0){
+ perror(_("swapctl failed: "));
+ die(STATE_UNKNOWN, _("Error in swapctl call\n"));
+ }
+
+ for(i=0;i<nswaps;i++){
+ dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
+ dskfree_mb = (float) tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
+ dskused_mb = ( dsktotal_mb - dskfree_mb );
+
+ if (verbose >= 3)
+ printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
+
+ if(allswaps && dsktotal_mb > 0){
+ percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
+ result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
+ if (verbose) {
+ xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
+ }
+ }
+
+ total_swap_mb += dsktotal_mb;
+ free_swap_mb += dskfree_mb;
+ used_swap_mb += dskused_mb;
+ }
+
+ /* and clean up after ourselves */
+ for(i=0;i<nswaps;i++){
+ free(tbl->swt_ent[i].ste_path);
+ }
+ free(tbl);
+# else
+# ifdef CHECK_SWAP_SWAPCTL_BSD
+
+ /* get the number of active swap devices */
+ nswaps=swapctl(SWAP_NSWAP, NULL, 0);
+
+ /* initialize swap table + entries */
+ ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
+
+ /* and now, tally 'em up */
+ swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
+ if(swapctl_res < 0){
+ perror(_("swapctl failed: "));
+ die(STATE_UNKNOWN, _("Error in swapctl call\n"));
+ }
+
+ for(i=0;i<nswaps;i++){
+ dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
+ dskused_mb = (float) ent[i].se_inuse / conv_factor;
+ dskfree_mb = ( dsktotal_mb - dskused_mb );
+
+ if(allswaps && dsktotal_mb > 0){
+ percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
+ result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
+ if (verbose) {
+ xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
+ }
+ }
+
+ total_swap_mb += dsktotal_mb;
+ free_swap_mb += dskfree_mb;
+ used_swap_mb += dskused_mb;
+ }
+
+ /* and clean up after ourselves */
+ free(ent);
+
+# endif /* CHECK_SWAP_SWAPCTL_BSD */
+# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
+# endif /* HAVE_SWAP */
+#endif /* HAVE_PROC_MEMINFO */
+
+ /* if total_swap_mb == 0, let's not divide by 0 */
+ if(total_swap_mb) {
+ percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
+ } else {
+ percent_used = 100;
+ status = "- Swap is either disabled, not present, or of zero size. ";
+ }
+
+ result = max_state (result, check_swap(free_swap_mb, total_swap_mb));
+ printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"),
+ state_text (result),
+ (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
+
+ uint64_t warn_print = warn.value;
+ if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100);
+ uint64_t crit_print = crit.value;
+ if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
+
+ puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B",
+ TRUE, warn_print,
+ TRUE, crit_print,
+ TRUE, 0,
+ TRUE, (long) total_swap_mb * 1024 * 1024));
+
+ return result;
+}
+
+
+int
+check_swap(float free_swap_mb, float total_swap_mb)
+{
+
+ if (!total_swap_mb) return no_swap_state;
+
+ uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */
+
+ if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
+ if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
+
+
+ uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100;
+
+ if (crit.is_percentage &&
+ crit.value != 0 &&
+ usage_percentage >= (100 - crit.value))
+ {
+ return STATE_CRITICAL;
+ }
+
+ if (warn.is_percentage &&
+ warn.value != 0 &&
+ usage_percentage >= (100 - warn.value))
+ {
+ return STATE_WARNING;
+ }
+
+ return STATE_OK;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c = 0; /* option character */
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"allswaps", no_argument, 0, 'a'},
+ {"no-swap", required_argument, 0, 'n'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ while (1) {
+ c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'w': /* warning size threshold */
+ {
+ /*
+ * We expect either a positive integer value without a unit, which means
+ * the unit is Bytes or a positive integer value and a percentage sign (%),
+ * which means the value must be with 0 and 100 and is relative to the total swap
+ */
+ size_t length;
+ length = strlen(optarg);
+
+ if (optarg[length - 1] == '%') {
+ /* It's percentage */
+ warn.is_percentage = 1;
+ optarg[length - 1] = '\0';
+ if (is_uint64(optarg, &warn.value)) {
+ if (warn.value > 100) {
+ usage4 (_("Warning threshold percentage must be <= 100!"));
+ }
+ }
+ break;
+ } else {
+ /* It's Bytes */
+ warn.is_percentage = 0;
+ if (is_uint64(optarg, &warn.value)) {
+ break;
+ } else {
+ usage4 (_("Warning threshold be positive integer or percentage!"));
+ }
+ }
+ }
+ case 'c': /* critical size threshold */
+ {
+ /*
+ * We expect either a positive integer value without a unit, which means
+ * the unit is Bytes or a positive integer value and a percentage sign (%),
+ * which means the value must be with 0 and 100 and is relative to the total swap
+ */
+ size_t length;
+ length = strlen(optarg);
+
+ if (optarg[length - 1] == '%') {
+ /* It's percentage */
+ crit.is_percentage = 1;
+ optarg[length - 1] = '\0';
+ if (is_uint64(optarg, &crit.value)) {
+ if (crit.value> 100) {
+ usage4 (_("Critical threshold percentage must be <= 100!"));
+ }
+ }
+ break;
+ } else {
+ /* It's Bytes */
+ crit.is_percentage = 0;
+ if (is_uint64(optarg, &crit.value)) {
+ break;
+ } else {
+ usage4 (_("Critical threshold be positive integer or percentage!"));
+ }
+ }
+ }
+ case 'a': /* all swap */
+ allswaps = TRUE;
+ break;
+ case 'n':
+ if ((no_swap_state = mp_translate_state(optarg)) == ERROR) {
+ usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ }
+ break;
+ case 'v': /* verbose */
+ verbose++;
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case '?': /* error */
+ usage5 ();
+ }
+ }
+
+ c = optind;
+ if (c == argc)
+ return validate_arguments ();
+
+ return validate_arguments ();
+}
+
+
+
+int
+validate_arguments (void)
+{
+ if (warn.value == 0 && crit.value == 0) {
+ return ERROR;
+ }
+ else if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
+ /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
+ * and crit is absolute. We cannot determine the condition at this point since we
+ * dont know the value of total swap yet
+ */
+ usage4(_("Warning should be more than critical"));
+ }
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf (_(COPYRIGHT), copyright, email);
+
+ printf ("%s\n", _("Check swap space on local machine."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
+ printf (" %s\n", "-w, --warning=PERCENT%");
+ printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
+ printf (" %s\n", "-c, --critical=PERCENT%");
+ printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
+ printf (" %s\n", "-a, --allswaps");
+ printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
+ printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
+ printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
+ printf (UT_VERBOSE);
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
+ printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf (" %s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
+ printf (" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
+}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
new file mode 100644
index 0000000..1d307cf
--- /dev/null
+++ b/plugins/check_tcp.c
@@ -0,0 +1,715 @@
+/*****************************************************************************
+*
+* Monitoring check_tcp plugin
+*
+* License: GPL
+* Copyright (c) 1999-2013 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_tcp plugin
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+* $Id$
+*
+*****************************************************************************/
+
+/* progname "check_tcp" changes depending on symlink called */
+char *progname;
+const char *copyright = "1999-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+#include "utils_tcp.h"
+
+#include <ctype.h>
+#include <sys/select.h>
+
+#ifdef HAVE_SSL
+static int check_cert = FALSE;
+static int days_till_exp_warn, days_till_exp_crit;
+# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
+# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
+#else
+# define my_recv(buf, len) read(sd, buf, len)
+# define my_send(buf, len) send(sd, buf, len, 0)
+#endif
+
+/* int my_recv(char *, size_t); */
+static int process_arguments (int, char **);
+void print_help (void);
+void print_usage (void);
+
+#define EXPECT server_expect[0]
+static char *SERVICE = "TCP";
+static char *SEND = NULL;
+static char *QUIT = NULL;
+static int PROTOCOL = IPPROTO_TCP; /* most common is default */
+static int PORT = 0;
+static int READ_TIMEOUT = 2;
+
+static int server_port = 0;
+static char *server_address = NULL;
+static int host_specified = FALSE;
+static char *server_send = NULL;
+static char *server_quit = NULL;
+static char **server_expect;
+static size_t server_expect_count = 0;
+static size_t maxbytes = 0;
+static char **warn_codes = NULL;
+static size_t warn_codes_count = 0;
+static char **crit_codes = NULL;
+static size_t crit_codes_count = 0;
+static unsigned int delay = 0;
+static double warning_time = 0;
+static double critical_time = 0;
+static double elapsed_time = 0;
+static long microsec;
+static int sd = 0;
+#define MAXBUF 1024
+static char buffer[MAXBUF];
+static int expect_mismatch_state = STATE_WARNING;
+static int match_flags = NP_MATCH_EXACT;
+
+#ifdef HAVE_SSL
+static char *sni = NULL;
+static int sni_specified = FALSE;
+#endif
+
+#define FLAG_SSL 0x01
+#define FLAG_VERBOSE 0x02
+#define FLAG_TIME_WARN 0x04
+#define FLAG_TIME_CRIT 0x08
+#define FLAG_HIDE_OUTPUT 0x10
+static size_t flags;
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ int i;
+ char *status = NULL;
+ struct timeval tv;
+ struct timeval timeout;
+ size_t len;
+ int match = -1;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* determine program- and service-name quickly */
+ progname = strrchr(argv[0], '/');
+ if(progname != NULL) progname++;
+ else progname = argv[0];
+
+ len = strlen(progname);
+ if(len > 6 && !memcmp(progname, "check_", 6)) {
+ SERVICE = strdup(progname + 6);
+ for(i = 0; i < len - 6; i++)
+ SERVICE[i] = toupper(SERVICE[i]);
+ }
+
+ /* set up a reasonable buffer at first (will be realloc()'ed if
+ * user specifies other options) */
+ server_expect = calloc(sizeof(char *), 2);
+
+ /* determine defaults for this service's protocol */
+ if (!strncmp(SERVICE, "UDP", 3)) {
+ PROTOCOL = IPPROTO_UDP;
+ }
+ else if (!strncmp(SERVICE, "FTP", 3)) {
+ EXPECT = "220";
+ QUIT = "QUIT\r\n";
+ PORT = 21;
+ }
+ else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) {
+ EXPECT = "+OK";
+ QUIT = "QUIT\r\n";
+ PORT = 110;
+ }
+ else if (!strncmp(SERVICE, "SMTP", 4)) {
+ EXPECT = "220";
+ QUIT = "QUIT\r\n";
+ PORT = 25;
+ }
+ else if (!strncmp(SERVICE, "IMAP", 4)) {
+ EXPECT = "* OK";
+ QUIT = "a1 LOGOUT\r\n";
+ PORT = 143;
+ }
+#ifdef HAVE_SSL
+ else if (!strncmp(SERVICE, "SIMAP", 5)) {
+ EXPECT = "* OK";
+ QUIT = "a1 LOGOUT\r\n";
+ flags |= FLAG_SSL;
+ PORT = 993;
+ }
+ else if (!strncmp(SERVICE, "SPOP", 4)) {
+ EXPECT = "+OK";
+ QUIT = "QUIT\r\n";
+ flags |= FLAG_SSL;
+ PORT = 995;
+ }
+ else if (!strncmp(SERVICE, "SSMTP", 5)) {
+ EXPECT = "220";
+ QUIT = "QUIT\r\n";
+ flags |= FLAG_SSL;
+ PORT = 465;
+ }
+ else if (!strncmp(SERVICE, "JABBER", 6)) {
+ SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
+ EXPECT = "<?xml version=\'1.0\'";
+ QUIT = "</stream:stream>\n";
+ flags |= FLAG_HIDE_OUTPUT;
+ PORT = 5222;
+ }
+ else if (!strncmp (SERVICE, "NNTPS", 5)) {
+ server_expect_count = 2;
+ server_expect[0] = "200";
+ server_expect[1] = "201";
+ QUIT = "QUIT\r\n";
+ flags |= FLAG_SSL;
+ PORT = 563;
+ }
+#endif
+ else if (!strncmp (SERVICE, "NNTP", 4)) {
+ server_expect_count = 2;
+ server_expect = malloc(sizeof(char *) * server_expect_count);
+ server_expect[0] = strdup("200");
+ server_expect[1] = strdup("201");
+ QUIT = "QUIT\r\n";
+ PORT = 119;
+ }
+ else if (!strncmp(SERVICE, "CLAMD", 5)) {
+ SEND = "PING";
+ EXPECT = "PONG";
+ QUIT = NULL;
+ PORT = 3310;
+ }
+ /* fallthrough check, so it's supposed to use reverse matching */
+ else if (strcmp (SERVICE, "TCP"))
+ usage (_("CRITICAL - Generic check_tcp called with unknown service\n"));
+
+ server_address = "127.0.0.1";
+ server_port = PORT;
+ server_send = SEND;
+ server_quit = QUIT;
+ status = NULL;
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ if(flags & FLAG_VERBOSE) {
+ printf("Using service %s\n", SERVICE);
+ printf("Port: %d\n", server_port);
+ printf("flags: 0x%x\n", (int)flags);
+ }
+
+ if(EXPECT && !server_expect_count)
+ server_expect_count++;
+
+ if(PROTOCOL==IPPROTO_UDP && !(server_expect_count && server_send)){
+ usage(_("With UDP checks, a send/expect string must be specified."));
+ }
+
+ /* set up the timer */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+ alarm (socket_timeout);
+
+ /* try to connect to the host at the given port number */
+ gettimeofday (&tv, NULL);
+
+ result = np_net_connect (server_address, server_port, &sd, PROTOCOL);
+ if (result == STATE_CRITICAL) return econn_refuse_state;
+
+#ifdef HAVE_SSL
+ if (flags & FLAG_SSL){
+ result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL));
+ if (result == STATE_OK && check_cert == TRUE) {
+ result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
+ }
+ }
+ if(result != STATE_OK){
+ if(sd) close(sd);
+ np_net_ssl_cleanup();
+ return result;
+ }
+#endif /* HAVE_SSL */
+
+ if (server_send != NULL) { /* Something to send? */
+ my_send(server_send, strlen(server_send));
+ }
+
+ if (delay > 0) {
+ tv.tv_sec += delay;
+ sleep (delay);
+ }
+
+ if(flags & FLAG_VERBOSE) {
+ if (server_send) {
+ printf("Send string: %s\n", server_send);
+ }
+ if (server_quit) {
+ printf("Quit string: %s\n", server_quit);
+ }
+ printf("server_expect_count: %d\n", (int)server_expect_count);
+ for(i = 0; i < server_expect_count; i++)
+ printf("\t%d: %s\n", i, server_expect[i]);
+ }
+
+ /* if(len) later on, we know we have a non-NULL response */
+ len = 0;
+ if (server_expect_count) {
+
+ /* watch for the expect string */
+ while ((i = my_recv(buffer, sizeof(buffer))) > 0) {
+ status = realloc(status, len + i + 1);
+ memcpy(&status[len], buffer, i);
+ len += i;
+ status[len] = '\0';
+
+ /* stop reading if user-forced */
+ if (maxbytes && len >= maxbytes)
+ break;
+
+ if ((match = np_expect_match(status,
+ server_expect,
+ server_expect_count,
+ match_flags)) != NP_MATCH_RETRY)
+ break;
+
+ /* some protocols wait for further input, so make sure we don't wait forever */
+ FD_SET(sd, &rfds);
+ timeout.tv_sec = READ_TIMEOUT;
+ timeout.tv_usec = 0;
+ if(select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0)
+ break;
+ }
+ if (match == NP_MATCH_RETRY)
+ match = NP_MATCH_FAILURE;
+
+ /* no data when expected, so return critical */
+ if (len == 0)
+ die (STATE_CRITICAL, _("No data received from host\n"));
+
+ /* print raw output if we're debugging */
+ if(flags & FLAG_VERBOSE)
+ printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n",
+ (int)len + 1, status);
+ /* strip whitespace from end of output */
+ while(--len > 0 && isspace(status[len]))
+ status[len] = '\0';
+ }
+
+ if (server_quit != NULL) {
+ my_send(server_quit, strlen(server_quit));
+ }
+ if (sd) close (sd);
+#ifdef HAVE_SSL
+ np_net_ssl_cleanup();
+#endif
+
+ microsec = deltime (tv);
+ elapsed_time = (double)microsec / 1.0e6;
+
+ if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time)
+ result = STATE_CRITICAL;
+ else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
+ result = STATE_WARNING;
+
+ /* did we get the response we hoped? */
+ if(match == NP_MATCH_FAILURE && result != STATE_CRITICAL)
+ result = expect_mismatch_state;
+
+ /* reset the alarm */
+ alarm (0);
+
+ /* this is a bit stupid, because we don't want to print the
+ * response time (which can look ok to the user) if we didn't get
+ * the response we were looking for. if-else */
+ printf("%s %s - ", SERVICE, state_text(result));
+
+ if(match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT))
+ printf("Unexpected response from host/socket: %s", status);
+ else {
+ if(match == NP_MATCH_FAILURE)
+ printf("Unexpected response from host/socket on ");
+ else
+ printf("%.3f second response time on ", elapsed_time);
+ if(server_address[0] != '/') {
+ if (host_specified)
+ printf("%s port %d",
+ server_address, server_port);
+ else
+ printf("port %d", server_port);
+ }
+ else
+ printf("socket %s", server_address);
+ }
+
+ if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len)
+ printf (" [%s]", status);
+
+ /* perf-data doesn't apply when server doesn't talk properly,
+ * so print all zeroes on warn and crit. Use fperfdata since
+ * localisation settings can make different outputs */
+ if(match == NP_MATCH_FAILURE)
+ printf ("|%s",
+ fperfdata ("time", elapsed_time, "s",
+ (flags & FLAG_TIME_WARN ? TRUE : FALSE), 0,
+ (flags & FLAG_TIME_CRIT ? TRUE : FALSE), 0,
+ TRUE, 0,
+ TRUE, socket_timeout)
+ );
+ else
+ printf("|%s",
+ fperfdata ("time", elapsed_time, "s",
+ (flags & FLAG_TIME_WARN ? TRUE : FALSE), warning_time,
+ (flags & FLAG_TIME_CRIT ? TRUE : FALSE), critical_time,
+ TRUE, 0,
+ TRUE, socket_timeout)
+ );
+
+ putchar('\n');
+ return result;
+}
+
+
+
+/* process command-line arguments */
+static int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ int escape = 0;
+ char *temp;
+
+ enum {
+ SNI_OPTION = CHAR_MAX + 1
+ };
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical-codes", required_argument, 0, 'C'},
+ {"warning-codes", required_argument, 0, 'W'},
+ {"timeout", required_argument, 0, 't'},
+ {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */
+ {"port", required_argument, 0, 'p'},
+ {"escape", no_argument, 0, 'E'},
+ {"all", no_argument, 0, 'A'},
+ {"send", required_argument, 0, 's'},
+ {"expect", required_argument, 0, 'e'},
+ {"maxbytes", required_argument, 0, 'm'},
+ {"quit", required_argument, 0, 'q'},
+ {"jail", no_argument, 0, 'j'},
+ {"delay", required_argument, 0, 'd'},
+ {"refuse", required_argument, 0, 'r'},
+ {"mismatch", required_argument, 0, 'M'},
+ {"use-ipv4", no_argument, 0, '4'},
+ {"use-ipv6", no_argument, 0, '6'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {"ssl", no_argument, 0, 'S'},
+ {"sni", required_argument, 0, SNI_OPTION},
+ {"certificate", required_argument, 0, 'D'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ usage4 (_("No arguments found"));
+
+ /* backwards compatibility */
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ if (!is_option (argv[1])) {
+ server_address = argv[1];
+ argv[1] = argv[0];
+ argv = &argv[1];
+ argc--;
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:",
+ longopts, &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'v': /* verbose mode */
+ flags |= FLAG_VERBOSE;
+ match_flags |= NP_MATCH_VERBOSE;
+ break;
+ case '4':
+ address_family = AF_INET;
+ break;
+ case '6':
+#ifdef USE_IPV6
+ address_family = AF_INET6;
+#else
+ usage4 (_("IPv6 support not available"));
+#endif
+ break;
+ case 'H': /* hostname */
+ host_specified = TRUE;
+ server_address = optarg;
+ break;
+ case 'c': /* critical */
+ critical_time = strtod (optarg, NULL);
+ flags |= FLAG_TIME_CRIT;
+ break;
+ case 'j': /* hide output */
+ flags |= FLAG_HIDE_OUTPUT;
+ break;
+ case 'w': /* warning */
+ warning_time = strtod (optarg, NULL);
+ flags |= FLAG_TIME_WARN;
+ break;
+ case 'C':
+ crit_codes = realloc (crit_codes, ++crit_codes_count);
+ crit_codes[crit_codes_count - 1] = optarg;
+ break;
+ case 'W':
+ warn_codes = realloc (warn_codes, ++warn_codes_count);
+ warn_codes[warn_codes_count - 1] = optarg;
+ break;
+ case 't': /* timeout */
+ if (!is_intpos (optarg))
+ usage4 (_("Timeout interval must be a positive integer"));
+ else
+ socket_timeout = atoi (optarg);
+ break;
+ case 'p': /* port */
+ if (!is_intpos (optarg))
+ usage4 (_("Port must be a positive integer"));
+ else
+ server_port = atoi (optarg);
+ break;
+ case 'E':
+ escape = 1;
+ break;
+ case 's':
+ if (escape)
+ server_send = np_escaped_string(optarg);
+ else
+ xasprintf(&server_send, "%s", optarg);
+ break;
+ case 'e': /* expect string (may be repeated) */
+ match_flags &= ~NP_MATCH_EXACT;
+ if (server_expect_count == 0)
+ server_expect = malloc (sizeof (char *) * (++server_expect_count));
+ else
+ server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count));
+ server_expect[server_expect_count - 1] = optarg;
+ break;
+ case 'm':
+ if (!is_intpos (optarg))
+ usage4 (_("Maxbytes must be a positive integer"));
+ else
+ maxbytes = strtol (optarg, NULL, 0);
+ break;
+ case 'q':
+ if (escape)
+ server_quit = np_escaped_string(optarg);
+ else
+ xasprintf(&server_quit, "%s\r\n", optarg);
+ break;
+ case 'r':
+ if (!strncmp(optarg,"ok",2))
+ econn_refuse_state = STATE_OK;
+ else if (!strncmp(optarg,"warn",4))
+ econn_refuse_state = STATE_WARNING;
+ else if (!strncmp(optarg,"crit",4))
+ econn_refuse_state = STATE_CRITICAL;
+ else
+ usage4 (_("Refuse must be one of ok, warn, crit"));
+ break;
+ case 'M':
+ if (!strncmp(optarg,"ok",2))
+ expect_mismatch_state = STATE_OK;
+ else if (!strncmp(optarg,"warn",4))
+ expect_mismatch_state = STATE_WARNING;
+ else if (!strncmp(optarg,"crit",4))
+ expect_mismatch_state = STATE_CRITICAL;
+ else
+ usage4 (_("Mismatch must be one of ok, warn, crit"));
+ break;
+ case 'd':
+ if (is_intpos (optarg))
+ delay = atoi (optarg);
+ else
+ usage4 (_("Delay must be a positive integer"));
+ break;
+ case 'D': /* Check SSL cert validity - days 'til certificate expiration */
+#ifdef HAVE_SSL
+# ifdef USE_OPENSSL /* XXX */
+ if ((temp=strchr(optarg,','))!=NULL) {
+ *temp='\0';
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi (optarg);
+ *temp=',';
+ temp++;
+ if (!is_intnonneg (temp))
+ usage2 (_("Invalid certificate expiration period"), temp);
+ days_till_exp_crit = atoi (temp);
+ }
+ else {
+ days_till_exp_crit=0;
+ if (!is_intnonneg (optarg))
+ usage2 (_("Invalid certificate expiration period"), optarg);
+ days_till_exp_warn = atoi (optarg);
+ }
+ check_cert = TRUE;
+ flags |= FLAG_SSL;
+ break;
+# endif /* USE_OPENSSL */
+#endif
+ /* fallthrough if we don't have ssl */
+ case 'S':
+#ifdef HAVE_SSL
+ flags |= FLAG_SSL;
+#else
+ die (STATE_UNKNOWN, _("Invalid option - SSL is not available"));
+#endif
+ break;
+ case SNI_OPTION:
+#ifdef HAVE_SSL
+ flags |= FLAG_SSL;
+ sni_specified = TRUE;
+ sni = optarg;
+#else
+ die (STATE_UNKNOWN, _("Invalid option - SSL is not available"));
+#endif
+ break;
+ case 'A':
+ match_flags |= NP_MATCH_ALL;
+ break;
+ }
+ }
+
+ c = optind;
+ if(host_specified == FALSE && c < argc)
+ server_address = strdup (argv[c++]);
+
+ if (server_address == NULL)
+ usage4 (_("You must provide a server address"));
+ else if (server_address[0] != '/' && is_host (server_address) == FALSE)
+ die (STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), server_address);
+
+ return TRUE;
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf (_("This plugin tests %s connections with the specified host (or unix socket).\n\n"),
+ SERVICE);
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', "none");
+
+ printf (UT_IPv46);
+
+ printf (" %s\n", "-E, --escape");
+ printf (" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option"));
+ printf (" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
+ printf (" %s\n", "-s, --send=STRING");
+ printf (" %s\n", _("String to send to the server"));
+ printf (" %s\n", "-e, --expect=STRING");
+ printf (" %s %s\n", _("String to expect in server response"), _("(may be repeated)"));
+ printf (" %s\n", "-A, --all");
+ printf (" %s\n", _("All expect strings need to occur in server response. Default is any"));
+ printf (" %s\n", "-q, --quit=STRING");
+ printf (" %s\n", _("String to send server to initiate a clean close of the connection"));
+ printf (" %s\n", "-r, --refuse=ok|warn|crit");
+ printf (" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
+ printf (" %s\n", "-M, --mismatch=ok|warn|crit");
+ printf (" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
+ printf (" %s\n", "-j, --jail");
+ printf (" %s\n", _("Hide output from TCP socket"));
+ printf (" %s\n", "-m, --maxbytes=INTEGER");
+ printf (" %s\n", _("Close connection once more than this number of bytes are received"));
+ printf (" %s\n", "-d, --delay=INTEGER");
+ printf (" %s\n", _("Seconds to wait between sending string and polling for response"));
+
+#ifdef HAVE_SSL
+ printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
+ printf (" %s\n", _("Minimum number of days a certificate has to be valid."));
+ printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
+ printf (" %s\n", "-S, --ssl");
+ printf (" %s\n", _("Use SSL for the connection."));
+ printf (" %s\n", "--sni=STRING");
+ printf (" %s\n", _("SSL server_name"));
+#endif
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_VERBOSE);
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",progname);
+ printf ("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
+ printf ("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
+ printf ("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
+}
diff --git a/plugins/check_time.c b/plugins/check_time.c
new file mode 100644
index 0000000..baf8c59
--- /dev/null
+++ b/plugins/check_time.c
@@ -0,0 +1,374 @@
+/*****************************************************************************
+*
+* Monitoring check_time plugin
+*
+* License: GPL
+* Copyright (c) 1999-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_time plugin
+*
+* This plugin will check the time difference with the specified host.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_time";
+const char *copyright = "1999-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum {
+ TIME_PORT = 37
+};
+
+#define UNIX_EPOCH 2208988800UL
+
+uint32_t raw_server_time;
+unsigned long server_time, diff_time;
+int warning_time = 0;
+int check_warning_time = FALSE;
+int critical_time = 0;
+int check_critical_time = FALSE;
+unsigned long warning_diff = 0;
+int check_warning_diff = FALSE;
+unsigned long critical_diff = 0;
+int check_critical_diff = FALSE;
+int server_port = TIME_PORT;
+char *server_address = NULL;
+int use_udp = FALSE;
+
+int process_arguments (int, char **);
+void print_help (void);
+void print_usage (void);
+
+int
+main (int argc, char **argv)
+{
+ int sd;
+ int result = STATE_UNKNOWN;
+ time_t conntime;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+ time (&start_time);
+
+ /* try to connect to the host at the given port number */
+ if (use_udp) {
+ result = my_udp_connect (server_address, server_port, &sd);
+ } else {
+ result = my_tcp_connect (server_address, server_port, &sd);
+ }
+
+ if (result != STATE_OK) {
+ if (check_critical_time == TRUE)
+ result = STATE_CRITICAL;
+ else if (check_warning_time == TRUE)
+ result = STATE_WARNING;
+ else
+ result = STATE_UNKNOWN;
+ die (result,
+ _("TIME UNKNOWN - could not connect to server %s, port %d\n"),
+ server_address, server_port);
+ }
+
+ if (use_udp) {
+ if (send (sd, "", 0, 0) < 0) {
+ if (check_critical_time == TRUE)
+ result = STATE_CRITICAL;
+ else if (check_warning_time == TRUE)
+ result = STATE_WARNING;
+ else
+ result = STATE_UNKNOWN;
+ die (result,
+ _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"),
+ server_address, server_port);
+ }
+ }
+
+ /* watch for the connection string */
+ result = recv (sd, (void *)&raw_server_time, sizeof (raw_server_time), 0);
+
+ /* close the connection */
+ close (sd);
+
+ /* reset the alarm */
+ time (&end_time);
+ alarm (0);
+
+ /* return a WARNING status if we couldn't read any data */
+ if (result <= 0) {
+ if (check_critical_time == TRUE)
+ result = STATE_CRITICAL;
+ else if (check_warning_time == TRUE)
+ result = STATE_WARNING;
+ else
+ result = STATE_UNKNOWN;
+ die (result,
+ _("TIME UNKNOWN - no data received from server %s, port %d\n"),
+ server_address, server_port);
+ }
+
+ result = STATE_OK;
+
+ conntime = (end_time - start_time);
+ if (check_critical_time == TRUE && conntime > critical_time)
+ result = STATE_CRITICAL;
+ else if (check_warning_time == TRUE && conntime > warning_time)
+ result = STATE_WARNING;
+
+ if (result != STATE_OK)
+ die (result, _("TIME %s - %d second response time|%s\n"),
+ state_text (result), (int)conntime,
+ perfdata ("time", (long)conntime, "s",
+ check_warning_time, (long)warning_time,
+ check_critical_time, (long)critical_time,
+ TRUE, 0, FALSE, 0));
+
+ server_time = ntohl (raw_server_time) - UNIX_EPOCH;
+ if (server_time > (unsigned long)end_time)
+ diff_time = server_time - (unsigned long)end_time;
+ else
+ diff_time = (unsigned long)end_time - server_time;
+
+ if (check_critical_diff == TRUE && diff_time > critical_diff)
+ result = STATE_CRITICAL;
+ else if (check_warning_diff == TRUE && diff_time > warning_diff)
+ result = STATE_WARNING;
+
+ printf (_("TIME %s - %lu second time difference|%s %s\n"),
+ state_text (result), diff_time,
+ perfdata ("time", (long)conntime, "s",
+ check_warning_time, (long)warning_time,
+ check_critical_time, (long)critical_time,
+ TRUE, 0, FALSE, 0),
+ perfdata ("offset", diff_time, "s",
+ check_warning_diff, warning_diff,
+ check_critical_diff, critical_diff,
+ TRUE, 0, FALSE, 0));
+ return result;
+}
+
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"warning-variance", required_argument, 0, 'w'},
+ {"critical-variance", required_argument, 0, 'c'},
+ {"warning-connect", required_argument, 0, 'W'},
+ {"critical-connect", required_argument, 0, 'C'},
+ {"port", required_argument, 0, 'p'},
+ {"udp", no_argument, 0, 'u'},
+ {"timeout", required_argument, 0, 't'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ usage ("\n");
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wd", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-cd", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-W");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-C");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVH:w:c:W:C:p:t:u", longopts,
+ &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'H': /* hostname */
+ if (is_host (optarg) == FALSE)
+ usage2 (_("Invalid hostname/address"), optarg);
+ server_address = optarg;
+ break;
+ case 'w': /* warning-variance */
+ if (is_intnonneg (optarg)) {
+ warning_diff = strtoul (optarg, NULL, 10);
+ check_warning_diff = TRUE;
+ }
+ else if (strspn (optarg, "0123456789:,") > 0) {
+ if (sscanf (optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) {
+ check_warning_diff = TRUE;
+ check_warning_time = TRUE;
+ }
+ else {
+ usage4 (_("Warning thresholds must be a positive integer"));
+ }
+ }
+ else {
+ usage4 (_("Warning threshold must be a positive integer"));
+ }
+ break;
+ case 'c': /* critical-variance */
+ if (is_intnonneg (optarg)) {
+ critical_diff = strtoul (optarg, NULL, 10);
+ check_critical_diff = TRUE;
+ }
+ else if (strspn (optarg, "0123456789:,") > 0) {
+ if (sscanf (optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) ==
+ 2) {
+ check_critical_diff = TRUE;
+ check_critical_time = TRUE;
+ }
+ else {
+ usage4 (_("Critical thresholds must be a positive integer"));
+ }
+ }
+ else {
+ usage4 (_("Critical threshold must be a positive integer"));
+ }
+ break;
+ case 'W': /* warning-connect */
+ if (!is_intnonneg (optarg))
+ usage4 (_("Warning threshold must be a positive integer"));
+ else
+ warning_time = atoi (optarg);
+ check_warning_time = TRUE;
+ break;
+ case 'C': /* critical-connect */
+ if (!is_intnonneg (optarg))
+ usage4 (_("Critical threshold must be a positive integer"));
+ else
+ critical_time = atoi (optarg);
+ check_critical_time = TRUE;
+ break;
+ case 'p': /* port */
+ if (!is_intnonneg (optarg))
+ usage4 (_("Port must be a positive integer"));
+ else
+ server_port = atoi (optarg);
+ break;
+ case 't': /* timeout */
+ if (!is_intnonneg (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ socket_timeout = atoi (optarg);
+ break;
+ case 'u': /* udp */
+ use_udp = TRUE;
+ }
+ }
+
+ c = optind;
+ if (server_address == NULL) {
+ if (argc > c) {
+ if (is_host (argv[c]) == FALSE)
+ usage2 (_("Invalid hostname/address"), optarg);
+ server_address = argv[c];
+ }
+ else {
+ usage4 (_("Hostname was not supplied"));
+ }
+ }
+
+ return OK;
+}
+
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", TIME_PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin will check the time on the specified host."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n", "-u, --udp");
+ printf (" %s\n", _("Use UDP to connect, not TCP"));
+ printf (" %s\n", "-w, --warning-variance=INTEGER");
+ printf (" %s\n", _("Time difference (sec.) necessary to result in a warning status"));
+ printf (" %s\n", "-c, --critical-variance=INTEGER");
+ printf (" %s\n", _("Time difference (sec.) necessary to result in a critical status"));
+ printf (" %s\n", "-W, --warning-connect=INTEGER");
+ printf (" %s\n", _("Response time (sec.) necessary to result in warning status"));
+ printf (" %s\n", "-C, --critical-connect=INTEGER");
+ printf (" %s\n", _("Response time (sec.) necessary to result in critical status"));
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n",progname);
+ printf (" [-W connect_time] [-C connect_time] [-t timeout]\n");
+}
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
new file mode 100644
index 0000000..68737c4
--- /dev/null
+++ b/plugins/check_ups.c
@@ -0,0 +1,665 @@
+/*****************************************************************************
+*
+* Monitoring check_ups plugin
+*
+* License: GPL
+* Copyright (c) 2000 Tom Shields
+* 2004 Alain Richard <alain.richard@equation.fr>
+* 2004 Arnaud Quette <arnaud.quette@mgeups.com>
+* Copyright (c) 2002-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains Network UPS Tools plugin for Monitoring
+*
+* This plugin tests the UPS service on the specified host. Network UPS Tools
+* from www.networkupstools.org must be running for this plugin to work.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_ups";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "netutils.h"
+#include "utils.h"
+
+enum {
+ PORT = 3493
+};
+
+#define CHECK_NONE 0
+
+#define UPS_NONE 0 /* no supported options */
+#define UPS_UTILITY 1 /* supports utility line voltage */
+#define UPS_BATTPCT 2 /* supports percent battery remaining */
+#define UPS_STATUS 4 /* supports UPS status */
+#define UPS_TEMP 8 /* supports UPS temperature */
+#define UPS_LOADPCT 16 /* supports load percent */
+
+#define UPSSTATUS_NONE 0
+#define UPSSTATUS_OFF 1
+#define UPSSTATUS_OL 2
+#define UPSSTATUS_OB 4
+#define UPSSTATUS_LB 8
+#define UPSSTATUS_CAL 16
+#define UPSSTATUS_RB 32 /*Replace Battery */
+#define UPSSTATUS_BYPASS 64
+#define UPSSTATUS_OVER 128
+#define UPSSTATUS_TRIM 256
+#define UPSSTATUS_BOOST 512
+#define UPSSTATUS_CHRG 1024
+#define UPSSTATUS_DISCHRG 2048
+#define UPSSTATUS_UNKNOWN 4096
+
+enum { NOSUCHVAR = ERROR-1 };
+
+int server_port = PORT;
+char *server_address;
+char *ups_name = NULL;
+double warning_value = 0.0;
+double critical_value = 0.0;
+int check_warn = FALSE;
+int check_crit = FALSE;
+int check_variable = UPS_NONE;
+int supported_options = UPS_NONE;
+int status = UPSSTATUS_NONE;
+
+double ups_utility_voltage = 0.0;
+double ups_battery_percent = 0.0;
+double ups_load_percent = 0.0;
+double ups_temperature = 0.0;
+char *ups_status;
+int temp_output_c = 0;
+
+int determine_status (void);
+int get_ups_variable (const char *, char *);
+
+int process_arguments (int, char **);
+int validate_arguments (void);
+void print_help (void);
+void print_usage (void);
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ char *message;
+ char *data;
+ char *tunits;
+ char temp_buffer[MAX_INPUT_BUFFER];
+ double ups_utility_deviation = 0.0;
+ int res;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ ups_status = strdup ("N/A");
+ data = strdup ("");
+ message = strdup ("");
+
+ /* Parse extra opts if any */
+ argv=np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ /* initialize alarm signal handling */
+ signal (SIGALRM, socket_timeout_alarm_handler);
+
+ /* set socket timeout */
+ alarm (socket_timeout);
+
+ /* get the ups status if possible */
+ if (determine_status () != OK)
+ return STATE_CRITICAL;
+ if (supported_options & UPS_STATUS) {
+
+ ups_status = strdup ("");
+ result = STATE_OK;
+
+ if (status & UPSSTATUS_OFF) {
+ xasprintf (&ups_status, "Off");
+ result = STATE_CRITICAL;
+ }
+ else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
+ (UPSSTATUS_OB | UPSSTATUS_LB)) {
+ xasprintf (&ups_status, _("On Battery, Low Battery"));
+ result = STATE_CRITICAL;
+ }
+ else {
+ if (status & UPSSTATUS_OL) {
+ xasprintf (&ups_status, "%s%s", ups_status, _("Online"));
+ }
+ if (status & UPSSTATUS_OB) {
+ xasprintf (&ups_status, "%s%s", ups_status, _("On Battery"));
+ result = STATE_WARNING;
+ }
+ if (status & UPSSTATUS_LB) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Low Battery"));
+ result = STATE_WARNING;
+ }
+ if (status & UPSSTATUS_CAL) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Calibrating"));
+ }
+ if (status & UPSSTATUS_RB) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Replace Battery"));
+ result = STATE_WARNING;
+ }
+ if (status & UPSSTATUS_BYPASS) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", On Bypass"));
+ }
+ if (status & UPSSTATUS_OVER) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Overload"));
+ }
+ if (status & UPSSTATUS_TRIM) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Trimming"));
+ }
+ if (status & UPSSTATUS_BOOST) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Boosting"));
+ }
+ if (status & UPSSTATUS_CHRG) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Charging"));
+ }
+ if (status & UPSSTATUS_DISCHRG) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Discharging"));
+ }
+ if (status & UPSSTATUS_UNKNOWN) {
+ xasprintf (&ups_status, "%s%s", ups_status, _(", Unknown"));
+ }
+ }
+ xasprintf (&message, "%sStatus=%s ", message, ups_status);
+ }
+
+ /* get the ups utility voltage if possible */
+ res=get_ups_variable ("input.voltage", temp_buffer);
+ if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY;
+ else if (res != OK)
+ return STATE_CRITICAL;
+ else {
+ supported_options |= UPS_UTILITY;
+
+ ups_utility_voltage = atof (temp_buffer);
+ xasprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
+
+ if (ups_utility_voltage > 120.0)
+ ups_utility_deviation = 120.0 - ups_utility_voltage;
+ else
+ ups_utility_deviation = ups_utility_voltage - 120.0;
+
+ if (check_variable == UPS_UTILITY) {
+ if (check_crit==TRUE && ups_utility_deviation>=critical_value) {
+ result = STATE_CRITICAL;
+ }
+ else if (check_warn==TRUE && ups_utility_deviation>=warning_value) {
+ result = max_state (result, STATE_WARNING);
+ }
+ xasprintf (&data, "%s",
+ perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
+ check_warn, (long)(1000*warning_value),
+ check_crit, (long)(1000*critical_value),
+ TRUE, 0, FALSE, 0));
+ } else {
+ xasprintf (&data, "%s",
+ perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
+ FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
+ }
+ }
+
+ /* get the ups battery percent if possible */
+ res=get_ups_variable ("battery.charge", temp_buffer);
+ if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT;
+ else if ( res != OK)
+ return STATE_CRITICAL;
+ else {
+ supported_options |= UPS_BATTPCT;
+ ups_battery_percent = atof (temp_buffer);
+ xasprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
+
+ if (check_variable == UPS_BATTPCT) {
+ if (check_crit==TRUE && ups_battery_percent <= critical_value) {
+ result = STATE_CRITICAL;
+ }
+ else if (check_warn==TRUE && ups_battery_percent<=warning_value) {
+ result = max_state (result, STATE_WARNING);
+ }
+ xasprintf (&data, "%s %s", data,
+ perfdata ("battery", (long)ups_battery_percent, "%",
+ check_warn, (long)(warning_value),
+ check_crit, (long)(critical_value),
+ TRUE, 0, TRUE, 100));
+ } else {
+ xasprintf (&data, "%s %s", data,
+ perfdata ("battery", (long)ups_battery_percent, "%",
+ FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
+ }
+ }
+
+ /* get the ups load percent if possible */
+ res=get_ups_variable ("ups.load", temp_buffer);
+ if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT;
+ else if ( res != OK)
+ return STATE_CRITICAL;
+ else {
+ supported_options |= UPS_LOADPCT;
+ ups_load_percent = atof (temp_buffer);
+ xasprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
+
+ if (check_variable == UPS_LOADPCT) {
+ if (check_crit==TRUE && ups_load_percent>=critical_value) {
+ result = STATE_CRITICAL;
+ }
+ else if (check_warn==TRUE && ups_load_percent>=warning_value) {
+ result = max_state (result, STATE_WARNING);
+ }
+ xasprintf (&data, "%s %s", data,
+ perfdata ("load", (long)ups_load_percent, "%",
+ check_warn, (long)(warning_value),
+ check_crit, (long)(critical_value),
+ TRUE, 0, TRUE, 100));
+ } else {
+ xasprintf (&data, "%s %s", data,
+ perfdata ("load", (long)ups_load_percent, "%",
+ FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
+ }
+ }
+
+ /* get the ups temperature if possible */
+ res=get_ups_variable ("ups.temperature", temp_buffer);
+ if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP;
+ else if ( res != OK)
+ return STATE_CRITICAL;
+ else {
+ supported_options |= UPS_TEMP;
+ if (temp_output_c) {
+ tunits="degC";
+ ups_temperature = atof (temp_buffer);
+ xasprintf (&message, "%sTemp=%3.1fC", message, ups_temperature);
+ }
+ else {
+ tunits="degF";
+ ups_temperature = (atof (temp_buffer) * 1.8) + 32;
+ xasprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
+ }
+
+ if (check_variable == UPS_TEMP) {
+ if (check_crit==TRUE && ups_temperature>=critical_value) {
+ result = STATE_CRITICAL;
+ }
+ else if (check_warn == TRUE && ups_temperature>=warning_value) {
+ result = max_state (result, STATE_WARNING);
+ }
+ xasprintf (&data, "%s %s", data,
+ perfdata ("temp", (long)ups_temperature, tunits,
+ check_warn, (long)(warning_value),
+ check_crit, (long)(critical_value),
+ TRUE, 0, FALSE, 0));
+ } else {
+ xasprintf (&data, "%s %s", data,
+ perfdata ("temp", (long)ups_temperature, tunits,
+ FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
+ }
+ }
+
+ /* if the UPS does not support any options we are looking for, report an error */
+ if (supported_options == UPS_NONE) {
+ result = STATE_CRITICAL;
+ xasprintf (&message, _("UPS does not support any available options\n"));
+ }
+
+ /* reset timeout */
+ alarm (0);
+
+ printf ("UPS %s - %s|%s\n", state_text(result), message, data);
+ return result;
+}
+
+
+
+/* determines what options are supported by the UPS */
+int
+determine_status (void)
+{
+ char recv_buffer[MAX_INPUT_BUFFER];
+ char temp_buffer[MAX_INPUT_BUFFER];
+ char *ptr;
+ int res;
+
+ res=get_ups_variable ("ups.status", recv_buffer);
+ if (res == NOSUCHVAR) return OK;
+ if (res != STATE_OK) {
+ printf ("%s\n", _("Invalid response received from host"));
+ return ERROR;
+ }
+
+ supported_options |= UPS_STATUS;
+
+ strcpy (temp_buffer, recv_buffer);
+ for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
+ ptr = (char *) strtok (NULL, " ")) {
+ if (!strcmp (ptr, "OFF"))
+ status |= UPSSTATUS_OFF;
+ else if (!strcmp (ptr, "OL"))
+ status |= UPSSTATUS_OL;
+ else if (!strcmp (ptr, "OB"))
+ status |= UPSSTATUS_OB;
+ else if (!strcmp (ptr, "LB"))
+ status |= UPSSTATUS_LB;
+ else if (!strcmp (ptr, "CAL"))
+ status |= UPSSTATUS_CAL;
+ else if (!strcmp (ptr, "RB"))
+ status |= UPSSTATUS_RB;
+ else if (!strcmp (ptr, "BYPASS"))
+ status |= UPSSTATUS_BYPASS;
+ else if (!strcmp (ptr, "OVER"))
+ status |= UPSSTATUS_OVER;
+ else if (!strcmp (ptr, "TRIM"))
+ status |= UPSSTATUS_TRIM;
+ else if (!strcmp (ptr, "BOOST"))
+ status |= UPSSTATUS_BOOST;
+ else if (!strcmp (ptr, "CHRG"))
+ status |= UPSSTATUS_CHRG;
+ else if (!strcmp (ptr, "DISCHRG"))
+ status |= UPSSTATUS_DISCHRG;
+ else
+ status |= UPSSTATUS_UNKNOWN;
+ }
+
+ return OK;
+}
+
+
+/* gets a variable value for a specific UPS */
+int
+get_ups_variable (const char *varname, char *buf)
+{
+ /* char command[MAX_INPUT_BUFFER]; */
+ char temp_buffer[MAX_INPUT_BUFFER];
+ char send_buffer[MAX_INPUT_BUFFER];
+ char *ptr;
+ char *logout = "OK Goodbye\n";
+ int logout_len = strlen(logout);
+ int len;
+
+ *buf=0;
+
+ /* create the command string to send to the UPS daemon */
+ /* Add LOGOUT to avoid read failure logs */
+ if (snprintf (send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", ups_name, varname) >= sizeof(send_buffer)) {
+ printf("%s\n", _("UPS name to long for buffer"));
+ return ERROR;
+ }
+
+ /* send the command to the daemon and get a response back */
+ if (process_tcp_request
+ (server_address, server_port, send_buffer, temp_buffer,
+ sizeof (temp_buffer)) != STATE_OK) {
+ printf ("%s\n", _("Invalid response received from host"));
+ return ERROR;
+ }
+
+ ptr = temp_buffer;
+ len = strlen(ptr);
+ if (len > logout_len && strcmp (ptr + len - logout_len, logout) == 0) len -= logout_len;
+ if (len > 0 && ptr[len-1] == '\n') ptr[len-1]=0;
+ if (strcmp (ptr, "ERR UNKNOWN-UPS") == 0) {
+ printf (_("CRITICAL - no such UPS '%s' on that host\n"), ups_name);
+ return ERROR;
+ }
+
+ if (strcmp (ptr, "ERR VAR-NOT-SUPPORTED") == 0) {
+ /*printf ("Error: Variable '%s' is not supported\n", varname);*/
+ return NOSUCHVAR;
+ }
+
+ if (strcmp (ptr, "ERR DATA-STALE") == 0) {
+ printf ("%s\n", _("CRITICAL - UPS data is stale"));
+ return ERROR;
+ }
+
+ if (strncmp (ptr, "ERR", 3) == 0) {
+ printf (_("Unknown error: %s\n"), ptr);
+ return ERROR;
+ }
+
+ ptr = temp_buffer + strlen (varname) + strlen (ups_name) + 6;
+ len = strlen(ptr);
+ if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
+ printf ("%s\n", _("Error: unable to parse variable"));
+ return ERROR;
+ }
+ strncpy (buf, ptr+1, len - 2);
+ buf[len - 2] = 0;
+
+ return OK;
+}
+
+
+/* Command line: CHECK_UPS -H <host_address> -u ups [-p port] [-v variable]
+ [-wv warn_value] [-cv crit_value] [-to to_sec] */
+
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"hostname", required_argument, 0, 'H'},
+ {"ups", required_argument, 0, 'u'},
+ {"port", required_argument, 0, 'p'},
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"timeout", required_argument, 0, 't'},
+ {"temperature", no_argument, 0, 'T'},
+ {"variable", required_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++) {
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+ else if (strcmp ("-wt", argv[c]) == 0)
+ strcpy (argv[c], "-w");
+ else if (strcmp ("-ct", argv[c]) == 0)
+ strcpy (argv[c], "-c");
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "hVTH:u:p:v:c:w:t:", longopts,
+ &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* help */
+ usage5 ();
+ case 'H': /* hostname */
+ if (is_host (optarg)) {
+ server_address = optarg;
+ }
+ else {
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+ break;
+ case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Fahrenheit) */
+ temp_output_c = 1;
+ break;
+ case 'u': /* ups name */
+ ups_name = optarg;
+ break;
+ case 'p': /* port */
+ if (is_intpos (optarg)) {
+ server_port = atoi (optarg);
+ }
+ else {
+ usage2 (_("Port must be a positive integer"), optarg);
+ }
+ break;
+ case 'c': /* critical time threshold */
+ if (is_intnonneg (optarg)) {
+ critical_value = atoi (optarg);
+ check_crit = TRUE;
+ }
+ else {
+ usage2 (_("Critical time must be a positive integer"), optarg);
+ }
+ break;
+ case 'w': /* warning time threshold */
+ if (is_intnonneg (optarg)) {
+ warning_value = atoi (optarg);
+ check_warn = TRUE;
+ }
+ else {
+ usage2 (_("Warning time must be a positive integer"), optarg);
+ }
+ break;
+ case 'v': /* variable */
+ if (!strcmp (optarg, "LINE"))
+ check_variable = UPS_UTILITY;
+ else if (!strcmp (optarg, "TEMP"))
+ check_variable = UPS_TEMP;
+ else if (!strcmp (optarg, "BATTPCT"))
+ check_variable = UPS_BATTPCT;
+ else if (!strcmp (optarg, "LOADPCT"))
+ check_variable = UPS_LOADPCT;
+ else
+ usage2 (_("Unrecognized UPS variable"), optarg);
+ break;
+ case 't': /* timeout */
+ if (is_intnonneg (optarg)) {
+ socket_timeout = atoi (optarg);
+ }
+ else {
+ usage4 (_("Timeout interval must be a positive integer"));
+ }
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ }
+ }
+
+
+ if (server_address == NULL && argc > optind) {
+ if (is_host (argv[optind]))
+ server_address = argv[optind++];
+ else
+ usage2 (_("Invalid hostname/address"), optarg);
+ }
+
+ if (server_address == NULL)
+ server_address = strdup("127.0.0.1");
+
+ return validate_arguments();
+}
+
+
+int
+validate_arguments (void)
+{
+ if (! ups_name) {
+ printf ("%s\n", _("Error : no UPS indicated"));
+ return ERROR;
+ }
+ return OK;
+}
+
+
+void
+print_help (void)
+{
+ char *myport;
+ xasprintf (&myport, "%d", PORT);
+
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 2000 Tom Shields\n");
+ printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
+ printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin tests the UPS service on the specified host. Network UPS Tools"));
+ printf ("%s\n", _("from www.networkupstools.org must be running for this plugin to work."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (UT_HOST_PORT, 'p', myport);
+
+ printf (" %s\n", "-u, --ups=STRING");
+ printf (" %s\n", _("Name of UPS"));
+ printf (" %s\n", "-T, --temperature");
+ printf (" %s\n", _("Output of temperatures in Celsius"));
+ printf (" %s\n", "-v, --variable=STRING");
+ printf (" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT or LOADPCT");
+
+ printf (UT_WARN_CRIT);
+
+ printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
+
+/* TODO: -v clashing with -v/-variable. Commenting out help text since verbose
+ is unused up to now */
+/* printf (UT_VERBOSE); */
+
+ printf ("\n");
+ printf ("%s\n", _("This plugin attempts to determine the status of a UPS (Uninterruptible Power"));
+ printf ("%s\n", _("Supply) on a local or remote host. If the UPS is online or calibrating, the"));
+ printf ("%s\n", _("plugin will return an OK state. If the battery is on it will return a WARNING"));
+ printf ("%s\n", _("state. If the UPS is off or has a low battery the plugin will return a CRITICAL"));
+ printf ("%s\n", _("state."));
+
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("You may also specify a variable to check (such as temperature, utility voltage,"));
+ printf (" %s\n", _("battery load, etc.) as well as warning and critical thresholds for the value"));
+ printf (" %s\n", _("of that variable. If the remote host has multiple UPS that are being monitored"));
+ printf (" %s\n", _("you will have to use the --ups option to specify which UPS to check."));
+ printf ("\n");
+ printf (" %s\n", _("This plugin requires that the UPSD daemon distributed with Russell Kroll's"));
+ printf (" %s\n", _("Network UPS Tools be installed on the remote host. If you do not have the"));
+ printf (" %s\n", _("package installed on your system, you can download it from"));
+ printf (" %s\n", _("http://www.networkupstools.org"));
+
+ printf (UT_SUPPORT);
+}
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -H host -u ups [-p port] [-v variable] [-w warn_value] [-c crit_value] [-to to_sec] [-T]\n", progname);
+}
diff --git a/plugins/check_users.c b/plugins/check_users.c
new file mode 100644
index 0000000..2a9ee98
--- /dev/null
+++ b/plugins/check_users.c
@@ -0,0 +1,277 @@
+/*****************************************************************************
+*
+* Monitoring check_users plugin
+*
+* License: GPL
+* Copyright (c) 2000-2012 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the check_users plugin
+*
+* This plugin checks the number of users currently logged in on the local
+* system and generates an error if the number exceeds the thresholds
+* specified.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "check_users";
+const char *copyright = "2000-2007";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+
+#if HAVE_WTSAPI32_H
+# include <windows.h>
+# include <wtsapi32.h>
+# undef ERROR
+# define ERROR -1
+#elif HAVE_UTMPX_H
+# include <utmpx.h>
+#else
+# include "popen.h"
+#endif
+
+#ifdef HAVE_LIBSYSTEMD
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
+#endif
+
+#define possibly_set(a,b) ((a) == 0 ? (b) : 0)
+
+int process_arguments (int, char **);
+void print_help (void);
+void print_usage (void);
+
+char *warning_range = NULL;
+char *critical_range = NULL;
+thresholds *thlds = NULL;
+
+int
+main (int argc, char **argv)
+{
+ int users = -1;
+ int result = STATE_UNKNOWN;
+#if HAVE_WTSAPI32_H
+ WTS_SESSION_INFO *wtsinfo;
+ DWORD wtscount;
+ DWORD index;
+#elif HAVE_UTMPX_H
+ struct utmpx *putmpx;
+#else
+ char input_buffer[MAX_INPUT_BUFFER];
+#endif
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts (&argc, argv, progname);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage4 (_("Could not parse arguments"));
+
+ users = 0;
+
+#ifdef HAVE_LIBSYSTEMD
+ if (sd_booted () > 0)
+ users = sd_get_sessions (NULL);
+ else {
+#endif
+#if HAVE_WTSAPI32_H
+ if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
+ 0, 1, &wtsinfo, &wtscount)) {
+ printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
+ return STATE_UNKNOWN;
+ }
+
+ for (index = 0; index < wtscount; index++) {
+ LPTSTR username;
+ DWORD size;
+ int len;
+
+ if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
+ wtsinfo[index].SessionId, WTSUserName, &username, &size))
+ continue;
+
+ len = lstrlen(username);
+
+ WTSFreeMemory(username);
+
+ if (len == 0)
+ continue;
+
+ if (wtsinfo[index].State == WTSActive ||
+ wtsinfo[index].State == WTSDisconnected)
+ users++;
+ }
+
+ WTSFreeMemory(wtsinfo);
+#elif HAVE_UTMPX_H
+ /* get currently logged users from utmpx */
+ setutxent ();
+
+ while ((putmpx = getutxent ()) != NULL)
+ if (putmpx->ut_type == USER_PROCESS)
+ users++;
+
+ endutxent ();
+#else
+ /* run the command */
+ child_process = spopen (WHO_COMMAND);
+ if (child_process == NULL) {
+ printf (_("Could not open pipe: %s\n"), WHO_COMMAND);
+ return STATE_UNKNOWN;
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL)
+ printf (_("Could not open stderr for %s\n"), WHO_COMMAND);
+
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+ /* increment 'users' on all lines except total user count */
+ if (input_buffer[0] != '#') {
+ users++;
+ continue;
+ }
+
+ /* get total logged in users */
+ if (sscanf (input_buffer, _("# users=%d"), &users) == 1)
+ break;
+ }
+
+ /* check STDERR */
+ if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
+ result = possibly_set (result, STATE_UNKNOWN);
+ (void) fclose (child_stderr);
+
+ /* close the pipe */
+ if (spclose (child_process))
+ result = possibly_set (result, STATE_UNKNOWN);
+#endif
+#ifdef HAVE_LIBSYSTEMD
+ }
+#endif
+
+ /* check the user count against warning and critical thresholds */
+ result = get_status((double)users, thlds);
+
+ if (result == STATE_UNKNOWN)
+ printf ("%s\n", _("Unable to read output"));
+ else {
+ printf (_("USERS %s - %d users currently logged in |%s\n"),
+ state_text(result), users,
+ sperfdata_int("users", users, "", warning_range,
+ critical_range, TRUE, 0, FALSE, 0));
+ }
+
+ return result;
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+ int option = 0;
+ static struct option longopts[] = {
+ {"critical", required_argument, 0, 'c'},
+ {"warning", required_argument, 0, 'w'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc < 2)
+ usage ("\n");
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVvc:w:", longopts, &option);
+
+ if (c == -1 || c == EOF || c == 1)
+ break;
+
+ switch (c) {
+ case '?': /* print short usage statement if args not parsable */
+ usage5 ();
+ case 'h': /* help */
+ print_help ();
+ exit (STATE_UNKNOWN);
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (STATE_UNKNOWN);
+ case 'c': /* critical */
+ critical_range = optarg;
+ break;
+ case 'w': /* warning */
+ warning_range = optarg;
+ break;
+ }
+ }
+
+ c = optind;
+ if (warning_range == NULL && argc > c)
+ warning_range = argv[c++];
+ if (critical_range == NULL && argc > c)
+ critical_range = argv[c++];
+
+ /* this will abort in case of invalid ranges */
+ set_thresholds (&thlds, warning_range, critical_range);
+
+ if (thlds->warning->end < 0)
+ usage4 (_("Warning threshold must be a positive integer"));
+ if (thlds->critical->end < 0)
+ usage4 (_("Critical threshold must be a positive integer"));
+
+ return OK;
+}
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 1999 Ethan Galstad\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin checks the number of users currently logged in on the local"));
+ printf ("%s\n", _("system and generates an error if the number exceeds the thresholds specified."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+ printf (UT_EXTRA_OPTS);
+
+ printf (" %s\n", "-w, --warning=INTEGER");
+ printf (" %s\n", _("Set WARNING status if more than INTEGER users are logged in"));
+ printf (" %s\n", "-c, --critical=INTEGER");
+ printf (" %s\n", _("Set CRITICAL status if more than INTEGER users are logged in"));
+
+ printf (UT_SUPPORT);
+}
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s -w <users> -c <users>\n", progname);
+}
diff --git a/plugins/common.h b/plugins/common.h
new file mode 100644
index 0000000..6bf4fca
--- /dev/null
+++ b/plugins/common.h
@@ -0,0 +1,228 @@
+/*****************************************************************************
+*
+* Monitoring Plugins common include file
+*
+* License: GPL
+* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
+* Copyright (c) 2003-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains common include files and defines used in many of
+* the plugins.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include "config.h"
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <stdio.h> /* obligatory includes */
+#include <stdlib.h>
+#include <errno.h>
+
+/* This block provides uintmax_t - should be reported to coreutils that this should be added to fsuage.h */
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <unistd.h>
+#ifndef UINTMAX_MAX
+# define UINTMAX_MAX ((uintmax_t) -1)
+#endif
+
+#include <limits.h> /* This is assumed true, because coreutils assume it too */
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#ifdef _AIX
+#ifdef HAVE_MP_H
+#include <mp.h>
+#endif
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* GET_NUMBER_OF_CPUS is a macro to return
+ number of CPUs, if we can get that data.
+ Use configure.in to test for various OS ways of
+ getting that data
+ Will return -1 if cannot get data
+*/
+#if defined(HAVE_SYSCONF__SC_NPROCESSORS_ONLN)
+# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_ONLN)
+#elif defined (HAVE_SYSCONF__SC_NPROCESSORS_CONF)
+# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_CONF)
+#else
+# define GET_NUMBER_OF_CPUS() -1
+#endif
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+/* GNU Libraries */
+#include <getopt.h>
+#include "dirname.h"
+
+#include <locale.h>
+
+#ifdef HAVE_SYS_POLL_H
+# include "sys/poll.h"
+#endif
+
+/*
+ *
+ * Missing Functions
+ *
+ */
+
+#ifndef HAVE_STRTOL
+# define strtol(a,b,c) atol((a))
+#endif
+
+#ifndef HAVE_STRTOUL
+# define strtoul(a,b,c) (unsigned long)atol((a))
+#endif
+
+/* SSL implementations */
+#ifdef HAVE_GNUTLS_OPENSSL_H
+# include <gnutls/openssl.h>
+#else
+# define OPENSSL_LOAD_CONF /* See the OPENSSL_config(3) man page. */
+# ifdef HAVE_SSL_H
+# include <rsa.h>
+# include <crypto.h>
+# include <x509.h>
+# include <pem.h>
+# include <ssl.h>
+# include <err.h>
+# else
+# ifdef HAVE_OPENSSL_SSL_H
+# include <openssl/rsa.h>
+# include <openssl/crypto.h>
+# include <openssl/x509.h>
+# include <openssl/pem.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# endif
+# endif
+#endif
+
+/* openssl 1.1 does not set OPENSSL_NO_SSL2 by default but ships without ssl2 */
+#ifdef OPENSSL_VERSION_NUMBER
+# if OPENSSL_VERSION_NUMBER >= 0x10100000
+# define OPENSSL_NO_SSL2
+# endif
+#endif
+
+/*
+ *
+ * Standard Values
+ *
+ */
+
+/* MariaDB 10.2 client does not set MYSQL_PORT */
+#ifndef MYSQL_PORT
+# define MYSQL_PORT 3306
+#endif
+
+enum {
+ OK = 0,
+ ERROR = -1
+};
+
+/* AIX seems to have this defined somewhere else */
+#ifndef FALSE
+enum {
+ FALSE,
+ TRUE
+};
+#endif
+
+enum {
+ STATE_OK,
+ STATE_WARNING,
+ STATE_CRITICAL,
+ STATE_UNKNOWN,
+ STATE_DEPENDENT
+};
+
+enum {
+ DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
+ MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
+ MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
+};
+
+/*
+ *
+ * Internationalization
+ *
+ */
+#include "gettext.h"
+#define _(String) gettext (String)
+#if ! ENABLE_NLS
+# undef textdomain
+# define textdomain(Domainname) /* empty */
+# undef bindtextdomain
+# define bindtextdomain(Domainname, Dirname) /* empty */
+#endif
+
+/* For non-GNU compilers to ignore __attribute__ */
+#ifndef __GNUC__
+# define __attribute__(x) /* do nothing */
+#endif
+
+#endif /* _COMMON_H_ */
diff --git a/plugins/negate.c b/plugins/negate.c
new file mode 100644
index 0000000..50f62d3
--- /dev/null
+++ b/plugins/negate.c
@@ -0,0 +1,275 @@
+/*****************************************************************************
+*
+* Monitoring negate plugin
+*
+* License: GPL
+* Copyright (c) 2002-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the negate plugin
+*
+* Negates the status of a plugin (returns OK for CRITICAL, and vice-versa).
+* Can also perform custom state switching.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "negate";
+const char *copyright = "2002-2008";
+const char *email = "devel@monitoring-plugins.org";
+
+#define DEFAULT_TIMEOUT 11
+
+#include "common.h"
+#include "utils.h"
+#include "utils_cmd.h"
+
+#include <ctype.h>
+
+/* char *command_line; */
+
+static const char **process_arguments (int, char **);
+void validate_arguments (char **);
+void print_help (void);
+void print_usage (void);
+int subst_text = FALSE;
+
+static int state[4] = {
+ STATE_OK,
+ STATE_WARNING,
+ STATE_CRITICAL,
+ STATE_UNKNOWN,
+};
+
+int
+main (int argc, char **argv)
+{
+ int result = STATE_UNKNOWN;
+ char *sub;
+ char **command_line;
+ output chld_out, chld_err;
+ int i;
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ timeout_interval = DEFAULT_TIMEOUT;
+
+ command_line = (char **) process_arguments (argc, argv);
+
+ /* Set signal handling and alarm */
+ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR)
+ die (STATE_UNKNOWN, _("Cannot catch SIGALRM"));
+
+ (void) alarm ((unsigned) timeout_interval);
+
+ /* catch when the command is quoted */
+ if(command_line[1] == NULL) {
+ result = cmd_run (command_line[0], &chld_out, &chld_err, 0);
+ } else {
+ result = cmd_run_array (command_line, &chld_out, &chld_err, 0);
+ }
+ if (chld_err.lines > 0) {
+ for (i = 0; i < chld_err.lines; i++) {
+ fprintf (stderr, "%s\n", chld_err.line[i]);
+ }
+ }
+
+ /* Return UNKNOWN or worse if no output is returned */
+ if (chld_out.lines == 0)
+ die (max_state_alt (result, STATE_UNKNOWN), _("No data returned from command\n"));
+
+ for (i = 0; i < chld_out.lines; i++) {
+ if (subst_text && result >= 0 && result <= 4 && result != state[result]) {
+ /* Loop over each match found */
+ while ((sub = strstr (chld_out.line[i], state_text (result)))) {
+ /* Terminate the first part and skip over the string we'll substitute */
+ *sub = '\0';
+ sub += strlen (state_text (result));
+ /* then put everything back together */
+ xasprintf (&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text (state[result]), sub);
+ }
+ }
+ printf ("%s\n", chld_out.line[i]);
+ }
+
+ if (result >= 0 && result <= 4) {
+ exit (state[result]);
+ } else {
+ exit (result);
+ }
+}
+
+
+/* process command-line arguments */
+static const char **
+process_arguments (int argc, char **argv)
+{
+ int c;
+ int permute = TRUE;
+
+ int option = 0;
+ static struct option longopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"timeout", required_argument, 0, 't'},
+ {"timeout-result", required_argument, 0, 'T'},
+ {"ok", required_argument, 0, 'o'},
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"unknown", required_argument, 0, 'u'},
+ {"substitute", no_argument, 0, 's'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case '?': /* help */
+ usage5 ();
+ break;
+ case 'h': /* help */
+ print_help ();
+ exit (EXIT_SUCCESS);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (EXIT_SUCCESS);
+ case 't': /* timeout period */
+ if (!is_integer (optarg))
+ usage2 (_("Timeout interval must be a positive integer"), optarg);
+ else
+ timeout_interval = atoi (optarg);
+ break;
+ case 'T': /* Result to return on timeouts */
+ if ((timeout_state = mp_translate_state(optarg)) == ERROR)
+ usage4 (_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ break;
+ case 'o': /* replacement for OK */
+ if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR)
+ usage4 (_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ permute = FALSE;
+ break;
+
+ case 'w': /* replacement for WARNING */
+ if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR)
+ usage4 (_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ permute = FALSE;
+ break;
+ case 'c': /* replacement for CRITICAL */
+ if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR)
+ usage4 (_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ permute = FALSE;
+ break;
+ case 'u': /* replacement for UNKNOWN */
+ if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR)
+ usage4 (_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
+ permute = FALSE;
+ break;
+ case 's': /* Substitute status text */
+ subst_text = TRUE;
+ break;
+ }
+ }
+
+ validate_arguments (&argv[optind]);
+
+ if (permute) { /* No [owcu] switch specified, default to this */
+ state[STATE_OK] = STATE_CRITICAL;
+ state[STATE_CRITICAL] = STATE_OK;
+ }
+
+ return (const char **) &argv[optind];
+}
+
+
+void
+validate_arguments (char **command_line)
+{
+ if (command_line[0] == NULL)
+ usage4 (_("Could not parse arguments"));
+
+ if (strncmp(command_line[0],"/",1) != 0 && strncmp(command_line[0],"./",2) != 0)
+ usage4 (_("Require path to command"));
+}
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("Negates the status of a plugin (returns OK for CRITICAL and vice-versa)."));
+ printf ("%s\n", _("Additional switches can be used to control which state becomes what."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+
+ printf (UT_PLUG_TIMEOUT, timeout_interval);
+ printf (" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status."));
+ printf (" -T, --timeout-result=STATUS\n");
+ printf (" %s\n", _("Custom result on Negate timeouts; see below for STATUS definition\n"));
+
+ printf(" -o, --ok=STATUS\n");
+ printf(" -w, --warning=STATUS\n");
+ printf(" -c, --critical=STATUS\n");
+ printf(" -u, --unknown=STATUS\n");
+ printf(_(" STATUS can be 'OK', 'WARNING', 'CRITICAL' or 'UNKNOWN' without single\n"));
+ printf(_(" quotes. Numeric values are accepted. If nothing is specified, permutes\n"));
+ printf(_(" OK and CRITICAL.\n"));
+ printf(" -s, --substitute\n");
+ printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n"));
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf (" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host");
+ printf (" %s\n", _("Run check_ping and invert result. Must use full path to plugin"));
+ printf (" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'");
+ printf (" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL"));
+ printf ("\n");
+ printf ("%s\n", _("Notes:"));
+ printf (" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it."));
+ printf (" %s\n", _("The full path of the plugin must be provided."));
+ printf (" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL."));
+ printf (" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK."));
+ printf (" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged."));
+ printf ("\n");
+ printf (" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a"));
+ printf (" %s\n", _("plugin by setting the negate timeout a bit lower."));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s [-t timeout] [-Towcu STATE] [-s] <definition of wrapped plugin>\n", progname);
+}
diff --git a/plugins/netutils.c b/plugins/netutils.c
new file mode 100644
index 0000000..1bb4f07
--- /dev/null
+++ b/plugins/netutils.c
@@ -0,0 +1,379 @@
+/*****************************************************************************
+*
+* Monitoring Plugins network utilities
+*
+* License: GPL
+* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
+* Copyright (c) 2003-2008 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains commons functions used in many of the plugins.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#include "common.h"
+#include "netutils.h"
+
+unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
+unsigned int socket_timeout_state = STATE_CRITICAL;
+
+int econn_refuse_state = STATE_CRITICAL;
+int was_refused = FALSE;
+#if USE_IPV6
+int address_family = AF_UNSPEC;
+#else
+int address_family = AF_INET;
+#endif
+
+/* handles socket timeouts */
+void
+socket_timeout_alarm_handler (int sig)
+{
+ if (sig == SIGALRM)
+ printf (_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
+ else
+ printf (_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
+
+ exit (socket_timeout_state);
+}
+
+
+/* connects to a host on a specified tcp port, sends a string, and gets a
+ response. loops on select-recv until timeout or eof to get all of a
+ multi-packet answer */
+int
+process_tcp_request2 (const char *server_address, int server_port,
+ const char *send_buffer, char *recv_buffer, int recv_size)
+{
+
+ int result;
+ int send_result;
+ int recv_result;
+ int sd;
+ struct timeval tv;
+ fd_set readfds;
+ int recv_length = 0;
+
+ result = np_net_connect (server_address, server_port, &sd, IPPROTO_TCP);
+ if (result != STATE_OK)
+ return STATE_CRITICAL;
+
+ send_result = send (sd, send_buffer, strlen (send_buffer), 0);
+ if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
+ printf ("%s\n", _("Send failed"));
+ result = STATE_WARNING;
+ }
+
+ while (1) {
+ /* wait up to the number of seconds for socket timeout
+ minus one for data from the host */
+ tv.tv_sec = socket_timeout - 1;
+ tv.tv_usec = 0;
+ FD_ZERO (&readfds);
+ FD_SET (sd, &readfds);
+ select (sd + 1, &readfds, NULL, NULL, &tv);
+
+ /* make sure some data has arrived */
+ if (!FD_ISSET (sd, &readfds)) { /* it hasn't */
+ if (!recv_length) {
+ strcpy (recv_buffer, "");
+ printf ("%s\n", _("No data was received from host!"));
+ result = STATE_WARNING;
+ }
+ else { /* this one failed, but previous ones worked */
+ recv_buffer[recv_length] = 0;
+ }
+ break;
+ }
+ else { /* it has */
+ recv_result =
+ recv (sd, recv_buffer + recv_length,
+ (size_t)recv_size - recv_length - 1, 0);
+ if (recv_result == -1) {
+ /* recv failed, bail out */
+ strcpy (recv_buffer + recv_length, "");
+ result = STATE_WARNING;
+ break;
+ }
+ else if (recv_result == 0) {
+ /* end of file ? */
+ recv_buffer[recv_length] = 0;
+ break;
+ }
+ else { /* we got data! */
+ recv_length += recv_result;
+ if (recv_length >= recv_size - 1) {
+ /* buffer full, we're done */
+ recv_buffer[recv_size - 1] = 0;
+ break;
+ }
+ }
+ }
+ /* end if(!FD_ISSET(sd,&readfds)) */
+ }
+ /* end while(1) */
+
+ close (sd);
+ return result;
+}
+
+
+/* connects to a host on a specified port, sends a string, and gets a
+ response */
+int
+process_request (const char *server_address, int server_port, int proto,
+ const char *send_buffer, char *recv_buffer, int recv_size)
+{
+ int result;
+ int sd;
+
+ result = STATE_OK;
+
+ result = np_net_connect (server_address, server_port, &sd, proto);
+ if (result != STATE_OK)
+ return STATE_CRITICAL;
+
+ result = send_request (sd, proto, send_buffer, recv_buffer, recv_size);
+
+ close (sd);
+
+ return result;
+}
+
+
+/* opens a tcp or udp connection to a remote host or local socket */
+int
+np_net_connect (const char *host_name, int port, int *sd, int proto)
+{
+ /* send back STATE_UNKOWN if there's an error
+ send back STATE_OK if we connect
+ send back STATE_CRITICAL if we can't connect.
+ Let upstream figure out what to send to the user. */
+ struct addrinfo hints;
+ struct addrinfo *r, *res;
+ struct sockaddr_un su;
+ char port_str[6], host[MAX_HOST_ADDRESS_LENGTH];
+ size_t len;
+ int socktype, result;
+ short is_socket = (host_name[0] == '/');
+
+ socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
+
+ /* as long as it doesn't start with a '/', it's assumed a host or ip */
+ if (!is_socket){
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = address_family;
+ hints.ai_protocol = proto;
+ hints.ai_socktype = socktype;
+
+ len = strlen (host_name);
+ /* check for an [IPv6] address (and strip the brackets) */
+ if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
+ host_name++;
+ len -= 2;
+ }
+ if (len >= sizeof(host))
+ return STATE_UNKNOWN;
+ memcpy (host, host_name, len);
+ host[len] = '\0';
+ snprintf (port_str, sizeof (port_str), "%d", port);
+ result = getaddrinfo (host, port_str, &hints, &res);
+
+ if (result != 0) {
+ printf ("%s\n", gai_strerror (result));
+ return STATE_UNKNOWN;
+ }
+
+ r = res;
+ while (r) {
+ /* attempt to create a socket */
+ *sd = socket (r->ai_family, socktype, r->ai_protocol);
+
+ if (*sd < 0) {
+ printf ("%s\n", _("Socket creation failed"));
+ freeaddrinfo (r);
+ return STATE_UNKNOWN;
+ }
+
+ /* attempt to open a connection */
+ result = connect (*sd, r->ai_addr, r->ai_addrlen);
+
+ if (result == 0) {
+ was_refused = FALSE;
+ break;
+ }
+
+ if (result < 0) {
+ switch (errno) {
+ case ECONNREFUSED:
+ was_refused = TRUE;
+ break;
+ }
+ }
+
+ close (*sd);
+ r = r->ai_next;
+ }
+ freeaddrinfo (res);
+ }
+ /* else the hostname is interpreted as a path to a unix socket */
+ else {
+ if(strlen(host_name) >= UNIX_PATH_MAX){
+ die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
+ }
+ memset(&su, 0, sizeof(su));
+ su.sun_family = AF_UNIX;
+ strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
+ *sd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if(*sd < 0){
+ die(STATE_UNKNOWN, _("Socket creation failed"));
+ }
+ result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
+ if (result < 0 && errno == ECONNREFUSED)
+ was_refused = TRUE;
+ }
+
+ if (result == 0)
+ return STATE_OK;
+ else if (was_refused) {
+ switch (econn_refuse_state) { /* a user-defined expected outcome */
+ case STATE_OK:
+ case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
+ case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
+ if (is_socket)
+ printf("connect to file socket %s: %s\n", host_name, strerror(errno));
+ else
+ printf("connect to address %s and port %d: %s\n",
+ host_name, port, strerror(errno));
+ return STATE_CRITICAL;
+ break;
+ default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
+ return STATE_UNKNOWN;
+ break;
+ }
+ }
+ else {
+ if (is_socket)
+ printf("connect to file socket %s: %s\n", host_name, strerror(errno));
+ else
+ printf("connect to address %s and port %d: %s\n",
+ host_name, port, strerror(errno));
+ return STATE_CRITICAL;
+ }
+}
+
+int
+send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size)
+{
+ int result = STATE_OK;
+ int send_result;
+ int recv_result;
+ struct timeval tv;
+ fd_set readfds;
+
+ send_result = send (sd, send_buffer, strlen (send_buffer), 0);
+ if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) {
+ printf ("%s\n", _("Send failed"));
+ result = STATE_WARNING;
+ }
+
+ /* wait up to the number of seconds for socket timeout minus one
+ for data from the host */
+ tv.tv_sec = socket_timeout - 1;
+ tv.tv_usec = 0;
+ FD_ZERO (&readfds);
+ FD_SET (sd, &readfds);
+ select (sd + 1, &readfds, NULL, NULL, &tv);
+
+ /* make sure some data has arrived */
+ if (!FD_ISSET (sd, &readfds)) {
+ strcpy (recv_buffer, "");
+ printf ("%s\n", _("No data was received from host!"));
+ result = STATE_WARNING;
+ }
+
+ else {
+ recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0);
+ if (recv_result == -1) {
+ strcpy (recv_buffer, "");
+ if (proto != IPPROTO_TCP)
+ printf ("%s\n", _("Receive failed"));
+ result = STATE_WARNING;
+ }
+ else
+ recv_buffer[recv_result] = 0;
+
+ /* die returned string */
+ recv_buffer[recv_size - 1] = 0;
+ }
+ return result;
+}
+
+
+int
+is_host (const char *address)
+{
+ if (is_addr (address) || is_hostname (address))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+void
+host_or_die(const char *str)
+{
+ if(!str || (!is_addr(str) && !is_hostname(str)))
+ usage_va(_("Invalid hostname/address - %s"), str);
+}
+
+int
+is_addr (const char *address)
+{
+#ifdef USE_IPV6
+ if (address_family == AF_INET && is_inet_addr (address))
+ return TRUE;
+ else if (address_family == AF_INET6 && is_inet6_addr (address))
+ return TRUE;
+#else
+ if (is_inet_addr (address))
+ return (TRUE);
+#endif
+
+ return (FALSE);
+}
+
+int
+dns_lookup (const char *in, struct sockaddr_storage *ss, int family)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int retval;
+
+ memset (&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = family;
+
+ retval = getaddrinfo (in, NULL, &hints, &res);
+ if (retval != 0)
+ return FALSE;
+
+ if (ss != NULL)
+ memcpy (ss, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo (res);
+ return TRUE;
+}
diff --git a/plugins/netutils.h b/plugins/netutils.h
new file mode 100644
index 0000000..ea653e7
--- /dev/null
+++ b/plugins/netutils.h
@@ -0,0 +1,120 @@
+/*****************************************************************************
+*
+* Monitoring Plugins net utilities include file
+*
+* License: GPL
+* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
+* Copyright (c) 2003-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains common include files and function definitions
+* used in many of the plugins.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#ifndef _NETUTILS_H_
+#define _NETUTILS_H_
+
+#include "common.h"
+#include "utils.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+# ifndef UNIX_PATH_MAX
+ /* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
+# define UNIX_PATH_MAX 104
+# endif /* UNIX_PATH_MAX */
+#endif /* HAVE_SYS_UN_H */
+
+#ifndef HOST_MAX_BYTES
+# define HOST_MAX_BYTES 255
+#endif
+
+/* process_request and wrapper macros */
+#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \
+ process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize)
+#define process_udp_request(addr, port, sbuf, rbuf, rsize) \
+ process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize)
+int process_tcp_request2 (const char *address, int port,
+ const char *sbuffer, char *rbuffer, int rsize);
+int process_request (const char *address, int port, int proto,
+ const char *sbuffer, char *rbuffer, int rsize);
+
+/* my_connect and wrapper macros */
+#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP)
+#define my_udp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_UDP)
+int np_net_connect(const char *address, int port, int *sd, int proto);
+
+/* send_request and wrapper macros */
+#define send_tcp_request(s, sbuf, rbuf, rsize) \
+ send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize)
+#define send_udp_request(s, sbuf, rbuf, rsize) \
+ send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize)
+int send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size);
+
+
+/* "is_*" wrapper macros and functions */
+int is_host (const char *);
+int is_addr (const char *);
+int dns_lookup (const char *, struct sockaddr_storage *, int);
+void host_or_die(const char *str);
+#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family)
+#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET)
+#ifdef USE_IPV6
+# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6)
+# define is_hostname(addr) resolve_host_or_addr(addr, address_family)
+#else
+# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET)
+#endif
+
+extern unsigned int socket_timeout;
+extern unsigned int socket_timeout_state;
+extern int econn_refuse_state;
+extern int was_refused;
+extern int address_family;
+
+void socket_timeout_alarm_handler (int) __attribute__((noreturn));
+
+/* SSL-Related functionality */
+#ifdef HAVE_SSL
+# define MP_SSLv2 1
+# define MP_SSLv3 2
+# define MP_TLSv1 3
+# define MP_TLSv1_1 4
+# define MP_TLSv1_2 5
+# define MP_SSLv2_OR_NEWER 6
+# define MP_SSLv3_OR_NEWER 7
+# define MP_TLSv1_OR_NEWER 8
+# define MP_TLSv1_1_OR_NEWER 9
+# define MP_TLSv1_2_OR_NEWER 10
+/* maybe this could be merged with the above np_net_connect, via some flags */
+int np_net_ssl_init(int sd);
+int np_net_ssl_init_with_hostname(int sd, char *host_name);
+int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version);
+int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey);
+void np_net_ssl_cleanup();
+int np_net_ssl_write(const void *buf, int num);
+int np_net_ssl_read(void *buf, int num);
+int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
+#endif /* HAVE_SSL */
+
+#endif /* _NETUTILS_H_ */
diff --git a/plugins/picohttpparser/Makefile.am b/plugins/picohttpparser/Makefile.am
new file mode 100644
index 0000000..87e0531
--- /dev/null
+++ b/plugins/picohttpparser/Makefile.am
@@ -0,0 +1,3 @@
+noinst_LIBRARIES = libpicohttpparser.a
+
+libpicohttpparser_a_SOURCES = picohttpparser.c picohttpparser.h
diff --git a/plugins/picohttpparser/Makefile.in b/plugins/picohttpparser/Makefile.in
new file mode 100644
index 0000000..75fea6b
--- /dev/null
+++ b/plugins/picohttpparser/Makefile.in
@@ -0,0 +1,2026 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plugins/picohttpparser
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \
+ $(top_srcdir)/m4/np_mysqlclient.m4 \
+ $(top_srcdir)/m4/uriparser.m4 $(top_srcdir)/gl/m4/00gnulib.m4 \
+ $(top_srcdir)/gl/m4/__inline.m4 \
+ $(top_srcdir)/gl/m4/absolute-header.m4 \
+ $(top_srcdir)/gl/m4/af_alg.m4 $(top_srcdir)/gl/m4/alloca.m4 \
+ $(top_srcdir)/gl/m4/arpa_inet_h.m4 \
+ $(top_srcdir)/gl/m4/assert_h.m4 $(top_srcdir)/gl/m4/base64.m4 \
+ $(top_srcdir)/gl/m4/btowc.m4 \
+ $(top_srcdir)/gl/m4/builtin-expect.m4 \
+ $(top_srcdir)/gl/m4/byteswap.m4 $(top_srcdir)/gl/m4/c-bool.m4 \
+ $(top_srcdir)/gl/m4/calloc.m4 $(top_srcdir)/gl/m4/close.m4 \
+ $(top_srcdir)/gl/m4/codeset.m4 \
+ $(top_srcdir)/gl/m4/double-slash-root.m4 \
+ $(top_srcdir)/gl/m4/dup2.m4 $(top_srcdir)/gl/m4/eealloc.m4 \
+ $(top_srcdir)/gl/m4/environ.m4 $(top_srcdir)/gl/m4/errno_h.m4 \
+ $(top_srcdir)/gl/m4/error.m4 $(top_srcdir)/gl/m4/exponentd.m4 \
+ $(top_srcdir)/gl/m4/extensions.m4 \
+ $(top_srcdir)/gl/m4/extern-inline.m4 \
+ $(top_srcdir)/gl/m4/fcntl-o.m4 $(top_srcdir)/gl/m4/fcntl.m4 \
+ $(top_srcdir)/gl/m4/fcntl_h.m4 $(top_srcdir)/gl/m4/fflush.m4 \
+ $(top_srcdir)/gl/m4/float_h.m4 $(top_srcdir)/gl/m4/floorf.m4 \
+ $(top_srcdir)/gl/m4/fopen.m4 $(top_srcdir)/gl/m4/fpurge.m4 \
+ $(top_srcdir)/gl/m4/freading.m4 $(top_srcdir)/gl/m4/free.m4 \
+ $(top_srcdir)/gl/m4/fseek.m4 $(top_srcdir)/gl/m4/fseeko.m4 \
+ $(top_srcdir)/gl/m4/fstat.m4 $(top_srcdir)/gl/m4/fstypename.m4 \
+ $(top_srcdir)/gl/m4/fsusage.m4 $(top_srcdir)/gl/m4/ftell.m4 \
+ $(top_srcdir)/gl/m4/ftello.m4 \
+ $(top_srcdir)/gl/m4/getaddrinfo.m4 \
+ $(top_srcdir)/gl/m4/getdelim.m4 \
+ $(top_srcdir)/gl/m4/getdtablesize.m4 \
+ $(top_srcdir)/gl/m4/gethostname.m4 \
+ $(top_srcdir)/gl/m4/getline.m4 \
+ $(top_srcdir)/gl/m4/getloadavg.m4 \
+ $(top_srcdir)/gl/m4/getopt.m4 \
+ $(top_srcdir)/gl/m4/getprogname.m4 \
+ $(top_srcdir)/gl/m4/gl-openssl.m4 \
+ $(top_srcdir)/gl/m4/gnulib-common.m4 \
+ $(top_srcdir)/gl/m4/gnulib-comp.m4 \
+ $(top_srcdir)/gl/m4/hostent.m4 $(top_srcdir)/gl/m4/idpriv.m4 \
+ $(top_srcdir)/gl/m4/include_next.m4 \
+ $(top_srcdir)/gl/m4/inet_ntop.m4 \
+ $(top_srcdir)/gl/m4/intmax_t.m4 \
+ $(top_srcdir)/gl/m4/inttypes.m4 \
+ $(top_srcdir)/gl/m4/inttypes_h.m4 \
+ $(top_srcdir)/gl/m4/langinfo_h.m4 \
+ $(top_srcdir)/gl/m4/largefile.m4 \
+ $(top_srcdir)/gl/m4/libtool.m4 $(top_srcdir)/gl/m4/limits-h.m4 \
+ $(top_srcdir)/gl/m4/localcharset.m4 \
+ $(top_srcdir)/gl/m4/locale-fr.m4 \
+ $(top_srcdir)/gl/m4/locale-ja.m4 \
+ $(top_srcdir)/gl/m4/locale-zh.m4 \
+ $(top_srcdir)/gl/m4/locale_h.m4 \
+ $(top_srcdir)/gl/m4/localeconv.m4 $(top_srcdir)/gl/m4/lock.m4 \
+ $(top_srcdir)/gl/m4/lseek.m4 $(top_srcdir)/gl/m4/ltoptions.m4 \
+ $(top_srcdir)/gl/m4/ltsugar.m4 \
+ $(top_srcdir)/gl/m4/ltversion.m4 \
+ $(top_srcdir)/gl/m4/lt~obsolete.m4 \
+ $(top_srcdir)/gl/m4/malloc.m4 $(top_srcdir)/gl/m4/malloca.m4 \
+ $(top_srcdir)/gl/m4/math_h.m4 $(top_srcdir)/gl/m4/mbrtowc.m4 \
+ $(top_srcdir)/gl/m4/mbsinit.m4 \
+ $(top_srcdir)/gl/m4/mbstate_t.m4 $(top_srcdir)/gl/m4/mbtowc.m4 \
+ $(top_srcdir)/gl/m4/memchr.m4 $(top_srcdir)/gl/m4/minmax.m4 \
+ $(top_srcdir)/gl/m4/mktime.m4 $(top_srcdir)/gl/m4/mmap-anon.m4 \
+ $(top_srcdir)/gl/m4/mode_t.m4 $(top_srcdir)/gl/m4/mountlist.m4 \
+ $(top_srcdir)/gl/m4/msvc-inval.m4 \
+ $(top_srcdir)/gl/m4/msvc-nothrow.m4 \
+ $(top_srcdir)/gl/m4/multiarch.m4 \
+ $(top_srcdir)/gl/m4/netdb_h.m4 \
+ $(top_srcdir)/gl/m4/netinet_in_h.m4 \
+ $(top_srcdir)/gl/m4/nl_langinfo.m4 \
+ $(top_srcdir)/gl/m4/nocrash.m4 $(top_srcdir)/gl/m4/off_t.m4 \
+ $(top_srcdir)/gl/m4/open-cloexec.m4 \
+ $(top_srcdir)/gl/m4/open-slash.m4 $(top_srcdir)/gl/m4/open.m4 \
+ $(top_srcdir)/gl/m4/pathmax.m4 $(top_srcdir)/gl/m4/pid_t.m4 \
+ $(top_srcdir)/gl/m4/printf.m4 \
+ $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \
+ $(top_srcdir)/gl/m4/realloc.m4 \
+ $(top_srcdir)/gl/m4/reallocarray.m4 \
+ $(top_srcdir)/gl/m4/regex.m4 $(top_srcdir)/gl/m4/servent.m4 \
+ $(top_srcdir)/gl/m4/setenv.m4 \
+ $(top_srcdir)/gl/m4/setlocale_null.m4 \
+ $(top_srcdir)/gl/m4/sha256.m4 $(top_srcdir)/gl/m4/size_max.m4 \
+ $(top_srcdir)/gl/m4/snprintf.m4 \
+ $(top_srcdir)/gl/m4/socketlib.m4 \
+ $(top_srcdir)/gl/m4/sockets.m4 $(top_srcdir)/gl/m4/socklen.m4 \
+ $(top_srcdir)/gl/m4/sockpfaf.m4 $(top_srcdir)/gl/m4/ssize_t.m4 \
+ $(top_srcdir)/gl/m4/stat-time.m4 $(top_srcdir)/gl/m4/stat.m4 \
+ $(top_srcdir)/gl/m4/std-gnu11.m4 \
+ $(top_srcdir)/gl/m4/stdalign.m4 \
+ $(top_srcdir)/gl/m4/stddef_h.m4 $(top_srcdir)/gl/m4/stdint.m4 \
+ $(top_srcdir)/gl/m4/stdint_h.m4 $(top_srcdir)/gl/m4/stdio_h.m4 \
+ $(top_srcdir)/gl/m4/stdlib_h.m4 $(top_srcdir)/gl/m4/strcase.m4 \
+ $(top_srcdir)/gl/m4/strcasestr.m4 \
+ $(top_srcdir)/gl/m4/strerror.m4 \
+ $(top_srcdir)/gl/m4/string_h.m4 \
+ $(top_srcdir)/gl/m4/strings_h.m4 $(top_srcdir)/gl/m4/strsep.m4 \
+ $(top_srcdir)/gl/m4/strstr.m4 \
+ $(top_srcdir)/gl/m4/sys_socket_h.m4 \
+ $(top_srcdir)/gl/m4/sys_stat_h.m4 \
+ $(top_srcdir)/gl/m4/sys_types_h.m4 \
+ $(top_srcdir)/gl/m4/sys_uio_h.m4 \
+ $(top_srcdir)/gl/m4/threadlib.m4 $(top_srcdir)/gl/m4/time_h.m4 \
+ $(top_srcdir)/gl/m4/time_r.m4 $(top_srcdir)/gl/m4/timegm.m4 \
+ $(top_srcdir)/gl/m4/ungetc.m4 $(top_srcdir)/gl/m4/unistd_h.m4 \
+ $(top_srcdir)/gl/m4/unlocked-io.m4 \
+ $(top_srcdir)/gl/m4/vararrays.m4 \
+ $(top_srcdir)/gl/m4/vasnprintf.m4 \
+ $(top_srcdir)/gl/m4/vasprintf.m4 \
+ $(top_srcdir)/gl/m4/visibility.m4 \
+ $(top_srcdir)/gl/m4/vsnprintf.m4 \
+ $(top_srcdir)/gl/m4/warn-on-use.m4 \
+ $(top_srcdir)/gl/m4/wchar_h.m4 $(top_srcdir)/gl/m4/wchar_t.m4 \
+ $(top_srcdir)/gl/m4/wcrtomb.m4 $(top_srcdir)/gl/m4/wctype_h.m4 \
+ $(top_srcdir)/gl/m4/wint_t.m4 $(top_srcdir)/gl/m4/xalloc.m4 \
+ $(top_srcdir)/gl/m4/xsize.m4 $(top_srcdir)/gl/m4/zzgnulib.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libpicohttpparser_a_AR = $(AR) $(ARFLAGS)
+libpicohttpparser_a_LIBADD =
+am_libpicohttpparser_a_OBJECTS = picohttpparser.$(OBJEXT)
+libpicohttpparser_a_OBJECTS = $(am_libpicohttpparser_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/picohttpparser.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libpicohttpparser_a_SOURCES)
+DIST_SOURCES = $(libpicohttpparser_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp \
+ $(top_srcdir)/build-aux/mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+ASSERT_H = @ASSERT_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASENAME = @BASENAME@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+BYTESWAP_H = @BYTESWAP_H@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBILIBS = @DBILIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPLIBS = @DEPLIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+EXEEXT = @EXEEXT@
+EXTRAS = @EXTRAS@
+EXTRAS_ROOT = @EXTRAS_ROOT@
+EXTRA_NETOBJS = @EXTRA_NETOBJS@
+EXTRA_TEST = @EXTRA_TEST@
+FGREP = @FGREP@
+FLOAT_H = @FLOAT_H@
+FLOORF_LIBM = @FLOORF_LIBM@
+GETADDRINFO_LIB = @GETADDRINFO_LIB@
+GETHOSTNAME_LIB = @GETHOSTNAME_LIB@
+GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
+GETOPT_CDEFS_H = @GETOPT_CDEFS_H@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@
+GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@
+GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@
+GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ACOSF = @GL_GNULIB_ACOSF@
+GL_GNULIB_ACOSL = @GL_GNULIB_ACOSL@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ASINF = @GL_GNULIB_ASINF@
+GL_GNULIB_ASINL = @GL_GNULIB_ASINL@
+GL_GNULIB_ATAN2F = @GL_GNULIB_ATAN2F@
+GL_GNULIB_ATANF = @GL_GNULIB_ATANF@
+GL_GNULIB_ATANL = @GL_GNULIB_ATANL@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_BIND = @GL_GNULIB_BIND@
+GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@
+GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CBRT = @GL_GNULIB_CBRT@
+GL_GNULIB_CBRTF = @GL_GNULIB_CBRTF@
+GL_GNULIB_CBRTL = @GL_GNULIB_CBRTL@
+GL_GNULIB_CEIL = @GL_GNULIB_CEIL@
+GL_GNULIB_CEILF = @GL_GNULIB_CEILF@
+GL_GNULIB_CEILL = @GL_GNULIB_CEILL@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@
+GL_GNULIB_COPYSIGN = @GL_GNULIB_COPYSIGN@
+GL_GNULIB_COPYSIGNF = @GL_GNULIB_COPYSIGNF@
+GL_GNULIB_COPYSIGNL = @GL_GNULIB_COPYSIGNL@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_COSF = @GL_GNULIB_COSF@
+GL_GNULIB_COSHF = @GL_GNULIB_COSHF@
+GL_GNULIB_COSL = @GL_GNULIB_COSL@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXP2 = @GL_GNULIB_EXP2@
+GL_GNULIB_EXP2F = @GL_GNULIB_EXP2F@
+GL_GNULIB_EXP2L = @GL_GNULIB_EXP2L@
+GL_GNULIB_EXPF = @GL_GNULIB_EXPF@
+GL_GNULIB_EXPL = @GL_GNULIB_EXPL@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_EXPM1 = @GL_GNULIB_EXPM1@
+GL_GNULIB_EXPM1F = @GL_GNULIB_EXPM1F@
+GL_GNULIB_EXPM1L = @GL_GNULIB_EXPM1L@
+GL_GNULIB_FABSF = @GL_GNULIB_FABSF@
+GL_GNULIB_FABSL = @GL_GNULIB_FABSL@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFS = @GL_GNULIB_FFS@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FLOOR = @GL_GNULIB_FLOOR@
+GL_GNULIB_FLOORF = @GL_GNULIB_FLOORF@
+GL_GNULIB_FLOORL = @GL_GNULIB_FLOORL@
+GL_GNULIB_FMA = @GL_GNULIB_FMA@
+GL_GNULIB_FMAF = @GL_GNULIB_FMAF@
+GL_GNULIB_FMAL = @GL_GNULIB_FMAL@
+GL_GNULIB_FMOD = @GL_GNULIB_FMOD@
+GL_GNULIB_FMODF = @GL_GNULIB_FMODF@
+GL_GNULIB_FMODL = @GL_GNULIB_FMODL@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FREXP = @GL_GNULIB_FREXP@
+GL_GNULIB_FREXPF = @GL_GNULIB_FREXPF@
+GL_GNULIB_FREXPL = @GL_GNULIB_FREXPL@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETADDRINFO = @GL_GNULIB_GETADDRINFO@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@
+GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@
+GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@
+GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_HYPOT = @GL_GNULIB_HYPOT@
+GL_GNULIB_HYPOTF = @GL_GNULIB_HYPOTF@
+GL_GNULIB_HYPOTL = @GL_GNULIB_HYPOTL@
+GL_GNULIB_ILOGB = @GL_GNULIB_ILOGB@
+GL_GNULIB_ILOGBF = @GL_GNULIB_ILOGBF@
+GL_GNULIB_ILOGBL = @GL_GNULIB_ILOGBL@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_INET_NTOP = @GL_GNULIB_INET_NTOP@
+GL_GNULIB_INET_PTON = @GL_GNULIB_INET_PTON@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_ISFINITE = @GL_GNULIB_ISFINITE@
+GL_GNULIB_ISINF = @GL_GNULIB_ISINF@
+GL_GNULIB_ISNAN = @GL_GNULIB_ISNAN@
+GL_GNULIB_ISNAND = @GL_GNULIB_ISNAND@
+GL_GNULIB_ISNANF = @GL_GNULIB_ISNANF@
+GL_GNULIB_ISNANL = @GL_GNULIB_ISNANL@
+GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@
+GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@
+GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@
+GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LDEXPF = @GL_GNULIB_LDEXPF@
+GL_GNULIB_LDEXPL = @GL_GNULIB_LDEXPL@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@
+GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@
+GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LOG = @GL_GNULIB_LOG@
+GL_GNULIB_LOG10 = @GL_GNULIB_LOG10@
+GL_GNULIB_LOG10F = @GL_GNULIB_LOG10F@
+GL_GNULIB_LOG10L = @GL_GNULIB_LOG10L@
+GL_GNULIB_LOG1P = @GL_GNULIB_LOG1P@
+GL_GNULIB_LOG1PF = @GL_GNULIB_LOG1PF@
+GL_GNULIB_LOG1PL = @GL_GNULIB_LOG1PL@
+GL_GNULIB_LOG2 = @GL_GNULIB_LOG2@
+GL_GNULIB_LOG2F = @GL_GNULIB_LOG2F@
+GL_GNULIB_LOG2L = @GL_GNULIB_LOG2L@
+GL_GNULIB_LOGB = @GL_GNULIB_LOGB@
+GL_GNULIB_LOGBF = @GL_GNULIB_LOGBF@
+GL_GNULIB_LOGBL = @GL_GNULIB_LOGBL@
+GL_GNULIB_LOGF = @GL_GNULIB_LOGF@
+GL_GNULIB_LOGL = @GL_GNULIB_LOGL@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@
+GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_J0 = @GL_GNULIB_MDA_J0@
+GL_GNULIB_MDA_J1 = @GL_GNULIB_MDA_J1@
+GL_GNULIB_MDA_JN = @GL_GNULIB_MDA_JN@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MDA_Y0 = @GL_GNULIB_MDA_Y0@
+GL_GNULIB_MDA_Y1 = @GL_GNULIB_MDA_Y1@
+GL_GNULIB_MDA_YN = @GL_GNULIB_MDA_YN@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_MODF = @GL_GNULIB_MODF@
+GL_GNULIB_MODFF = @GL_GNULIB_MODFF@
+GL_GNULIB_MODFL = @GL_GNULIB_MODFL@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_POWF = @GL_GNULIB_POWF@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_RECV = @GL_GNULIB_RECV@
+GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@
+GL_GNULIB_REMAINDER = @GL_GNULIB_REMAINDER@
+GL_GNULIB_REMAINDERF = @GL_GNULIB_REMAINDERF@
+GL_GNULIB_REMAINDERL = @GL_GNULIB_REMAINDERL@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_RINT = @GL_GNULIB_RINT@
+GL_GNULIB_RINTF = @GL_GNULIB_RINTF@
+GL_GNULIB_RINTL = @GL_GNULIB_RINTL@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_ROUND = @GL_GNULIB_ROUND@
+GL_GNULIB_ROUNDF = @GL_GNULIB_ROUNDF@
+GL_GNULIB_ROUNDL = @GL_GNULIB_ROUNDL@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SEND = @GL_GNULIB_SEND@
+GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@
+GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@
+GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@
+GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SIGNBIT = @GL_GNULIB_SIGNBIT@
+GL_GNULIB_SINF = @GL_GNULIB_SINF@
+GL_GNULIB_SINHF = @GL_GNULIB_SINHF@
+GL_GNULIB_SINL = @GL_GNULIB_SINL@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_SQRTF = @GL_GNULIB_SQRTF@
+GL_GNULIB_SQRTL = @GL_GNULIB_SQRTL@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TANF = @GL_GNULIB_TANF@
+GL_GNULIB_TANHF = @GL_GNULIB_TANHF@
+GL_GNULIB_TANL = @GL_GNULIB_TANL@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@
+GL_GNULIB_TRUNC = @GL_GNULIB_TRUNC@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TRUNCF = @GL_GNULIB_TRUNCF@
+GL_GNULIB_TRUNCL = @GL_GNULIB_TRUNCL@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@
+GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@
+GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@
+GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@
+GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@
+GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@
+GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@
+GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@
+GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@
+GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@
+GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@
+GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@
+GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@
+GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@
+GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@
+GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@
+GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@
+GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@
+GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@
+GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@
+GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@
+GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@
+GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@
+GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@
+GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@
+GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@
+GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@
+GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@
+GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@
+GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@
+GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@
+GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@
+GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@
+GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@
+GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@
+GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GREP = @GREP@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ACOSF = @HAVE_ACOSF@
+HAVE_ACOSL = @HAVE_ACOSL@
+HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ASINF = @HAVE_ASINF@
+HAVE_ASINL = @HAVE_ASINL@
+HAVE_ATAN2F = @HAVE_ATAN2F@
+HAVE_ATANF = @HAVE_ATANF@
+HAVE_ATANL = @HAVE_ATANL@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CBRT = @HAVE_CBRT@
+HAVE_CBRTF = @HAVE_CBRTF@
+HAVE_CBRTL = @HAVE_CBRTL@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_COPYSIGN = @HAVE_COPYSIGN@
+HAVE_COPYSIGNL = @HAVE_COPYSIGNL@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_COSF = @HAVE_COSF@
+HAVE_COSHF = @HAVE_COSHF@
+HAVE_COSL = @HAVE_COSL@
+HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
+HAVE_DECL_ACOSL = @HAVE_DECL_ACOSL@
+HAVE_DECL_ASINL = @HAVE_DECL_ASINL@
+HAVE_DECL_ATANL = @HAVE_DECL_ATANL@
+HAVE_DECL_CBRTF = @HAVE_DECL_CBRTF@
+HAVE_DECL_CBRTL = @HAVE_DECL_CBRTL@
+HAVE_DECL_CEILF = @HAVE_DECL_CEILF@
+HAVE_DECL_CEILL = @HAVE_DECL_CEILL@
+HAVE_DECL_COPYSIGNF = @HAVE_DECL_COPYSIGNF@
+HAVE_DECL_COSL = @HAVE_DECL_COSL@
+HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@
+HAVE_DECL_EXP2 = @HAVE_DECL_EXP2@
+HAVE_DECL_EXP2F = @HAVE_DECL_EXP2F@
+HAVE_DECL_EXP2L = @HAVE_DECL_EXP2L@
+HAVE_DECL_EXPL = @HAVE_DECL_EXPL@
+HAVE_DECL_EXPM1L = @HAVE_DECL_EXPM1L@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@
+HAVE_DECL_FCVT = @HAVE_DECL_FCVT@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+HAVE_DECL_FLOORF = @HAVE_DECL_FLOORF@
+HAVE_DECL_FLOORL = @HAVE_DECL_FLOORL@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_FREEADDRINFO = @HAVE_DECL_FREEADDRINFO@
+HAVE_DECL_FREXPL = @HAVE_DECL_FREXPL@
+HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@
+HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@
+HAVE_DECL_GAI_STRERROR = @HAVE_DECL_GAI_STRERROR@
+HAVE_DECL_GCVT = @HAVE_DECL_GCVT@
+HAVE_DECL_GETADDRINFO = @HAVE_DECL_GETADDRINFO@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_GETNAMEINFO = @HAVE_DECL_GETNAMEINFO@
+HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@
+HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@
+HAVE_DECL_LDEXPL = @HAVE_DECL_LDEXPL@
+HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@
+HAVE_DECL_LOG10L = @HAVE_DECL_LOG10L@
+HAVE_DECL_LOG2 = @HAVE_DECL_LOG2@
+HAVE_DECL_LOG2F = @HAVE_DECL_LOG2F@
+HAVE_DECL_LOG2L = @HAVE_DECL_LOG2L@
+HAVE_DECL_LOGB = @HAVE_DECL_LOGB@
+HAVE_DECL_LOGL = @HAVE_DECL_LOGL@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_REMAINDER = @HAVE_DECL_REMAINDER@
+HAVE_DECL_REMAINDERL = @HAVE_DECL_REMAINDERL@
+HAVE_DECL_RINTF = @HAVE_DECL_RINTF@
+HAVE_DECL_ROUND = @HAVE_DECL_ROUND@
+HAVE_DECL_ROUNDF = @HAVE_DECL_ROUNDF@
+HAVE_DECL_ROUNDL = @HAVE_DECL_ROUNDL@
+HAVE_DECL_SETENV = @HAVE_DECL_SETENV@
+HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@
+HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@
+HAVE_DECL_SINL = @HAVE_DECL_SINL@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_SQRTL = @HAVE_DECL_SQRTL@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@
+HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_TANL = @HAVE_DECL_TANL@
+HAVE_DECL_TRUNC = @HAVE_DECL_TRUNC@
+HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@
+HAVE_DECL_TRUNCF = @HAVE_DECL_TRUNCF@
+HAVE_DECL_TRUNCL = @HAVE_DECL_TRUNCL@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCSDUP = @HAVE_DECL_WCSDUP@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_EXECVPE = @HAVE_EXECVPE@
+HAVE_EXPF = @HAVE_EXPF@
+HAVE_EXPL = @HAVE_EXPL@
+HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@
+HAVE_EXPM1 = @HAVE_EXPM1@
+HAVE_EXPM1F = @HAVE_EXPM1F@
+HAVE_FABSF = @HAVE_FABSF@
+HAVE_FABSL = @HAVE_FABSL@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHDIR = @HAVE_FCHDIR@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDATASYNC = @HAVE_FDATASYNC@
+HAVE_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFS = @HAVE_FFS@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+HAVE_FMA = @HAVE_FMA@
+HAVE_FMAF = @HAVE_FMAF@
+HAVE_FMAL = @HAVE_FMAL@
+HAVE_FMODF = @HAVE_FMODF@
+HAVE_FMODL = @HAVE_FMODL@
+HAVE_FREELOCALE = @HAVE_FREELOCALE@
+HAVE_FREXPF = @HAVE_FREXPF@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETENTROPY = @HAVE_GETENTROPY@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETPASS = @HAVE_GETPASS@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETUMASK = @HAVE_GETUMASK@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_HYPOTF = @HAVE_HYPOTF@
+HAVE_HYPOTL = @HAVE_HYPOTL@
+HAVE_ILOGB = @HAVE_ILOGB@
+HAVE_ILOGBF = @HAVE_ILOGBF@
+HAVE_ILOGBL = @HAVE_ILOGBL@
+HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@
+HAVE_INITSTATE = @HAVE_INITSTATE@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISNAND = @HAVE_ISNAND@
+HAVE_ISNANF = @HAVE_ISNANF@
+HAVE_ISNANL = @HAVE_ISNANL@
+HAVE_ISWBLANK = @HAVE_ISWBLANK@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@
+HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@
+HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@
+HAVE_LANGINFO_H = @HAVE_LANGINFO_H@
+HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@
+HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LDEXPF = @HAVE_LDEXPF@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LOG10F = @HAVE_LOG10F@
+HAVE_LOG10L = @HAVE_LOG10L@
+HAVE_LOG1P = @HAVE_LOG1P@
+HAVE_LOG1PF = @HAVE_LOG1PF@
+HAVE_LOG1PL = @HAVE_LOG1PL@
+HAVE_LOGBF = @HAVE_LOGBF@
+HAVE_LOGBL = @HAVE_LOGBL@
+HAVE_LOGF = @HAVE_LOGF@
+HAVE_LOGL = @HAVE_LOGL@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMP = @HAVE_MKSTEMP@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_MODFF = @HAVE_MODFF@
+HAVE_MODFL = @HAVE_MODFL@
+HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@
+HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NETDB_H = @HAVE_NETDB_H@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+HAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@
+HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@
+HAVE_POWF = @HAVE_POWF@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_PTSNAME = @HAVE_PTSNAME@
+HAVE_PTSNAME_R = @HAVE_PTSNAME_R@
+HAVE_PWRITE = @HAVE_PWRITE@
+HAVE_QSORT_R = @HAVE_QSORT_R@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_REMAINDER = @HAVE_REMAINDER@
+HAVE_REMAINDERF = @HAVE_REMAINDERF@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RINT = @HAVE_RINT@
+HAVE_RINTL = @HAVE_RINTL@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
+HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@
+HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SINF = @HAVE_SINF@
+HAVE_SINHF = @HAVE_SINHF@
+HAVE_SINL = @HAVE_SINL@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_SQRTF = @HAVE_SQRTF@
+HAVE_SQRTL = @HAVE_SQRTL@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASECMP = @HAVE_STRCASECMP@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@
+HAVE_STRINGS_H = @HAVE_STRINGS_H@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
+HAVE_STRTOLD = @HAVE_STRTOLD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_ADDRINFO = @HAVE_STRUCT_ADDRINFO@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@
+HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@
+HAVE_TANF = @HAVE_TANF@
+HAVE_TANHF = @HAVE_TANHF@
+HAVE_TANL = @HAVE_TANL@
+HAVE_TIMEGM = @HAVE_TIMEGM@
+HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@
+HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@
+HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNLOCKPT = @HAVE_UNLOCKPT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCPCPY = @HAVE_WCPCPY@
+HAVE_WCPNCPY = @HAVE_WCPNCPY@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSCASECMP = @HAVE_WCSCASECMP@
+HAVE_WCSCAT = @HAVE_WCSCAT@
+HAVE_WCSCHR = @HAVE_WCSCHR@
+HAVE_WCSCMP = @HAVE_WCSCMP@
+HAVE_WCSCOLL = @HAVE_WCSCOLL@
+HAVE_WCSCPY = @HAVE_WCSCPY@
+HAVE_WCSCSPN = @HAVE_WCSCSPN@
+HAVE_WCSDUP = @HAVE_WCSDUP@
+HAVE_WCSFTIME = @HAVE_WCSFTIME@
+HAVE_WCSLEN = @HAVE_WCSLEN@
+HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@
+HAVE_WCSNCAT = @HAVE_WCSNCAT@
+HAVE_WCSNCMP = @HAVE_WCSNCMP@
+HAVE_WCSNCPY = @HAVE_WCSNCPY@
+HAVE_WCSNLEN = @HAVE_WCSNLEN@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSPBRK = @HAVE_WCSPBRK@
+HAVE_WCSRCHR = @HAVE_WCSRCHR@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCSSPN = @HAVE_WCSSPN@
+HAVE_WCSSTR = @HAVE_WCSSTR@
+HAVE_WCSTOK = @HAVE_WCSTOK@
+HAVE_WCSWIDTH = @HAVE_WCSWIDTH@
+HAVE_WCSXFRM = @HAVE_WCSXFRM@
+HAVE_WCTRANS_T = @HAVE_WCTRANS_T@
+HAVE_WCTYPE_H = @HAVE_WCTYPE_H@
+HAVE_WCTYPE_T = @HAVE_WCTYPE_T@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE_WMEMCHR = @HAVE_WMEMCHR@
+HAVE_WMEMCMP = @HAVE_WMEMCMP@
+HAVE_WMEMCPY = @HAVE_WMEMCPY@
+HAVE_WMEMMOVE = @HAVE_WMEMMOVE@
+HAVE_WMEMPCPY = @HAVE_WMEMPCPY@
+HAVE_WMEMSET = @HAVE_WMEMSET@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE_XLOCALE_H = @HAVE_XLOCALE_H@
+HAVE__EXIT = @HAVE__EXIT@
+HOSTENT_LIB = @HOSTENT_LIB@
+HOSTNAME = @HOSTNAME@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INET_NTOP_LIB = @INET_NTOP_LIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KRBINCLUDE = @KRBINCLUDE@
+LD = @LD@
+LDAPINCLUDE = @LDAPINCLUDE@
+LDAPLIBS = @LDAPLIBS@
+LDFLAGS = @LDFLAGS@
+LIBCURL = @LIBCURL@
+LIBCURLCFLAGS = @LIBCURLCFLAGS@
+LIBCURLINCLUDE = @LIBCURLINCLUDE@
+LIBCURLLIBS = @LIBCURLLIBS@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@
+LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPMULTITHREAD = @LIBPMULTITHREAD@
+LIBPTHREAD = @LIBPTHREAD@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSTDTHREAD = @LIBSTDTHREAD@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIB_CRYPTO = @LIB_CRYPTO@
+LIB_HARD_LOCALE = @LIB_HARD_LOCALE@
+LIB_MBRTOWC = @LIB_MBRTOWC@
+LIB_NL_LANGINFO = @LIB_NL_LANGINFO@
+LIB_SCHED_YIELD = @LIB_SCHED_YIELD@
+LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@
+LIMITS_H = @LIMITS_H@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@
+LOCALE_FR = @LOCALE_FR@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATHLIBS = @MATHLIBS@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGMERGE = @MSGMERGE@
+MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@
+MYSQLCFLAGS = @MYSQLCFLAGS@
+MYSQLINCLUDE = @MYSQLINCLUDE@
+MYSQLLIBS = @MYSQLLIBS@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@
+NEXT_ASSERT_H = @NEXT_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_ASSERT_H = @NEXT_AS_FIRST_DIRECTIVE_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@
+NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@
+NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
+NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@
+NEXT_AS_FIRST_DIRECTIVE_MATH_H = @NEXT_AS_FIRST_DIRECTIVE_MATH_H@
+NEXT_AS_FIRST_DIRECTIVE_NETDB_H = @NEXT_AS_FIRST_DIRECTIVE_NETDB_H@
+NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_H@
+NEXT_LIMITS_H = @NEXT_LIMITS_H@
+NEXT_LOCALE_H = @NEXT_LOCALE_H@
+NEXT_MATH_H = @NEXT_MATH_H@
+NEXT_NETDB_H = @NEXT_NETDB_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRINGS_H = @NEXT_STRINGS_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@
+NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NEXT_WCTYPE_H = @NEXT_WCTYPE_H@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NP_RELEASE = @NP_RELEASE@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PATH_TO_APTGET = @PATH_TO_APTGET@
+PATH_TO_DIG = @PATH_TO_DIG@
+PATH_TO_ENV = @PATH_TO_ENV@
+PATH_TO_FPING = @PATH_TO_FPING@
+PATH_TO_FPING6 = @PATH_TO_FPING6@
+PATH_TO_LMSTAT = @PATH_TO_LMSTAT@
+PATH_TO_LSPS = @PATH_TO_LSPS@
+PATH_TO_MAILQ = @PATH_TO_MAILQ@
+PATH_TO_NSLOOKUP = @PATH_TO_NSLOOKUP@
+PATH_TO_PING = @PATH_TO_PING@
+PATH_TO_PING6 = @PATH_TO_PING6@
+PATH_TO_PS = @PATH_TO_PS@
+PATH_TO_QMAIL_QSTAT = @PATH_TO_QMAIL_QSTAT@
+PATH_TO_QSTAT = @PATH_TO_QSTAT@
+PATH_TO_QUAKESTAT = @PATH_TO_QUAKESTAT@
+PATH_TO_RPCINFO = @PATH_TO_RPCINFO@
+PATH_TO_SMBCLIENT = @PATH_TO_SMBCLIENT@
+PATH_TO_SNMPGET = @PATH_TO_SNMPGET@
+PATH_TO_SNMPGETNEXT = @PATH_TO_SNMPGETNEXT@
+PATH_TO_SSH = @PATH_TO_SSH@
+PATH_TO_SUDO = @PATH_TO_SUDO@
+PATH_TO_SWAP = @PATH_TO_SWAP@
+PATH_TO_SWAPINFO = @PATH_TO_SWAPINFO@
+PATH_TO_UPTIME = @PATH_TO_UPTIME@
+PATH_TO_WHO = @PATH_TO_WHO@
+PERL = @PERL@
+PERLMODS_DIR = @PERLMODS_DIR@
+PGINCLUDE = @PGINCLUDE@
+PGLIBS = @PGLIBS@
+PKGCONFIG = @PKGCONFIG@
+PKG_ARCH = @PKG_ARCH@
+PLUGIN_TEST = @PLUGIN_TEST@
+POSUB = @POSUB@
+POW_LIB = @POW_LIB@
+PRAGMA_COLUMNS = @PRAGMA_COLUMNS@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PST3CFLAGS = @PST3CFLAGS@
+PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RADIUSLIBS = @RADIUSLIBS@
+RANLIB = @RANLIB@
+RELEASE = @RELEASE@
+REPLACE_ACCESS = @REPLACE_ACCESS@
+REPLACE_ACOSF = @REPLACE_ACOSF@
+REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
+REPLACE_ASINF = @REPLACE_ASINF@
+REPLACE_ATAN2F = @REPLACE_ATAN2F@
+REPLACE_ATANF = @REPLACE_ATANF@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@
+REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CBRTF = @REPLACE_CBRTF@
+REPLACE_CBRTL = @REPLACE_CBRTL@
+REPLACE_CEIL = @REPLACE_CEIL@
+REPLACE_CEILF = @REPLACE_CEILF@
+REPLACE_CEILL = @REPLACE_CEILL@
+REPLACE_CHMOD = @REPLACE_CHMOD@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@
+REPLACE_COSF = @REPLACE_COSF@
+REPLACE_COSHF = @REPLACE_COSHF@
+REPLACE_CREAT = @REPLACE_CREAT@
+REPLACE_CTIME = @REPLACE_CTIME@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_EXECL = @REPLACE_EXECL@
+REPLACE_EXECLE = @REPLACE_EXECLE@
+REPLACE_EXECLP = @REPLACE_EXECLP@
+REPLACE_EXECV = @REPLACE_EXECV@
+REPLACE_EXECVE = @REPLACE_EXECVE@
+REPLACE_EXECVP = @REPLACE_EXECVP@
+REPLACE_EXECVPE = @REPLACE_EXECVPE@
+REPLACE_EXP2 = @REPLACE_EXP2@
+REPLACE_EXP2L = @REPLACE_EXP2L@
+REPLACE_EXPF = @REPLACE_EXPF@
+REPLACE_EXPL = @REPLACE_EXPL@
+REPLACE_EXPM1 = @REPLACE_EXPM1@
+REPLACE_EXPM1F = @REPLACE_EXPM1F@
+REPLACE_EXPM1L = @REPLACE_EXPM1L@
+REPLACE_FABSL = @REPLACE_FABSL@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
+REPLACE_FCHMODAT = @REPLACE_FCHMODAT@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FFSLL = @REPLACE_FFSLL@
+REPLACE_FLOOR = @REPLACE_FLOOR@
+REPLACE_FLOORF = @REPLACE_FLOORF@
+REPLACE_FLOORL = @REPLACE_FLOORL@
+REPLACE_FMA = @REPLACE_FMA@
+REPLACE_FMAF = @REPLACE_FMAF@
+REPLACE_FMAL = @REPLACE_FMAL@
+REPLACE_FMOD = @REPLACE_FMOD@
+REPLACE_FMODF = @REPLACE_FMODF@
+REPLACE_FMODL = @REPLACE_FMODL@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREE = @REPLACE_FREE@
+REPLACE_FREELOCALE = @REPLACE_FREELOCALE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FREXP = @REPLACE_FREXP@
+REPLACE_FREXPF = @REPLACE_FREXPF@
+REPLACE_FREXPL = @REPLACE_FREXPL@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GAI_STRERROR = @REPLACE_GAI_STRERROR@
+REPLACE_GETADDRINFO = @REPLACE_GETADDRINFO@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@
+REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETPASS = @REPLACE_GETPASS@
+REPLACE_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@
+REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_HUGE_VAL = @REPLACE_HUGE_VAL@
+REPLACE_HYPOT = @REPLACE_HYPOT@
+REPLACE_HYPOTF = @REPLACE_HYPOTF@
+REPLACE_HYPOTL = @REPLACE_HYPOTL@
+REPLACE_ILOGB = @REPLACE_ILOGB@
+REPLACE_ILOGBF = @REPLACE_ILOGBF@
+REPLACE_ILOGBL = @REPLACE_ILOGBL@
+REPLACE_INET_NTOP = @REPLACE_INET_NTOP@
+REPLACE_INET_PTON = @REPLACE_INET_PTON@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ISFINITE = @REPLACE_ISFINITE@
+REPLACE_ISINF = @REPLACE_ISINF@
+REPLACE_ISNAN = @REPLACE_ISNAN@
+REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@
+REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@
+REPLACE_ITOLD = @REPLACE_ITOLD@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LDEXPL = @REPLACE_LDEXPL@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALECONV = @REPLACE_LOCALECONV@
+REPLACE_LOCALTIME = @REPLACE_LOCALTIME@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LOG = @REPLACE_LOG@
+REPLACE_LOG10 = @REPLACE_LOG10@
+REPLACE_LOG10F = @REPLACE_LOG10F@
+REPLACE_LOG10L = @REPLACE_LOG10L@
+REPLACE_LOG1P = @REPLACE_LOG1P@
+REPLACE_LOG1PF = @REPLACE_LOG1PF@
+REPLACE_LOG1PL = @REPLACE_LOG1PL@
+REPLACE_LOG2 = @REPLACE_LOG2@
+REPLACE_LOG2F = @REPLACE_LOG2F@
+REPLACE_LOG2L = @REPLACE_LOG2L@
+REPLACE_LOGB = @REPLACE_LOGB@
+REPLACE_LOGBF = @REPLACE_LOGBF@
+REPLACE_LOGBL = @REPLACE_LOGBL@
+REPLACE_LOGF = @REPLACE_LOGF@
+REPLACE_LOGL = @REPLACE_LOGL@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MALLOC_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@
+REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MBTOWC = @REPLACE_MBTOWC@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKNODAT = @REPLACE_MKNODAT@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_MODF = @REPLACE_MODF@
+REPLACE_MODFF = @REPLACE_MODFF@
+REPLACE_MODFL = @REPLACE_MODFL@
+REPLACE_NAN = @REPLACE_NAN@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@
+REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PTSNAME = @REPLACE_PTSNAME@
+REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_PWRITE = @REPLACE_PWRITE@
+REPLACE_QSORT_R = @REPLACE_QSORT_R@
+REPLACE_RANDOM = @REPLACE_RANDOM@
+REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
+REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@
+REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMAINDER = @REPLACE_REMAINDER@
+REPLACE_REMAINDERF = @REPLACE_REMAINDERF@
+REPLACE_REMAINDERL = @REPLACE_REMAINDERL@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RINTL = @REPLACE_RINTL@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_ROUND = @REPLACE_ROUND@
+REPLACE_ROUNDF = @REPLACE_ROUNDF@
+REPLACE_ROUNDL = @REPLACE_ROUNDL@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
+REPLACE_SIGNBIT = @REPLACE_SIGNBIT@
+REPLACE_SIGNBIT_USING_BUILTINS = @REPLACE_SIGNBIT_USING_BUILTINS@
+REPLACE_SINF = @REPLACE_SINF@
+REPLACE_SINHF = @REPLACE_SINHF@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_SQRTF = @REPLACE_SQRTF@
+REPLACE_SQRTL = @REPLACE_SQRTL@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STPNCPY = @REPLACE_STPNCPY@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@
+REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
+REPLACE_STRFTIME = @REPLACE_STRFTIME@
+REPLACE_STRNCAT = @REPLACE_STRNCAT@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRNLEN = @REPLACE_STRNLEN@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
+REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
+REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@
+REPLACE_TANF = @REPLACE_TANF@
+REPLACE_TANHF = @REPLACE_TANHF@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_TMPFILE = @REPLACE_TMPFILE@
+REPLACE_TOWLOWER = @REPLACE_TOWLOWER@
+REPLACE_TRUNC = @REPLACE_TRUNC@
+REPLACE_TRUNCATE = @REPLACE_TRUNCATE@
+REPLACE_TRUNCF = @REPLACE_TRUNCF@
+REPLACE_TRUNCL = @REPLACE_TRUNCL@
+REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_TZSET = @REPLACE_TZSET@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSFTIME = @REPLACE_WCSFTIME@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSTOK = @REPLACE_WCSTOK@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+REV_DATESTAMP = @REV_DATESTAMP@
+REV_TIMESTAMP = @REV_TIMESTAMP@
+SCRIPT_TEST = @SCRIPT_TEST@
+SED = @SED@
+SERVENT_LIB = @SERVENT_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+SOCKETLIBS = @SOCKETLIBS@
+SSLINCLUDE = @SSLINCLUDE@
+SSLLIBS = @SSLLIBS@
+STDALIGN_H = @STDALIGN_H@
+STDCKDINT_H = @STDCKDINT_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SUPPORT = @SUPPORT@
+SYSTEMDINCLUDE = @SYSTEMDINCLUDE@
+SYSTEMDLIBS = @SYSTEMDLIBS@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@
+UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+URIPARSER = @URIPARSER@
+URIPARSERCFLAGS = @URIPARSERCFLAGS@
+URIPARSERINCLUDE = @URIPARSERINCLUDE@
+URIPARSERLIBS = @URIPARSERLIBS@
+URIPARSER_CPPFLAGS = @URIPARSER_CPPFLAGS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARRANTY = @WARRANTY@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@
+WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@
+WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@
+WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+WTSAPI32LIBS = @WTSAPI32LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+check_tcp_ssl = @check_tcp_ssl@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gl_LIBOBJDEPS = @gl_LIBOBJDEPS@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+gltests_WITNESS = @gltests_WITNESS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+np_mysql_config = @np_mysql_config@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+with_trusted_path = @with_trusted_path@
+noinst_LIBRARIES = libpicohttpparser.a
+libpicohttpparser_a_SOURCES = picohttpparser.c picohttpparser.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/picohttpparser/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/picohttpparser/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libpicohttpparser.a: $(libpicohttpparser_a_OBJECTS) $(libpicohttpparser_a_DEPENDENCIES) $(EXTRA_libpicohttpparser_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libpicohttpparser.a
+ $(AM_V_AR)$(libpicohttpparser_a_AR) libpicohttpparser.a $(libpicohttpparser_a_OBJECTS) $(libpicohttpparser_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libpicohttpparser.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/picohttpparser.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/picohttpparser.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/picohttpparser.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
new file mode 100644
index 0000000..d0bfac6
--- /dev/null
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
+ * Shigeo Mitsunari
+ *
+ * The software is licensed under either the MIT License (below) or the Perl
+ * license.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#ifdef __SSE4_2__
+#ifdef _MSC_VER
+#include <nmmintrin.h>
+#else
+#include <x86intrin.h>
+#endif
+#endif
+#include "picohttpparser.h"
+
+#if __GNUC__ >= 3
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifdef _MSC_VER
+#define ALIGNED(n) _declspec(align(n))
+#else
+#define ALIGNED(n) __attribute__((aligned(n)))
+#endif
+
+#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u)
+
+#define CHECK_EOF() \
+ if (buf == buf_end) { \
+ *ret = -2; \
+ return NULL; \
+ }
+
+#define EXPECT_CHAR_NO_CHECK(ch) \
+ if (*buf++ != ch) { \
+ *ret = -1; \
+ return NULL; \
+ }
+
+#define EXPECT_CHAR(ch) \
+ CHECK_EOF(); \
+ EXPECT_CHAR_NO_CHECK(ch);
+
+#define ADVANCE_TOKEN(tok, toklen) \
+ do { \
+ const char *tok_start = buf; \
+ static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \
+ int found2; \
+ buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \
+ if (!found2) { \
+ CHECK_EOF(); \
+ } \
+ while (1) { \
+ if (*buf == ' ') { \
+ break; \
+ } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
+ if ((unsigned char)*buf < '\040' || *buf == '\177') { \
+ *ret = -1; \
+ return NULL; \
+ } \
+ } \
+ ++buf; \
+ CHECK_EOF(); \
+ } \
+ tok = tok_start; \
+ toklen = buf - tok_start; \
+ } while (0)
+
+static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
+ "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
+ "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found)
+{
+ *found = 0;
+#if __SSE4_2__
+ if (likely(buf_end - buf >= 16)) {
+ __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges);
+
+ size_t left = (buf_end - buf) & ~15;
+ do {
+ __m128i b16 = _mm_loadu_si128((const __m128i *)buf);
+ int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
+ if (unlikely(r != 16)) {
+ buf += r;
+ *found = 1;
+ break;
+ }
+ buf += 16;
+ left -= 16;
+ } while (likely(left != 0));
+ }
+#else
+ /* suppress unused parameter warning */
+ (void)buf_end;
+ (void)ranges;
+ (void)ranges_size;
+#endif
+ return buf;
+}
+
+static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret)
+{
+ const char *token_start = buf;
+
+#ifdef __SSE4_2__
+ static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */
+ "\012\037" /* allow SP and up to but not including DEL */
+ "\177\177"; /* allow chars w. MSB set */
+ int found;
+ buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
+ if (found)
+ goto FOUND_CTL;
+#else
+ /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
+ while (likely(buf_end - buf >= 8)) {
+#define DOIT() \
+ do { \
+ if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
+ goto NonPrintable; \
+ ++buf; \
+ } while (0)
+ DOIT();
+ DOIT();
+ DOIT();
+ DOIT();
+ DOIT();
+ DOIT();
+ DOIT();
+ DOIT();
+#undef DOIT
+ continue;
+ NonPrintable:
+ if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
+ goto FOUND_CTL;
+ }
+ ++buf;
+ }
+#endif
+ for (;; ++buf) {
+ CHECK_EOF();
+ if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
+ if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
+ goto FOUND_CTL;
+ }
+ }
+ }
+FOUND_CTL:
+ if (likely(*buf == '\015')) {
+ ++buf;
+ EXPECT_CHAR('\012');
+ *token_len = buf - 2 - token_start;
+ } else if (*buf == '\012') {
+ *token_len = buf - token_start;
+ ++buf;
+ } else {
+ *ret = -1;
+ return NULL;
+ }
+ *token = token_start;
+
+ return buf;
+}
+
+static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret)
+{
+ int ret_cnt = 0;
+ buf = last_len < 3 ? buf : buf + last_len - 3;
+
+ while (1) {
+ CHECK_EOF();
+ if (*buf == '\015') {
+ ++buf;
+ CHECK_EOF();
+ EXPECT_CHAR('\012');
+ ++ret_cnt;
+ } else if (*buf == '\012') {
+ ++buf;
+ ++ret_cnt;
+ } else {
+ ++buf;
+ ret_cnt = 0;
+ }
+ if (ret_cnt == 2) {
+ return buf;
+ }
+ }
+
+ *ret = -2;
+ return NULL;
+}
+
+#define PARSE_INT(valp_, mul_) \
+ if (*buf < '0' || '9' < *buf) { \
+ buf++; \
+ *ret = -1; \
+ return NULL; \
+ } \
+ *(valp_) = (mul_) * (*buf++ - '0');
+
+#define PARSE_INT_3(valp_) \
+ do { \
+ int res_ = 0; \
+ PARSE_INT(&res_, 100) \
+ *valp_ = res_; \
+ PARSE_INT(&res_, 10) \
+ *valp_ += res_; \
+ PARSE_INT(&res_, 1) \
+ *valp_ += res_; \
+ } while (0)
+
+/* returned pointer is always within [buf, buf_end), or null */
+static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret)
+{
+ /* we want at least [HTTP/1.<two chars>] to try to parse */
+ if (buf_end - buf < 9) {
+ *ret = -2;
+ return NULL;
+ }
+ EXPECT_CHAR_NO_CHECK('H');
+ EXPECT_CHAR_NO_CHECK('T');
+ EXPECT_CHAR_NO_CHECK('T');
+ EXPECT_CHAR_NO_CHECK('P');
+ EXPECT_CHAR_NO_CHECK('/');
+ PARSE_INT(major_version, 1);
+ if (*major_version == 1) {
+ EXPECT_CHAR_NO_CHECK('.');
+ PARSE_INT(minor_version, 1);
+ } else {
+ *minor_version = 0;
+ }
+ return buf;
+}
+
+static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers,
+ size_t max_headers, int *ret)
+{
+ for (;; ++*num_headers) {
+ CHECK_EOF();
+ if (*buf == '\015') {
+ ++buf;
+ EXPECT_CHAR('\012');
+ break;
+ } else if (*buf == '\012') {
+ ++buf;
+ break;
+ }
+ if (*num_headers == max_headers) {
+ *ret = -1;
+ return NULL;
+ }
+ if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) {
+ /* parsing name, but do not discard SP before colon, see
+ * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
+ headers[*num_headers].name = buf;
+ static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */
+ "\"\"" /* 0x22 */
+ "()" /* 0x28,0x29 */
+ ",," /* 0x2c */
+ "//" /* 0x2f */
+ ":@" /* 0x3a-0x40 */
+ "[]" /* 0x5b-0x5d */
+ "{\377"; /* 0x7b-0xff */
+ int found;
+ buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
+ if (!found) {
+ CHECK_EOF();
+ }
+ while (1) {
+ if (*buf == ':') {
+ break;
+ } else if (!token_char_map[(unsigned char)*buf]) {
+ *ret = -1;
+ return NULL;
+ }
+ ++buf;
+ CHECK_EOF();
+ }
+ if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) {
+ *ret = -1;
+ return NULL;
+ }
+ ++buf;
+ for (;; ++buf) {
+ CHECK_EOF();
+ if (!(*buf == ' ' || *buf == '\t')) {
+ break;
+ }
+ }
+ } else {
+ headers[*num_headers].name = NULL;
+ headers[*num_headers].name_len = 0;
+ }
+ const char *value;
+ size_t value_len;
+ if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) {
+ return NULL;
+ }
+ /* remove trailing SPs and HTABs */
+ const char *value_end = value + value_len;
+ for (; value_end != value; --value_end) {
+ const char c = *(value_end - 1);
+ if (!(c == ' ' || c == '\t')) {
+ break;
+ }
+ }
+ headers[*num_headers].value = value;
+ headers[*num_headers].value_len = value_end - value;
+ }
+ return buf;
+}
+
+static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
+ size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers,
+ size_t max_headers, int *ret)
+{
+ /* skip first empty line (some clients add CRLF after POST content) */
+ CHECK_EOF();
+ if (*buf == '\015') {
+ ++buf;
+ EXPECT_CHAR('\012');
+ } else if (*buf == '\012') {
+ ++buf;
+ }
+
+ /* parse request line */
+ ADVANCE_TOKEN(*method, *method_len);
+ do {
+ ++buf;
+ } while (*buf == ' ');
+ ADVANCE_TOKEN(*path, *path_len);
+ do {
+ ++buf;
+ } while (*buf == ' ');
+ if (*method_len == 0 || *path_len == 0) {
+ *ret = -1;
+ return NULL;
+ }
+ if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
+ return NULL;
+ }
+ if (*buf == '\015') {
+ ++buf;
+ EXPECT_CHAR('\012');
+ } else if (*buf == '\012') {
+ ++buf;
+ } else {
+ *ret = -1;
+ return NULL;
+ }
+
+ return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
+}
+
+int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path,
+ size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len)
+{
+ const char *buf = buf_start, *buf_end = buf_start + len;
+ size_t max_headers = *num_headers;
+ int r;
+
+ *method = NULL;
+ *method_len = 0;
+ *path = NULL;
+ *path_len = 0;
+ *major_version = -1;
+ *minor_version = -1;
+ *num_headers = 0;
+
+ /* if last_len != 0, check if the request is complete (a fast countermeasure
+ against slowloris */
+ if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
+ return r;
+ }
+
+ if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, max_headers,
+ &r)) == NULL) {
+ return r;
+ }
+
+ return (int)(buf - buf_start);
+}
+
+static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, const char **msg,
+ size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret)
+{
+ /* parse "HTTP/1.x" */
+ if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
+ return NULL;
+ }
+ /* skip space */
+ if (*buf != ' ') {
+ *ret = -1;
+ return NULL;
+ }
+ do {
+ ++buf;
+ } while (*buf == ' ');
+ /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */
+ if (buf_end - buf < 4) {
+ *ret = -2;
+ return NULL;
+ }
+ PARSE_INT_3(status);
+
+ /* get message including preceding space */
+ if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) {
+ return NULL;
+ }
+ if (*msg_len == 0) {
+ /* ok */
+ } else if (**msg == ' ') {
+ /* remove preceding space */
+ do {
+ ++*msg;
+ --*msg_len;
+ } while (**msg == ' ');
+ } else {
+ /* garbage found after status code */
+ *ret = -1;
+ return NULL;
+ }
+
+ return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
+}
+
+int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len,
+ struct phr_header *headers, size_t *num_headers, size_t last_len)
+{
+ const char *buf = buf_start, *buf_end = buf + len;
+ size_t max_headers = *num_headers;
+ int r;
+
+ *major_version = -1;
+ *minor_version = -1;
+ *status = 0;
+ *msg = NULL;
+ *msg_len = 0;
+ *num_headers = 0;
+
+ /* if last_len != 0, check if the response is complete (a fast countermeasure
+ against slowloris */
+ if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
+ return r;
+ }
+
+ if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) {
+ return r;
+ }
+
+ return (int)(buf - buf_start);
+}
+
+int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len)
+{
+ const char *buf = buf_start, *buf_end = buf + len;
+ size_t max_headers = *num_headers;
+ int r;
+
+ *num_headers = 0;
+
+ /* if last_len != 0, check if the response is complete (a fast countermeasure
+ against slowloris */
+ if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
+ return r;
+ }
+
+ if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) {
+ return r;
+ }
+
+ return (int)(buf - buf_start);
+}
+
+enum {
+ CHUNKED_IN_CHUNK_SIZE,
+ CHUNKED_IN_CHUNK_EXT,
+ CHUNKED_IN_CHUNK_DATA,
+ CHUNKED_IN_CHUNK_CRLF,
+ CHUNKED_IN_TRAILERS_LINE_HEAD,
+ CHUNKED_IN_TRAILERS_LINE_MIDDLE
+};
+
+static int decode_hex(int ch)
+{
+ if ('0' <= ch && ch <= '9') {
+ return ch - '0';
+ } else if ('A' <= ch && ch <= 'F') {
+ return ch - 'A' + 0xa;
+ } else if ('a' <= ch && ch <= 'f') {
+ return ch - 'a' + 0xa;
+ } else {
+ return -1;
+ }
+}
+
+ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz)
+{
+ size_t dst = 0, src = 0, bufsz = *_bufsz;
+ ssize_t ret = -2; /* incomplete */
+
+ while (1) {
+ switch (decoder->_state) {
+ case CHUNKED_IN_CHUNK_SIZE:
+ for (;; ++src) {
+ int v;
+ if (src == bufsz)
+ goto Exit;
+ if ((v = decode_hex(buf[src])) == -1) {
+ if (decoder->_hex_count == 0) {
+ ret = -1;
+ goto Exit;
+ }
+ break;
+ }
+ if (decoder->_hex_count == sizeof(size_t) * 2) {
+ ret = -1;
+ goto Exit;
+ }
+ decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
+ ++decoder->_hex_count;
+ }
+ decoder->_hex_count = 0;
+ decoder->_state = CHUNKED_IN_CHUNK_EXT;
+ /* fallthru */
+ case CHUNKED_IN_CHUNK_EXT:
+ /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
+ for (;; ++src) {
+ if (src == bufsz)
+ goto Exit;
+ if (buf[src] == '\012')
+ break;
+ }
+ ++src;
+ if (decoder->bytes_left_in_chunk == 0) {
+ if (decoder->consume_trailer) {
+ decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
+ break;
+ } else {
+ goto Complete;
+ }
+ }
+ decoder->_state = CHUNKED_IN_CHUNK_DATA;
+ /* fallthru */
+ case CHUNKED_IN_CHUNK_DATA: {
+ size_t avail = bufsz - src;
+ if (avail < decoder->bytes_left_in_chunk) {
+ if (dst != src)
+ memmove(buf + dst, buf + src, avail);
+ src += avail;
+ dst += avail;
+ decoder->bytes_left_in_chunk -= avail;
+ goto Exit;
+ }
+ if (dst != src)
+ memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
+ src += decoder->bytes_left_in_chunk;
+ dst += decoder->bytes_left_in_chunk;
+ decoder->bytes_left_in_chunk = 0;
+ decoder->_state = CHUNKED_IN_CHUNK_CRLF;
+ }
+ /* fallthru */
+ case CHUNKED_IN_CHUNK_CRLF:
+ for (;; ++src) {
+ if (src == bufsz)
+ goto Exit;
+ if (buf[src] != '\015')
+ break;
+ }
+ if (buf[src] != '\012') {
+ ret = -1;
+ goto Exit;
+ }
+ ++src;
+ decoder->_state = CHUNKED_IN_CHUNK_SIZE;
+ break;
+ case CHUNKED_IN_TRAILERS_LINE_HEAD:
+ for (;; ++src) {
+ if (src == bufsz)
+ goto Exit;
+ if (buf[src] != '\015')
+ break;
+ }
+ if (buf[src++] == '\012')
+ goto Complete;
+ decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
+ /* fallthru */
+ case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
+ for (;; ++src) {
+ if (src == bufsz)
+ goto Exit;
+ if (buf[src] == '\012')
+ break;
+ }
+ ++src;
+ decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
+ break;
+ default:
+ assert(!"decoder is corrupt");
+ }
+ }
+
+Complete:
+ ret = bufsz - src;
+Exit:
+ if (dst != src)
+ memmove(buf + dst, buf + src, bufsz - src);
+ *_bufsz = dst;
+ return ret;
+}
+
+int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder)
+{
+ return decoder->_state == CHUNKED_IN_CHUNK_DATA;
+}
+
+#undef CHECK_EOF
+#undef EXPECT_CHAR
+#undef ADVANCE_TOKEN
diff --git a/plugins/picohttpparser/picohttpparser.h b/plugins/picohttpparser/picohttpparser.h
new file mode 100644
index 0000000..8f13b36
--- /dev/null
+++ b/plugins/picohttpparser/picohttpparser.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
+ * Shigeo Mitsunari
+ *
+ * The software is licensed under either the MIT License (below) or the Perl
+ * license.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef picohttpparser_h
+#define picohttpparser_h
+
+#include <sys/types.h>
+
+#ifdef _MSC_VER
+#define ssize_t intptr_t
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* contains name and value of a header (name == NULL if is a continuing line
+ * of a multiline header */
+struct phr_header {
+ const char *name;
+ size_t name_len;
+ const char *value;
+ size_t value_len;
+};
+
+/* returns number of bytes consumed if successful, -2 if request is partial,
+ * -1 if failed */
+int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len,
+ int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len);
+
+/* ditto */
+int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len,
+ struct phr_header *headers, size_t *num_headers, size_t last_len);
+
+/* ditto */
+int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len);
+
+/* should be zero-filled before start */
+struct phr_chunked_decoder {
+ size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
+ char consume_trailer; /* if trailing headers should be consumed */
+ char _hex_count;
+ char _state;
+};
+
+/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
+ * encoding headers. When the function returns without an error, bufsz is
+ * updated to the length of the decoded data available. Applications should
+ * repeatedly call the function while it returns -2 (incomplete) every time
+ * supplying newly arrived data. If the end of the chunked-encoded data is
+ * found, the function returns a non-negative number indicating the number of
+ * octets left undecoded at the tail of the supplied buffer. Returns -1 on
+ * error.
+ */
+ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz);
+
+/* returns if the chunked decoder is in middle of chunked data */
+int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/popen.c b/plugins/popen.c
new file mode 100644
index 0000000..036bc60
--- /dev/null
+++ b/plugins/popen.c
@@ -0,0 +1,294 @@
+/*****************************************************************************
+*
+* Monitoring Plugins popen
+*
+* License: GPL
+* Copyright (c) 2005-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* A safe alternative to popen
+*
+* Provides spopen and spclose
+*
+* FILE * spopen(const char *);
+* int spclose(FILE *);
+*
+* Code taken with little modification from "Advanced Programming for the Unix
+* Environment" by W. Richard Stevens
+*
+* This is considered safe in that no shell is spawned, and the environment
+* and path passed to the exec'd program are essentially empty. (popen create
+* a shell and passes the environment to it).
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#include "./common.h"
+#include "./utils.h"
+#include "../lib/maxfd.h"
+
+/* extern so plugin has pid to kill exec'd process on timeouts */
+extern pid_t *childpid;
+extern int *child_stderr_array;
+extern FILE *child_process;
+
+FILE *spopen (const char *);
+int spclose (FILE *);
+#ifdef REDHAT_SPOPEN_ERROR
+void popen_sigchld_handler (int);
+#endif
+void popen_timeout_alarm_handler (int);
+
+#include <stdarg.h> /* ANSI C header file */
+#include <fcntl.h>
+
+#include <limits.h>
+#include <sys/resource.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
+#if defined(SIG_IGN) && !defined(SIG_ERR)
+#define SIG_ERR ((Sigfunc *)-1)
+#endif
+
+
+char *pname = NULL; /* caller can set this from argv[0] */
+
+#ifdef REDHAT_SPOPEN_ERROR
+static volatile int childtermd = 0;
+#endif
+
+FILE *
+spopen (const char *cmdstring)
+{
+ char *env[2];
+ char *cmd = NULL;
+ char **argv = NULL;
+ char *str, *tmp;
+ int argc;
+
+ int i = 0, pfd[2], pfderr[2];
+ pid_t pid;
+
+#ifdef RLIMIT_CORE
+ /* do not leave core files */
+ struct rlimit limit;
+ getrlimit (RLIMIT_CORE, &limit);
+ limit.rlim_cur = 0;
+ setrlimit (RLIMIT_CORE, &limit);
+#endif
+
+ env[0] = strdup("LC_ALL=C");
+ env[1] = '\0';
+
+ /* if no command was passed, return with no error */
+ if (cmdstring == NULL)
+ return (NULL);
+
+ /* make copy of command string so strtok() doesn't silently modify it */
+ /* (the calling program may want to access it later) */
+ cmd = malloc (strlen (cmdstring) + 1);
+ if (cmd == NULL)
+ return NULL;
+ strcpy (cmd, cmdstring);
+
+ /* This is not a shell, so we don't handle "???" */
+ if (strstr (cmdstring, "\""))
+ return NULL;
+
+ /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
+ if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''"))
+ return NULL;
+
+ /* there cannot be more args than characters */
+ argc = strlen (cmdstring) + 1; /* add 1 for NULL termination */
+ argv = malloc (sizeof(char*)*argc);
+
+ if (argv == NULL) {
+ printf ("%s\n", _("Could not malloc argv array in popen()"));
+ return NULL;
+ }
+
+ /* loop to get arguments to command */
+ while (cmd) {
+ str = cmd;
+ str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
+
+ if (i >= argc - 2) {
+ printf ("%s\n",_("CRITICAL - You need more args!!!"));
+ return (NULL);
+ }
+
+ if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
+ str++;
+ if (!strstr (str, "'"))
+ return NULL; /* balanced? */
+ cmd = 1 + strstr (str, "'");
+ str[strcspn (str, "'")] = 0;
+ }
+ else if (strcspn(str,"'") < strcspn (str, " \t\r\n")) {
+ /* handle --option='foo bar' strings */
+ tmp = str + strcspn(str, "'") + 1;
+ if (!strstr (tmp, "'"))
+ return NULL; /* balanced? */
+ tmp += strcspn(tmp,"'") + 1;
+ *tmp = 0;
+ cmd = tmp + 1;
+ } else {
+ if (strpbrk (str, " \t\r\n")) {
+ cmd = 1 + strpbrk (str, " \t\r\n");
+ str[strcspn (str, " \t\r\n")] = 0;
+ }
+ else {
+ cmd = NULL;
+ }
+ }
+
+ if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n"))
+ cmd = NULL;
+
+ argv[i++] = str;
+
+ }
+ argv[i] = NULL;
+
+ long maxfd = mp_open_max();
+
+ if (childpid == NULL) { /* first time through */
+ if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL)
+ return (NULL);
+ }
+
+ if (child_stderr_array == NULL) { /* first time through */
+ if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL)
+ return (NULL);
+ }
+
+ if (pipe (pfd) < 0)
+ return (NULL); /* errno set by pipe() */
+
+ if (pipe (pfderr) < 0)
+ return (NULL); /* errno set by pipe() */
+
+#ifdef REDHAT_SPOPEN_ERROR
+ if (signal (SIGCHLD, popen_sigchld_handler) == SIG_ERR) {
+ usage4 (_("Cannot catch SIGCHLD"));
+ }
+#endif
+
+ if ((pid = fork ()) < 0)
+ return (NULL); /* errno set by fork() */
+ else if (pid == 0) { /* child */
+ close (pfd[0]);
+ if (pfd[1] != STDOUT_FILENO) {
+ dup2 (pfd[1], STDOUT_FILENO);
+ close (pfd[1]);
+ }
+ close (pfderr[0]);
+ if (pfderr[1] != STDERR_FILENO) {
+ dup2 (pfderr[1], STDERR_FILENO);
+ close (pfderr[1]);
+ }
+ /* close all descriptors in childpid[] */
+ for (i = 0; i < maxfd; i++)
+ if (childpid[i] > 0)
+ close (i);
+
+ execve (argv[0], argv, env);
+ _exit (0);
+ }
+
+ close (pfd[1]); /* parent */
+ if ((child_process = fdopen (pfd[0], "r")) == NULL)
+ return (NULL);
+ close (pfderr[1]);
+
+ childpid[fileno (child_process)] = pid; /* remember child pid for this fd */
+ child_stderr_array[fileno (child_process)] = pfderr[0]; /* remember STDERR */
+ return (child_process);
+}
+
+int
+spclose (FILE * fp)
+{
+ int fd, status;
+ pid_t pid;
+
+ if (childpid == NULL)
+ return (1); /* popen() has never been called */
+
+ fd = fileno (fp);
+ if ((pid = childpid[fd]) == 0)
+ return (1); /* fp wasn't opened by popen() */
+
+ childpid[fd] = 0;
+ if (fclose (fp) == EOF)
+ return (1);
+
+#ifdef REDHAT_SPOPEN_ERROR
+ while (!childtermd); /* wait until SIGCHLD */
+#endif
+
+ while (waitpid (pid, &status, 0) < 0)
+ if (errno != EINTR)
+ return (1); /* error other than EINTR from waitpid() */
+
+ if (WIFEXITED (status))
+ return (WEXITSTATUS (status)); /* return child's termination status */
+
+ return (1);
+}
+
+#ifdef REDHAT_SPOPEN_ERROR
+void
+popen_sigchld_handler (int signo)
+{
+ if (signo == SIGCHLD)
+ childtermd = 1;
+}
+#endif
+
+void
+popen_timeout_alarm_handler (int signo)
+{
+ int fh;
+ if (signo == SIGALRM) {
+ if (child_process != NULL) {
+ fh=fileno (child_process);
+ if(fh >= 0){
+ kill (childpid[fh], SIGKILL);
+ }
+ printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
+ timeout_interval);
+ } else {
+ printf ("%s\n", _("CRITICAL - popen timeout received, but no child process"));
+ }
+ exit (STATE_CRITICAL);
+ }
+}
diff --git a/plugins/popen.h b/plugins/popen.h
new file mode 100644
index 0000000..1ea6963
--- /dev/null
+++ b/plugins/popen.h
@@ -0,0 +1,13 @@
+/******************************************************************************
+*
+*
+*****************************************************************************/
+
+FILE *spopen (const char *);
+int spclose (FILE *);
+void popen_timeout_alarm_handler (int);
+
+pid_t *childpid=NULL;
+int *child_stderr_array=NULL;
+FILE *child_process=NULL;
+FILE *child_stderr=NULL;
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
new file mode 100644
index 0000000..4f3e349
--- /dev/null
+++ b/plugins/runcmd.c
@@ -0,0 +1,342 @@
+/*****************************************************************************
+*
+* Monitoring run command utilities
+*
+* License: GPL
+* Copyright (c) 2005-2006 Monitoring Plugins Development Team
+*
+* Description :
+*
+* A simple interface to executing programs from other programs, using an
+* optimized and safe popen()-like implementation. It is considered safe
+* in that no shell needs to be spawned and the environment passed to the
+* execve()'d program is essentially empty.
+*
+* The code in this file is a derivative of popen.c which in turn was taken
+* from "Advanced Programming for the Unix Environment" by W. Richard Stevens.
+*
+* Care has been taken to make sure the functions are async-safe. The one
+* function which isn't is np_runcmd_init() which it doesn't make sense to
+* call twice anyway, so the api as a whole should be considered async-safe.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#define NAGIOSPLUG_API_C 1
+
+/** includes **/
+#include "runcmd.h"
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "./utils.h"
+
+/** macros **/
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
+#if defined(SIG_IGN) && !defined(SIG_ERR)
+# define SIG_ERR ((Sigfunc *)-1)
+#endif
+
+#include "../lib/maxfd.h"
+
+/* This variable must be global, since there's no way the caller
+ * can forcibly slay a dead or ungainly running program otherwise.
+ * Multithreading apps and plugins can initialize it (via NP_RUNCMD_INIT)
+ * in an async safe manner PRIOR to calling np_runcmd() for the first time.
+ *
+ * The check for initialized values is atomic and can
+ * occur in any number of threads simultaneously. */
+static pid_t *np_pids = NULL;
+
+/** prototypes **/
+static int np_runcmd_open(const char *, int *, int *)
+ __attribute__((__nonnull__(1, 2, 3)));
+
+static int np_fetch_output(int, output *, int)
+ __attribute__((__nonnull__(2)));
+
+static int np_runcmd_close(int);
+
+/* prototype imported from utils.h */
+extern void die (int, const char *, ...)
+ __attribute__((__noreturn__,__format__(__printf__, 2, 3)));
+
+
+/* this function is NOT async-safe. It is exported so multithreaded
+ * plugins (or other apps) can call it prior to running any commands
+ * through this api and thus achieve async-safeness throughout the api */
+void np_runcmd_init(void)
+{
+ long maxfd = mp_open_max();
+ if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t));
+}
+
+
+/* Start running a command */
+static int
+np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
+{
+ char *env[2];
+ char *cmd = NULL;
+ char **argv = NULL;
+ char *str;
+ int argc;
+ size_t cmdlen;
+ pid_t pid;
+#ifdef RLIMIT_CORE
+ struct rlimit limit;
+#endif
+
+ int i = 0;
+
+ if(!np_pids) NP_RUNCMD_INIT;
+
+ env[0] = strdup("LC_ALL=C");
+ env[1] = '\0';
+
+ /* make copy of command string so strtok() doesn't silently modify it */
+ /* (the calling program may want to access it later) */
+ cmdlen = strlen(cmdstring);
+ if((cmd = malloc(cmdlen + 1)) == NULL) return -1;
+ memcpy(cmd, cmdstring, cmdlen);
+ cmd[cmdlen] = '\0';
+
+ /* This is not a shell, so we don't handle "???" */
+ if (strstr (cmdstring, "\"")) return -1;
+
+ /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
+ if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''"))
+ return -1;
+
+ /* each arg must be whitespace-separated, so args can be a maximum
+ * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
+ argc = (cmdlen >> 1) + 2;
+ argv = calloc(sizeof(char *), argc);
+
+ if (argv == NULL) {
+ printf ("%s\n", _("Could not malloc argv array in popen()"));
+ return -1;
+ }
+
+ /* get command arguments (stupidly, but fairly quickly) */
+ while (cmd) {
+ str = cmd;
+ str += strspn (str, " \t\r\n"); /* trim any leading whitespace */
+
+ if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */
+ str++;
+ if (!strstr (str, "'")) return -1; /* balanced? */
+ cmd = 1 + strstr (str, "'");
+ str[strcspn (str, "'")] = 0;
+ }
+ else {
+ if (strpbrk (str, " \t\r\n")) {
+ cmd = 1 + strpbrk (str, " \t\r\n");
+ str[strcspn (str, " \t\r\n")] = 0;
+ }
+ else {
+ cmd = NULL;
+ }
+ }
+
+ if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n"))
+ cmd = NULL;
+
+ argv[i++] = str;
+ }
+
+ if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0)
+ return -1; /* errno set by the failing function */
+
+ /* child runs exceve() and _exit. */
+ if (pid == 0) {
+#ifdef RLIMIT_CORE
+ /* the program we execve shouldn't leave core files */
+ getrlimit (RLIMIT_CORE, &limit);
+ limit.rlim_cur = 0;
+ setrlimit (RLIMIT_CORE, &limit);
+#endif
+ close (pfd[0]);
+ if (pfd[1] != STDOUT_FILENO) {
+ dup2 (pfd[1], STDOUT_FILENO);
+ close (pfd[1]);
+ }
+ close (pfderr[0]);
+ if (pfderr[1] != STDERR_FILENO) {
+ dup2 (pfderr[1], STDERR_FILENO);
+ close (pfderr[1]);
+ }
+
+ /* close all descriptors in np_pids[]
+ * This is executed in a separate address space (pure child),
+ * so we don't have to worry about async safety */
+ long maxfd = mp_open_max();
+ for (i = 0; i < maxfd; i++)
+ if(np_pids[i] > 0)
+ close (i);
+
+ execve (argv[0], argv, env);
+ _exit (STATE_UNKNOWN);
+ }
+
+ /* parent picks up execution here */
+ /* close children descriptors in our address space */
+ close(pfd[1]);
+ close(pfderr[1]);
+
+ /* tag our file's entry in the pid-list and return it */
+ np_pids[pfd[0]] = pid;
+
+ return pfd[0];
+}
+
+
+static int
+np_runcmd_close(int fd)
+{
+ int status;
+ pid_t pid;
+
+ /* make sure this fd was opened by popen() */
+ long maxfd = mp_open_max();
+ if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0)
+ return -1;
+
+ np_pids[fd] = 0;
+ if (close (fd) == -1) return -1;
+
+ /* EINTR is ok (sort of), everything else is bad */
+ while (waitpid (pid, &status, 0) < 0)
+ if (errno != EINTR) return -1;
+
+ /* return child's termination status */
+ return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
+}
+
+
+void
+runcmd_timeout_alarm_handler (int signo)
+{
+ size_t i;
+
+ if (signo == SIGALRM)
+ puts(_("CRITICAL - Plugin timed out while executing system call"));
+
+ long maxfd = mp_open_max();
+ if(np_pids) for(i = 0; i < maxfd; i++) {
+ if(np_pids[i] != 0) kill(np_pids[i], SIGKILL);
+ }
+
+ exit (STATE_CRITICAL);
+}
+
+
+static int
+np_fetch_output(int fd, output *op, int flags)
+{
+ size_t len = 0, i = 0, lineno = 0;
+ size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
+ char *buf = NULL;
+ int ret;
+ char tmpbuf[4096];
+
+ op->buf = NULL;
+ op->buflen = 0;
+ while((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
+ len = (size_t)ret;
+ op->buf = realloc(op->buf, op->buflen + len + 1);
+ memcpy(op->buf + op->buflen, tmpbuf, len);
+ op->buflen += len;
+ i++;
+ }
+
+ if(ret < 0) {
+ printf("read() returned %d: %s\n", ret, strerror(errno));
+ return ret;
+ }
+
+ /* some plugins may want to keep output unbroken, and some commands
+ * will yield no output, so return here for those */
+ if(flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen)
+ return op->buflen;
+
+ /* and some may want both */
+ if(flags & RUNCMD_NO_ASSOC) {
+ buf = malloc(op->buflen);
+ memcpy(buf, op->buf, op->buflen);
+ }
+ else buf = op->buf;
+
+ op->line = NULL;
+ op->lens = NULL;
+ i = 0;
+ while(i < op->buflen) {
+ /* make sure we have enough memory */
+ if(lineno >= ary_size) {
+ /* ary_size must never be zero */
+ do {
+ ary_size = op->buflen >> --rsf;
+ } while(!ary_size);
+
+ op->line = realloc(op->line, ary_size * sizeof(char *));
+ op->lens = realloc(op->lens, ary_size * sizeof(size_t));
+ }
+
+ /* set the pointer to the string */
+ op->line[lineno] = &buf[i];
+
+ /* hop to next newline or end of buffer */
+ while(buf[i] != '\n' && i < op->buflen) i++;
+ buf[i] = '\0';
+
+ /* calculate the string length using pointer difference */
+ op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
+
+ lineno++;
+ i++;
+ }
+
+ return lineno;
+}
+
+
+int
+np_runcmd(const char *cmd, output *out, output *err, int flags)
+{
+ int fd, pfd_out[2], pfd_err[2];
+
+ /* initialize the structs */
+ if(out) memset(out, 0, sizeof(output));
+ if(err) memset(err, 0, sizeof(output));
+
+ if((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1)
+ die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
+
+ if(out) out->lines = np_fetch_output(pfd_out[0], out, flags);
+ if(err) err->lines = np_fetch_output(pfd_err[0], err, flags);
+
+ return np_runcmd_close(fd);
+}
diff --git a/plugins/runcmd.h b/plugins/runcmd.h
new file mode 100644
index 0000000..2dcdadf
--- /dev/null
+++ b/plugins/runcmd.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+*
+* License: GPL
+* Copyright (c) 2005 Monitoring Plugins Development Team
+* Author: Andreas Ericsson <ae@op5.se>
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#ifndef NAGIOSPLUG_RUNCMD_H
+#define NAGIOSPLUG_RUNCMD_H
+
+#include "common.h"
+#include "utils_cmd.h" /* for the "output" type */
+
+/** prototypes **/
+int np_runcmd(const char *, output *, output *, int);
+void runcmd_timeout_alarm_handler(int)
+ __attribute__((__noreturn__));
+
+/* only multi-threaded plugins need to bother with this */
+void np_runcmd_init(void);
+#define NP_RUNCMD_INIT np_runcmd_init()
+
+/* possible flags for np_runcmd()'s fourth argument */
+#define RUNCMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
+#define RUNCMD_NO_ASSOC 0x02 /* output.line won't point to buf */
+
+#endif /* NAGIOSPLUG_RUNCMD_H */
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
new file mode 100644
index 0000000..6bc0ba8
--- /dev/null
+++ b/plugins/sslutils.c
@@ -0,0 +1,330 @@
+/*****************************************************************************
+*
+* Monitoring Plugins SSL utilities
+*
+* License: GPL
+* Copyright (c) 2005-2010 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains common functions for plugins that require SSL.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#define MAX_CN_LENGTH 256
+#include "common.h"
+#include "netutils.h"
+
+#ifdef HAVE_SSL
+static SSL_CTX *ctx=NULL;
+static SSL *s=NULL;
+
+int np_net_ssl_init(int sd) {
+ return np_net_ssl_init_with_hostname(sd, NULL);
+}
+
+int np_net_ssl_init_with_hostname(int sd, char *host_name) {
+ return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
+}
+
+int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
+ return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
+}
+
+int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) {
+ long options = 0;
+
+ if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
+ printf("%s\n", _("CRITICAL - Cannot create SSL context."));
+ return STATE_CRITICAL;
+ }
+
+ switch (version) {
+ case MP_SSLv2: /* SSLv2 protocol */
+ printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+ case MP_SSLv3: /* SSLv3 protocol */
+#if defined(OPENSSL_NO_SSL3)
+ printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
+ SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
+ break;
+#endif
+ case MP_TLSv1: /* TLSv1 protocol */
+#if defined(OPENSSL_NO_TLS1)
+ printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
+ SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
+ break;
+#endif
+ case MP_TLSv1_1: /* TLSv1.1 protocol */
+#if !defined(SSL_OP_NO_TLSv1_1)
+ printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
+ SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
+ break;
+#endif
+ case MP_TLSv1_2: /* TLSv1.2 protocol */
+#if !defined(SSL_OP_NO_TLSv1_2)
+ printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
+ SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
+ break;
+#endif
+ case MP_TLSv1_2_OR_NEWER:
+#if !defined(SSL_OP_NO_TLSv1_1)
+ printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
+ break;
+#endif
+ case MP_TLSv1_1_OR_NEWER:
+#if !defined(SSL_OP_NO_TLSv1)
+ printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library."));
+ return STATE_UNKNOWN;
+#else
+ SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
+ break;
+#endif
+ case MP_TLSv1_OR_NEWER:
+#if defined(SSL_OP_NO_SSLv3)
+ SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
+ break;
+#endif
+ case MP_SSLv3_OR_NEWER:
+#if defined(SSL_OP_NO_SSLv2)
+ SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
+ break;
+#endif
+ }
+
+ if (cert && privkey) {
+#ifdef USE_OPENSSL
+ if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
+#elif USE_GNUTLS
+ if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
+#else
+#error Unported for unknown SSL library
+#endif
+ printf ("%s\n", _("CRITICAL - Unable to open certificate chain file!\n"));
+ return STATE_CRITICAL;
+ }
+ SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM);
+#ifdef USE_OPENSSL
+ if (!SSL_CTX_check_private_key(ctx)) {
+ printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
+ return STATE_CRITICAL;
+ }
+#endif
+ }
+#ifdef SSL_OP_NO_TICKET
+ options |= SSL_OP_NO_TICKET;
+#endif
+ SSL_CTX_set_options(ctx, options);
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+ if ((s = SSL_new(ctx)) != NULL) {
+#ifdef SSL_set_tlsext_host_name
+ if (host_name != NULL)
+ SSL_set_tlsext_host_name(s, host_name);
+#endif
+ SSL_set_fd(s, sd);
+ if (SSL_connect(s) == 1) {
+ return OK;
+ } else {
+ printf("%s\n", _("CRITICAL - Cannot make SSL connection."));
+# ifdef USE_OPENSSL /* XXX look into ERR_error_string */
+ ERR_print_errors_fp(stdout);
+# endif /* USE_OPENSSL */
+ }
+ } else {
+ printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake."));
+ }
+ return STATE_CRITICAL;
+}
+
+void np_net_ssl_cleanup() {
+ if (s) {
+#ifdef SSL_set_tlsext_host_name
+ SSL_set_tlsext_host_name(s, NULL);
+#endif
+ SSL_shutdown(s);
+ SSL_free(s);
+ if (ctx) {
+ SSL_CTX_free(ctx);
+ ctx=NULL;
+ }
+ s=NULL;
+ }
+}
+
+int np_net_ssl_write(const void *buf, int num) {
+ return SSL_write(s, buf, num);
+}
+
+int np_net_ssl_read(void *buf, int num) {
+ return SSL_read(s, buf, num);
+}
+
+int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit){
+# ifdef USE_OPENSSL
+ X509_NAME *subj=NULL;
+ char timestamp[50] = "";
+ char cn[MAX_CN_LENGTH]= "";
+ char *tz;
+
+ int cnlen =-1;
+ int status=STATE_UNKNOWN;
+
+ ASN1_STRING *tm;
+ int offset;
+ struct tm stamp;
+ float time_left;
+ int days_left;
+ int time_remaining;
+ time_t tm_t;
+
+ if (!certificate) {
+ printf("%s\n",_("CRITICAL - Cannot retrieve server certificate."));
+ return STATE_CRITICAL;
+ }
+
+ /* Extract CN from certificate subject */
+ subj=X509_get_subject_name(certificate);
+
+ if (!subj) {
+ printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject."));
+ return STATE_CRITICAL;
+ }
+ cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
+ if (cnlen == -1)
+ strcpy(cn, _("Unknown CN"));
+
+ /* Retrieve timestamp of certificate */
+ tm = X509_get_notAfter(certificate);
+
+ /* Generate tm structure to process timestamp */
+ if (tm->type == V_ASN1_UTCTIME) {
+ if (tm->length < 10) {
+ printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
+ return STATE_CRITICAL;
+ } else {
+ stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
+ if (stamp.tm_year < 50)
+ stamp.tm_year += 100;
+ offset = 0;
+ }
+ } else {
+ if (tm->length < 12) {
+ printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
+ return STATE_CRITICAL;
+ } else {
+ stamp.tm_year =
+ (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
+ (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
+ stamp.tm_year -= 1900;
+ offset = 2;
+ }
+ }
+ stamp.tm_mon =
+ (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
+ stamp.tm_mday =
+ (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
+ stamp.tm_hour =
+ (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
+ stamp.tm_min =
+ (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
+ stamp.tm_sec =
+ (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
+ stamp.tm_isdst = -1;
+
+ tm_t = timegm(&stamp);
+ time_left = difftime(tm_t, time(NULL));
+ days_left = time_left / 86400;
+ tz = getenv("TZ");
+ setenv("TZ", "GMT", 1);
+ tzset();
+ strftime(timestamp, 50, "%c %z", localtime(&tm_t));
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+
+ if (days_left > 0 && days_left <= days_till_exp_warn) {
+ printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp);
+ if (days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else if (days_left == 0 && time_left > 0) {
+ if (time_left >= 3600)
+ time_remaining = (int) time_left / 3600;
+ else
+ time_remaining = (int) time_left / 60;
+
+ printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"),
+ (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining,
+ time_left >= 3600 ? "hours" : "minutes", timestamp);
+
+ if ( days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else if (time_left < 0) {
+ printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
+ status=STATE_CRITICAL;
+ } else if (days_left == 0) {
+ printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp);
+ if (days_left > days_till_exp_crit)
+ status = STATE_WARNING;
+ else
+ status = STATE_CRITICAL;
+ } else {
+ printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp);
+ status = STATE_OK;
+ }
+ X509_free(certificate);
+ return status;
+# else /* ifndef USE_OPENSSL */
+ printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
+ return STATE_WARNING;
+# endif /* USE_OPENSSL */
+}
+
+int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){
+# ifdef USE_OPENSSL
+ X509 *certificate = NULL;
+ certificate=SSL_get_peer_certificate(s);
+ return(np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit));
+# else /* ifndef USE_OPENSSL */
+ printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
+ return STATE_WARNING;
+# endif /* USE_OPENSSL */
+}
+
+
+#endif /* HAVE_SSL */
diff --git a/plugins/t/check_apt.t b/plugins/t/check_apt.t
new file mode 100644
index 0000000..430eb53
--- /dev/null
+++ b/plugins/t/check_apt.t
@@ -0,0 +1,106 @@
+#!/usr/bin/perl -w -I ..
+#
+# Test check_apt using input files.
+# Contributed by Alex Bradley, October 2012
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+sub make_result_regexp {
+ my ($warning, $critical) = @_;
+ my $status;
+ if ($warning == 0 && $critical == 0) {
+ $status = "OK";
+ } elsif ($critical == 0) {
+ $status = "WARNING";
+ } else {
+ $status = "CRITICAL";
+ }
+ return sprintf('/^APT %s: %d packages available for upgrade \(%d critical updates\)\. |available_upgrades=%d;;;0 critical_updates=%d;;;0$/',
+ $status, $warning, $critical, $warning, $critical);
+}
+
+if (-x "./check_apt") {
+ plan tests => 36;
+} else {
+ plan skip_all => "No check_apt compiled";
+}
+
+my $result;
+
+my $testfile_command = "./check_apt %s --input-file=t/check_apt_input/%s";
+
+$result = NPTest->testCmd( sprintf($testfile_command, "", "debian1") );
+is( $result->return_code, 0, "No upgrades" );
+like( $result->output, make_result_regexp(0, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "", "debian2") );
+is( $result->return_code, 1, "Debian apt output, warning" );
+like( $result->output, make_result_regexp(13, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") );
+is( $result->return_code, 0, "Debian apt output, no critical" );
+like( $result->output, make_result_regexp(13, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") );
+is( $result->return_code, 2, "Debian apt output, some critical" );
+like( $result->output, make_result_regexp(19, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian3") );
+is( $result->return_code, 2, "Debian apt output, some critical" );
+like( $result->output, make_result_regexp(19, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-c '^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)'", "debian3") );
+is( $result->return_code, 2, "Debian apt output - should have same result when default security regexp specified via -c" );
+like( $result->output, make_result_regexp(19, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-i libc6", "debian3") );
+is( $result->return_code, 1, "Debian apt output, filter for libc6" );
+like( $result->output, make_result_regexp(3, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-i libc6", "debian3") );
+is( $result->return_code, 1, "Debian apt output, filter for libc6, not critical" );
+like( $result->output, make_result_regexp(3, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-i libc6 -i xen", "debian3") );
+is( $result->return_code, 2, "Debian apt output, filter for libc6 and xen" );
+like( $result->output, make_result_regexp(9, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-i libc6 -i xen -i linux", "debian3") );
+is( $result->return_code, 2, "Debian apt output, filter for libc6, xen, linux" );
+like( $result->output, make_result_regexp(12, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-e libc6", "debian3") );
+is( $result->return_code, 2, "Debian apt output, filter out libc6" );
+like( $result->output, make_result_regexp(16, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-e libc6 -o", "debian3") );
+is( $result->return_code, 2, "Debian apt output, filter out libc6, critical" );
+like( $result->output, make_result_regexp(16, 4), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-e libc6 -e xen", "debian3") );
+is( $result->return_code, 1, "Debian apt output, filter out libc6 and xen" );
+like( $result->output, make_result_regexp(10, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-e libc6 -e xen -e linux", "debian3") );
+is( $result->return_code, 1, "Debian apt output, filter out libc6, xen, linux" );
+like( $result->output, make_result_regexp(7, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-c Debian-Security -c linux", "debian3") );
+is( $result->return_code, 2, "Debian apt output, critical on Debian-Security or linux" );
+like( $result->output, make_result_regexp(19, 9), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "-i lib -i linux -e gc1c -c linux-image", "debian3") );
+is( $result->return_code, 2, "Debian apt output, include lib and linux, exclude gc1c, critical on linux-image" );
+like( $result->output, make_result_regexp(10, 2), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "", "ubuntu1") );
+is( $result->return_code, 1, "Ubuntu apt output, warning" );
+like( $result->output, make_result_regexp(5, 0), "Output correct" );
+
+$result = NPTest->testCmd( sprintf($testfile_command, "", "ubuntu2") );
+is( $result->return_code, 2, "Ubuntu apt output, some critical" );
+like( $result->output, make_result_regexp(25, 14), "Output correct" );
+
diff --git a/plugins/t/check_apt_input/debian1 b/plugins/t/check_apt_input/debian1
new file mode 100644
index 0000000..317e7ea
--- /dev/null
+++ b/plugins/t/check_apt_input/debian1
@@ -0,0 +1,4 @@
+NOTE: This is only a simulation!
+ apt-get needs root privileges for real execution.
+ Keep also in mind that locking is deactivated,
+ so don't depend on the relevance to the real current situation!
diff --git a/plugins/t/check_apt_input/debian2 b/plugins/t/check_apt_input/debian2
new file mode 100644
index 0000000..effd155
--- /dev/null
+++ b/plugins/t/check_apt_input/debian2
@@ -0,0 +1,37 @@
+NOTE: This is only a simulation!
+ apt-get needs root privileges for real execution.
+ Keep also in mind that locking is deactivated,
+ so don't depend on the relevance to the real current situation!
+Reading package lists... Done
+Building dependency tree
+Reading state information... Done
+The following packages will be upgraded:
+ base-files debian-archive-keyring dpkg firmware-linux-free libc-bin libc-dev-bin libc6 libc6-dev linux-base
+ linux-image-2.6.32-5-xen-amd64 linux-libc-dev locales lockfile-progs
+13 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
+Inst base-files [6.0squeeze5] (6.0squeeze6 Debian:6.0.6/stable [amd64])
+Conf base-files (6.0squeeze6 Debian:6.0.6/stable [amd64])
+Inst dpkg [1.15.8.12] (1.15.8.13 Debian:6.0.6/stable [amd64])
+Conf dpkg (1.15.8.13 Debian:6.0.6/stable [amd64])
+Inst linux-base [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [all])
+Inst linux-image-2.6.32-5-xen-amd64 [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [amd64])
+Inst debian-archive-keyring [2010.08.28] (2010.08.28+squeeze1 Debian:6.0.6/stable [all])
+Conf debian-archive-keyring (2010.08.28+squeeze1 Debian:6.0.6/stable [all])
+Inst libc6-dev [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64]) []
+Inst libc-dev-bin [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64]) []
+Inst linux-libc-dev [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [amd64]) []
+Inst libc-bin [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64]) [libc6:amd64 ]
+Conf libc-bin (2.11.3-4 Debian:6.0.6/stable [amd64]) [libc6:amd64 ]
+Inst libc6 [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64])
+Conf libc6 (2.11.3-4 Debian:6.0.6/stable [amd64])
+Inst locales [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [all])
+Inst firmware-linux-free [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [all])
+Inst lockfile-progs [0.1.15] (0.1.15+squeeze1 Debian:6.0.6/stable [amd64])
+Conf linux-base (2.6.32-46 Debian:6.0.6/stable [all])
+Conf linux-image-2.6.32-5-xen-amd64 (2.6.32-46 Debian:6.0.6/stable [amd64])
+Conf libc-dev-bin (2.11.3-4 Debian:6.0.6/stable [amd64])
+Conf linux-libc-dev (2.6.32-46 Debian:6.0.6/stable [amd64])
+Conf libc6-dev (2.11.3-4 Debian:6.0.6/stable [amd64])
+Conf locales (2.11.3-4 Debian:6.0.6/stable [all])
+Conf firmware-linux-free (2.6.32-46 Debian:6.0.6/stable [all])
+Conf lockfile-progs (0.1.15+squeeze1 Debian:6.0.6/stable [amd64])
diff --git a/plugins/t/check_apt_input/debian3 b/plugins/t/check_apt_input/debian3
new file mode 100644
index 0000000..719dce9
--- /dev/null
+++ b/plugins/t/check_apt_input/debian3
@@ -0,0 +1,42 @@
+NOTE: This is only a simulation!
+ apt-get needs root privileges for real execution.
+ Keep also in mind that locking is deactivated,
+ so don't depend on the relevance to the real current situation!
+Inst base-files [6.0squeeze5] (6.0squeeze6 Debian:6.0.6/stable [amd64])
+Conf base-files (6.0squeeze6 Debian:6.0.6/stable [amd64])
+Inst dpkg [1.15.8.12] (1.15.8.13 Debian:6.0.6/stable [amd64])
+Conf dpkg (1.15.8.13 Debian:6.0.6/stable [amd64])
+Inst linux-base [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [all])
+Inst linux-image-2.6.32-5-amd64 [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [amd64])
+Inst xen-hypervisor-4.0-amd64 [4.0.1-5.3] (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Inst xen-linux-system-2.6.32-5-xen-amd64 [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [amd64]) []
+Inst linux-image-2.6.32-5-xen-amd64 [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [amd64])
+Inst debian-archive-keyring [2010.08.28] (2010.08.28+squeeze1 Debian:6.0.6/stable [all])
+Conf debian-archive-keyring (2010.08.28+squeeze1 Debian:6.0.6/stable [all])
+Inst libc6-i386 [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64]) []
+Inst libc-bin [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64]) [libc6:amd64 ]
+Conf libc-bin (2.11.3-4 Debian:6.0.6/stable [amd64]) [libc6:amd64 ]
+Inst libc6 [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [amd64])
+Conf libc6 (2.11.3-4 Debian:6.0.6/stable [amd64])
+Inst libgc1c2 [1:6.8-1.2] (1:6.8-2 Debian:6.0.6/stable [amd64])
+Inst locales [2.11.3-3] (2.11.3-4 Debian:6.0.6/stable [all])
+Inst firmware-linux-free [2.6.32-45] (2.6.32-46 Debian:6.0.6/stable [all])
+Inst libxenstore3.0 [4.0.1-5.3] (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Inst lockfile-progs [0.1.15] (0.1.15+squeeze1 Debian:6.0.6/stable [amd64])
+Inst xen-utils-4.0 [4.0.1-5.3] (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Inst xenstore-utils [4.0.1-5.3] (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Inst libconfig-inifiles-perl [2.52-1] (2.52-1+squeeze1 Debian:6.0.6/stable [all])
+Conf linux-base (2.6.32-46 Debian:6.0.6/stable [all])
+Conf linux-image-2.6.32-5-amd64 (2.6.32-46 Debian:6.0.6/stable [amd64])
+Conf xen-hypervisor-4.0-amd64 (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Conf linux-image-2.6.32-5-xen-amd64 (2.6.32-46 Debian:6.0.6/stable [amd64])
+Conf xen-linux-system-2.6.32-5-xen-amd64 (2.6.32-46 Debian:6.0.6/stable [amd64])
+Conf libc6-i386 (2.11.3-4 Debian:6.0.6/stable [amd64])
+Conf libgc1c2 (1:6.8-2 Debian:6.0.6/stable [amd64])
+Conf locales (2.11.3-4 Debian:6.0.6/stable [all])
+Conf firmware-linux-free (2.6.32-46 Debian:6.0.6/stable [all])
+Conf libxenstore3.0 (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Conf lockfile-progs (0.1.15+squeeze1 Debian:6.0.6/stable [amd64])
+Conf xen-utils-4.0 (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Conf xenstore-utils (4.0.1-5.4 Debian:6.0.6/stable, Debian-Security:6.0/stable [amd64])
+Conf libconfig-inifiles-perl (2.52-1+squeeze1 Debian:6.0.6/stable [all])
diff --git a/plugins/t/check_apt_input/ubuntu1 b/plugins/t/check_apt_input/ubuntu1
new file mode 100644
index 0000000..2f61c30
--- /dev/null
+++ b/plugins/t/check_apt_input/ubuntu1
@@ -0,0 +1,14 @@
+NOTE: This is only a simulation!
+ apt-get needs root privileges for real execution.
+ Also keep in mind that locking is deactivated,
+ so don't depend on the relevance to the real current situation!
+Inst grub-pc [1.99-21ubuntu3.1] (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64]) []
+Inst grub-pc-bin [1.99-21ubuntu3.1] (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64]) []
+Inst grub2-common [1.99-21ubuntu3.1] (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64]) []
+Inst grub-efi-amd64-bin [1.99-21ubuntu3.1] (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64]) []
+Inst grub-common [1.99-21ubuntu3.1] (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
+Conf grub-common (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
+Conf grub2-common (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
+Conf grub-pc-bin (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
+Conf grub-pc (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
+Conf grub-efi-amd64-bin (1.99-21ubuntu3.4 Ubuntu:12.04/precise-updates [amd64])
diff --git a/plugins/t/check_apt_input/ubuntu2 b/plugins/t/check_apt_input/ubuntu2
new file mode 100644
index 0000000..29a14a0
--- /dev/null
+++ b/plugins/t/check_apt_input/ubuntu2
@@ -0,0 +1,54 @@
+NOTE: This is only a simulation!
+ apt-get needs root privileges for real execution.
+ Also keep in mind that locking is deactivated,
+ so don't depend on the relevance to the real current situation!
+Inst libc6-dev [2.15-0ubuntu10] (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64]) []
+Inst libc-dev-bin [2.15-0ubuntu10] (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64]) []
+Inst linux-libc-dev [3.2.0-29.46] (3.2.0-31.50 Ubuntu:12.04/precise-security [amd64]) []
+Inst tzdata [2012e-0ubuntu0.12.04] (2012e-0ubuntu0.12.04.1 Ubuntu:12.04/precise-security [all]) []
+Conf tzdata (2012e-0ubuntu0.12.04.1 Ubuntu:12.04/precise-security [all]) []
+Inst libc-bin [2.15-0ubuntu10] (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64]) [libc6:amd64 ]
+Conf libc-bin (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64]) [libc6:amd64 ]
+Inst libc6 [2.15-0ubuntu10] (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Conf libc6 (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Inst libapt-pkg4.12 [0.8.16~exp12ubuntu10.2] (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Conf libapt-pkg4.12 (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Inst ubuntu-keyring [2011.11.21] (2011.11.21.1 Ubuntu:12.04/precise-updates [all])
+Conf ubuntu-keyring (2011.11.21.1 Ubuntu:12.04/precise-updates [all])
+Inst gpgv [1.4.11-3ubuntu2] (1.4.11-3ubuntu2.1 Ubuntu:12.04/precise-security [amd64])
+Conf gpgv (1.4.11-3ubuntu2.1 Ubuntu:12.04/precise-security [amd64])
+Inst gnupg [1.4.11-3ubuntu2] (1.4.11-3ubuntu2.1 Ubuntu:12.04/precise-security [amd64])
+Conf gnupg (1.4.11-3ubuntu2.1 Ubuntu:12.04/precise-security [amd64])
+Inst apt [0.8.16~exp12ubuntu10.2] (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Conf apt (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Inst libssl1.0.0 [1.0.1-4ubuntu5.3] (1.0.1-4ubuntu5.5 Ubuntu:12.04/precise-updates [amd64])
+Conf libssl1.0.0 (1.0.1-4ubuntu5.5 Ubuntu:12.04/precise-updates [amd64])
+Inst libapt-inst1.4 [0.8.16~exp12ubuntu10.2] (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Inst resolvconf [1.63ubuntu15] (1.63ubuntu16 Ubuntu:12.04/precise-updates [all])
+Inst libdbus-1-3 [1.4.18-1ubuntu1] (1.4.18-1ubuntu1.1 Ubuntu:12.04/precise-security [amd64])
+Inst libxml2 [2.7.8.dfsg-5.1ubuntu4.1] (2.7.8.dfsg-5.1ubuntu4.2 Ubuntu:12.04/precise-security [amd64])
+Inst multiarch-support [2.15-0ubuntu10] (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Conf multiarch-support (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Inst apt-utils [0.8.16~exp12ubuntu10.2] (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Inst isc-dhcp-client [4.1.ESV-R4-0ubuntu5.2] (4.1.ESV-R4-0ubuntu5.5 Ubuntu:12.04/precise-security [amd64]) []
+Inst isc-dhcp-common [4.1.ESV-R4-0ubuntu5.2] (4.1.ESV-R4-0ubuntu5.5 Ubuntu:12.04/precise-security [amd64])
+Inst dbus [1.4.18-1ubuntu1] (1.4.18-1ubuntu1.1 Ubuntu:12.04/precise-security [amd64])
+Inst linux-firmware [1.79] (1.79.1 Ubuntu:12.04/precise-updates [all])
+Inst xserver-common [2:1.11.4-0ubuntu10.7] (2:1.11.4-0ubuntu10.8 Ubuntu:12.04/precise-updates [all])
+Inst xserver-xorg-core [2:1.11.4-0ubuntu10.7] (2:1.11.4-0ubuntu10.8 Ubuntu:12.04/precise-updates [amd64])
+Inst xserver-xorg-input-synaptics [1.6.2-1ubuntu1~precise1] (1.6.2-1ubuntu1~precise2 Ubuntu:12.04/precise-updates [amd64])
+Conf libc-dev-bin (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Conf linux-libc-dev (3.2.0-31.50 Ubuntu:12.04/precise-security [amd64])
+Conf libc6-dev (2.15-0ubuntu10.2 Ubuntu:12.04/precise-security [amd64])
+Conf libapt-inst1.4 (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Conf resolvconf (1.63ubuntu16 Ubuntu:12.04/precise-updates [all])
+Conf libdbus-1-3 (1.4.18-1ubuntu1.1 Ubuntu:12.04/precise-security [amd64])
+Conf libxml2 (2.7.8.dfsg-5.1ubuntu4.2 Ubuntu:12.04/precise-security [amd64])
+Conf apt-utils (0.8.16~exp12ubuntu10.3 Ubuntu:12.04/precise-updates [amd64])
+Conf isc-dhcp-common (4.1.ESV-R4-0ubuntu5.5 Ubuntu:12.04/precise-security [amd64])
+Conf isc-dhcp-client (4.1.ESV-R4-0ubuntu5.5 Ubuntu:12.04/precise-security [amd64])
+Conf dbus (1.4.18-1ubuntu1.1 Ubuntu:12.04/precise-security [amd64])
+Conf linux-firmware (1.79.1 Ubuntu:12.04/precise-updates [all])
+Conf xserver-common (2:1.11.4-0ubuntu10.8 Ubuntu:12.04/precise-updates [all])
+Conf xserver-xorg-core (2:1.11.4-0ubuntu10.8 Ubuntu:12.04/precise-updates [amd64])
+Conf xserver-xorg-input-synaptics (1.6.2-1ubuntu1~precise2 Ubuntu:12.04/precise-updates [amd64])
diff --git a/plugins/t/check_by_ssh.t b/plugins/t/check_by_ssh.t
new file mode 100644
index 0000000..b6479f1
--- /dev/null
+++ b/plugins/t/check_by_ssh.t
@@ -0,0 +1,153 @@
+#! /usr/bin/perl -w -I ..
+#
+# check_by_ssh tests
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+# Required parameters
+my $ssh_service = getTestParameter("NP_SSH_HOST", "A host providing SSH service", "localhost");
+my $ssh_key = getTestParameter("NP_SSH_IDENTITY", "A key allowing access to NP_SSH_HOST", "~/.ssh/id_dsa");
+my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE", "A config file with ssh settings", "~/.ssh/config");
+
+
+plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key);
+
+plan tests => 42;
+
+# Some random check strings/response
+my @response = ('OK: Everything is fine',
+ 'WARNING: Hey, pick me, pick me',
+ 'CRITICAL: Shit happens',
+ 'UNKNOWN: What can I do for ya',
+ 'WOOPS: What did I smoke',
+);
+my @response_re;
+my @check;
+for (@response) {
+ push(@check, "echo $_");
+ my $re_str = $_;
+ $re_str =~ s{(.)} { "\Q$1" }ge;
+ push(@response_re, $re_str);
+}
+
+my $result;
+
+# expand paths
+$ssh_key = glob($ssh_key) if $ssh_key;
+$ssh_conf = glob($ssh_conf) if $ssh_conf;
+
+## Single active checks
+
+for (my $i=0; $i<4; $i++) {
+ $result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'"
+ );
+ cmp_ok($result->return_code, '==', $i, "Exit with return code $i");
+ is($result->output, $response[$i], "Status text is correct for check $i");
+}
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'"
+ );
+cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
+is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'"
+ );
+cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)");
+is($result->output, 'WARNING - check_by_ssh: Remote command \'exit 1\' returned status 1', "Status text if command returned none (WARNING)");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'"
+ );
+cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)");
+is($result->output, 'CRITICAL - check_by_ssh: Remote command \'exit 2\' returned status 2', "Status text if command returned none (CRITICAL)");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'"
+ );
+cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
+is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 3\' returned status 3', "Status text if command returned none (UNKNOWN)");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'"
+ );
+cmp_ok($result->return_code, '==', 7, "Exit with return code 7 (out of bounds)");
+is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 7\' returned status 7', "Status text if command returned none (out of bounds)");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'"
+ );
+cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)");
+is($result->output, $response[4], "Return proper status text even with unknown status codes");
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'"
+ );
+cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
+is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)");
+
+# Multiple active checks
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'"
+ );
+cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK");
+my @lines = split(/\n/, $result->output);
+cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks");
+my %linemap = (
+ '0' => '1',
+ '2' => '0',
+ '4' => '3',
+ '6' => '2',
+);
+foreach my $line (0, 2, 4, 6) {
+ my $code = $linemap{$line};
+ my $statline = $line+1;
+ is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line");
+ is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line");
+}
+
+# Passive checks
+unlink("/tmp/check_by_ssh.$$");
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -n flint -s serv -C '$check[2]; sh -c exit\\ 2' -O /tmp/check_by_ssh.$$"
+ );
+cmp_ok($result->return_code, '==', 0, "Exit always ok on passive checks");
+open(PASV, "/tmp/check_by_ssh.$$") or die("Unable to open '/tmp/check_by_ssh.$$': $!");
+my @pasv = <PASV>;
+close(PASV) or die("Unable to close '/tmp/check_by_ssh.$$': $!");
+cmp_ok(scalar(@pasv), '==', 1, 'One passive result for one check performed');
+for (0) {
+ if ($pasv[$_]) {
+ like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;serv;2;' . $response_re[2] . '$/', 'proper result for passive check');
+ } else {
+ fail('proper result for passive check');
+ }
+}
+unlink("/tmp/check_by_ssh.$$") or die("Unable to unlink '/tmp/check_by_ssh.$$': $!");
+undef @pasv;
+
+$result = NPTest->testCmd(
+ "./check_by_ssh -i $ssh_key -H $ssh_service -n flint -s c0:c1:c2:c3:c4 -C '$check[0];sh -c exit\\ 0' -C '$check[1];sh -c exit\\ 1' -C '$check[2];sh -c exit\\ 2' -C '$check[3];sh -c exit\\ 3' -C '$check[4];sh -c exit\\ 9' -O /tmp/check_by_ssh.$$"
+ );
+cmp_ok($result->return_code, '==', 0, "Exit always ok on passive checks");
+open(PASV, "/tmp/check_by_ssh.$$") or die("Unable to open '/tmp/check_by_ssh.$$': $!");
+@pasv = <PASV>;
+close(PASV) or die("Unable to close '/tmp/check_by_ssh.$$': $!");
+cmp_ok(scalar(@pasv), '==', 5, 'Five passive result for five checks performed');
+for (0, 1, 2, 3, 4) {
+ if ($pasv[$_]) {
+ my $ret = $_;
+ $ret = 9 if ($_ == 4);
+ like($pasv[$_], '/^\[\d+\] PROCESS_SERVICE_CHECK_RESULT;flint;c' . $_ . ';' . $ret . ';' . $response_re[$_] . '$/', "proper result for passive check $_");
+ } else {
+ fail("proper result for passive check $_");
+ }
+}
+unlink("/tmp/check_by_ssh.$$") or die("Unable to unlink '/tmp/check_by_ssh.$$': $!");
+
diff --git a/plugins/t/check_cluster.t b/plugins/t/check_cluster.t
new file mode 100644
index 0000000..4736f06
--- /dev/null
+++ b/plugins/t/check_cluster.t
@@ -0,0 +1,82 @@
+#! /usr/bin/perl -w -I ..
+#
+# check_cluster tests
+#
+#
+
+use strict;
+use Test::More tests => 15;
+use NPTest;
+
+my $result;
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0:0 -c 0:0 -d 0,0,0,0"
+ );
+cmp_ok( $result->return_code, '==', 0, "Exit OK if non-ok services are inside critical and warning ranges" );
+like( $result->output, qr/service/i, "Output contains the word 'service' (case insensitive)");
+
+$result = NPTest->testCmd(
+ "./check_cluster -l LABEL -s -w 0:0 -c 0:0 -d 0,0,0,0"
+ );
+like( $result->output, qr/LABEL/, "Output contains the defined label 'LABEL' (case sensitive)");
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0:0 -c 0:1 -d 0,0,0,1"
+ );
+cmp_ok( $result->return_code, '==', 1, "Exit WARNING if non-ok services are inside critical and outside warning ranges" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0:0 -c 0:1 -d 0,0,1,1"
+ );
+cmp_ok( $result->return_code, '==', 2, "Exit CRITICAL if non-ok services are inside critical and outside warning ranges" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0 -c 0 -d 0,0,0,0"
+ );
+cmp_ok( $result->return_code, '==', 0, "Exit OK if non-ok services are inside critical and warning (no ranges)" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0 -c 1 -d 0,0,1,0"
+ );
+cmp_ok( $result->return_code, '==', 1, "Exit WARNING if number of non-ok services exceed warning (no ranges)" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -s -w 0 -c 1 -d 0,0,1,1"
+ );
+cmp_ok( $result->return_code, '==', 2, "Exit Critical if non-ok services exceed critical warning (no ranges)" );
+
+
+#
+# And for hosts..
+#
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0:0 -c 0:0 -d 0,0,0,0"
+ );
+cmp_ok( $result->return_code, '==', 0, "Exit OK if non-ok hosts are inside critical and warning ranges" );
+like( $result->output, qr/host/i, "Output contains the word 'host' (case insensitive)");
+
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0:0 -c 0:1 -d 0,0,0,1"
+ );
+cmp_ok( $result->return_code, '==', 1, "Exit WARNING if non-ok hosts are inside critical and outside warning ranges" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0:0 -c 0:1 -d 0,0,1,1"
+ );
+cmp_ok( $result->return_code, '==', 2, "Exit CRITICAL if non-ok hosts are inside critical and outside warning ranges" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0 -c 0 -d 0,0,0,0"
+ );
+cmp_ok( $result->return_code, '==', 0, "Exit OK if non-ok hosts are inside critical and warning (no ranges)" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0 -c 1 -d 0,0,1,0"
+ );
+cmp_ok( $result->return_code, '==', 1, "Exit WARNING if number of non-ok hosts exceed warning (no ranges)" );
+
+$result = NPTest->testCmd(
+ "./check_cluster -h -w 0 -c 1 -d 0,0,1,1"
+ );
+cmp_ok( $result->return_code, '==', 2, "Exit Critical if non-ok hosts exceed critical warning (no ranges)" );
diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t
new file mode 100644
index 0000000..eae98cc
--- /dev/null
+++ b/plugins/t/check_curl.t
@@ -0,0 +1,213 @@
+#! /usr/bin/perl -w -I ..
+#
+# HyperText Transfer Protocol (HTTP) Test via check_curl
+#
+#
+
+use strict;
+use Test::More;
+use POSIX qw/mktime strftime/;
+
+use vars qw($tests $has_ipv6);
+
+BEGIN {
+ use NPTest;
+ $has_ipv6 = NPTest::has_ipv6();
+ $tests = $has_ipv6 ? 59 : 57;
+ plan tests => $tests;
+}
+
+
+my $successOutput = '/OK.*HTTP.*second/';
+
+my $res;
+my $plugin = 'check_http';
+$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
+
+my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
+my $host_tcp_http_ipv6 = getTestParameter("NP_HOST_TCP_HTTP_IPV6", "An IPv6 address providing a HTTP Service (a web server)", "::1");
+my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
+my $host_tls_cert = getTestParameter("NP_HOST_TLS_CERT", "the common name of the certificate.", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
+my $host_tcp_http2 = getTestParameter("NP_HOST_TCP_HTTP2", "A host providing an index page containing the string 'monitoring'", "test.monitoring-plugins.org");
+my $host_tcp_proxy = getTestParameter("NP_HOST_TCP_PROXY", "A host providing a HTTP proxy with CONNECT support", "localhost");
+my $port_tcp_proxy = getTestParameter("NP_PORT_TCP_PROXY", "Port of the proxy with HTTP and CONNECT support", "3128");
+
+my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
+
+
+$res = NPTest->testCmd(
+ "./$plugin $host_tcp_http -wt 300 -ct 600"
+ );
+cmp_ok( $res->return_code, '==', 0, "Webserver $host_tcp_http responded" );
+like( $res->output, $successOutput, "Output OK" );
+
+if ($has_ipv6) {
+ # Test for IPv6 formatting
+ $res = NPTest->testCmd(
+ "./$plugin -I $host_tcp_http_ipv6 -wt 300 -ct 600"
+ );
+ cmp_ok( $res->return_code, '==', 0, "IPv6 URL formatting is working" );
+ like( $res->output, $successOutput, "Output OK" );
+}
+
+$res = NPTest->testCmd(
+ "./$plugin $host_tcp_http -wt 300 -ct 600 -v -v -v -k 'bob:there' -k 'carl:frown'"
+ );
+like( $res->output, '/bob:there\r\ncarl:frown\r\n/', "Got headers with multiple -k options" );
+
+$res = NPTest->testCmd(
+ "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
+ );
+cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
+# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
+like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK");
+
+$res = NPTest->testCmd(
+ "./$plugin $hostname_invalid -wt 1 -ct 2"
+ );
+cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" );
+# The first part of the message comes from the OS catalogue, so cannot check this.
+# On Debian, it is Name or service not known, on Darwin, it is No address associated with nodename
+# Is also possible to get a socket timeout if DNS is not responding fast enough
+# cURL gives us consistent strings from it's own 'lib/strerror.c'
+like( $res->output, "/cURL returned 6 - Could not resolve host:/", "Output OK");
+
+# host header checks
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http");
+like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80 -k 'Host: testhost:8001'");
+like( $res->output, '/^Host: testhost:8001\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+$res = NPTest->testCmd("./$plugin -v -I $host_tcp_http -p 80 -k 'Host: testhost:8001'");
+like( $res->output, '/^Host: testhost:8001\s*$/ms', "Host Header OK" );
+like( $res->output, '/CURLOPT_URL: http:\/\/'.$host_tcp_http.':80\//ms', "Url OK" );
+
+SKIP: {
+ skip "No internet access", 4 if $internet_access eq "no";
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -S");
+ like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:8080 -S -p 443");
+ like( $res->output, '/^Host: '.$host_tls_http.':8080\s*$/ms', "Host Header OK" );
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:443 -S -p 443");
+ like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -D -S -p 443");
+ like( $res->output, '/(^Host: '.$host_tls_http.'\s*$)|(cURL returned 60)/ms', "Host Header OK" );
+};
+
+SKIP: {
+ skip "No host serving monitoring in index file", 7 unless $host_tcp_http2;
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring'" );
+ cmp_ok( $res->return_code, "==", 0, "Got a reference to 'monitoring'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
+ cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
+ like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
+ cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
+ cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
+ like ( $res->output, "/pattern found/", "Error message says 'pattern found'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
+ cmp_ok( $res->return_code, "==", 0, "And also when not found");
+}
+SKIP: {
+ skip "No internet access", 28 if $internet_access eq "no";
+
+ $res = NPTest->testCmd(
+ "./$plugin --ssl $host_tls_http"
+ );
+ cmp_ok( $res->return_code, '==', 0, "Can read https for $host_tls_http" );
+
+ $res = NPTest->testCmd( "./$plugin -C 1 --ssl $host_tls_http" );
+ cmp_ok( $res->return_code, '==', 0, "Checking certificate for $host_tls_http");
+ like ( $res->output, "/Certificate '$host_tls_cert' will expire on/", "Output OK" );
+ my $saved_cert_output = $res->output;
+
+ $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
+ cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
+ like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
+
+ $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
+ is( $res->return_code, 0, "Old syntax for cert checking okay" );
+ is( $res->output, $saved_cert_output, "Same output as new syntax" );
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
+ is( $res->return_code, 0, "Updated syntax for cert checking okay" );
+ is( $res->output, $saved_cert_output, "Same output as new syntax" );
+
+ $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
+ cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
+
+ $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
+ cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
+
+ # run some certificate checks with faketime
+ SKIP: {
+ skip "No faketime binary found", 12 if !$faketime;
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output");
+ is( $res->return_code, 0, "Catch cert output exit code" );
+ my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
+ if(!defined $year) {
+ die("parsing date failed from: ".$res->output);
+ }
+ my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
+ my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
+ my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date");
+ is( $res->return_code, 2, "Output on expire date" );
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
+ is( $res->return_code, 2, "cert expires in 1 second exit code" );
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
+ is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
+ is( $res->return_code, 2, "cert expires in 2 hours exit code" );
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output");
+ is( $res->return_code, 2, "Certificate expired exit code" );
+ };
+
+ $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
+ like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
+ like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
+
+ $res = NPTest->testCmd( "./$plugin -H www.mozilla.com -u /firefox -f curl" );
+ is( $res->return_code, 0, "Redirection based on location is okay");
+
+ $res = NPTest->testCmd( "./$plugin -H www.mozilla.com --extended-perfdata" );
+ like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
+}
diff --git a/plugins/t/check_dbi.t b/plugins/t/check_dbi.t
new file mode 100644
index 0000000..c24b5a8
--- /dev/null
+++ b/plugins/t/check_dbi.t
@@ -0,0 +1,103 @@
+#! /usr/bin/perl -w -I ..
+#
+# Database Server Tests via check_dbi
+#
+#
+# Uses the 'sqlite3' DBD driver and command line utility.
+
+use strict;
+use Test::More;
+use NPTest;
+
+use File::Temp;
+
+use vars qw($tests);
+
+plan skip_all => "check_dbi not compiled" unless (-x "check_dbi");
+
+$tests = 20;
+plan tests => $tests;
+
+my $missing_driver_output = "failed to open DBI driver 'sqlite3'";
+
+my $bad_driver_output = "/failed to open DBI driver 'nodriver'/";
+my $conn_time_output = "/OK - connection time: [0-9\.]+s \|/";
+my $missing_query_output = "/Must specify a query to execute/";
+my $no_rows_output = "/WARNING - no rows returned/";
+my $not_numeric_output = "/CRITICAL - result value is not a numeric:/";
+my $query_time_output = "/OK - connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/";
+my $syntax_error_output = "/CRITICAL - failed to execute query 'GET ALL FROM test': 1: near \"GET\": syntax error/";
+
+my $result;
+
+SKIP: {
+ my $sqlite3 = qx(which sqlite3 2> /dev/null);
+ chomp($sqlite3);
+
+ skip "No Sqlite3 found", $tests unless $sqlite3;
+
+ my $sqlite3_check = qx(./check_dbi -d sqlite3 -q '');
+ if ($sqlite3_check =~ m/$missing_driver_output/) {
+ skip "No 'sqlite3' DBD driver found", $tests;
+ }
+
+ my $fh = File::Temp->new(
+ TEMPLATE => "/tmp/check_dbi_sqlite3.XXXXXXX",
+ UNLINK => 1,
+ );
+ my $filename = $fh->filename;
+ $filename =~ s/^\/tmp\///;
+
+ system("$sqlite3 /tmp/$filename 'CREATE TABLE test(a INT, b TEXT)'");
+ system("$sqlite3 /tmp/$filename 'INSERT INTO test VALUES (1, \"text1\")'");
+ system("$sqlite3 /tmp/$filename 'INSERT INTO test VALUES (2, \"text2\")'");
+
+ my $check_cmd = "./check_dbi -d sqlite3 -o sqlite3_dbdir=/tmp -o dbname=$filename";
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT 1'");
+ cmp_ok($result->return_code, '==', 0, "Sqlite3 login okay and can run query");
+
+ $result = NPTest->testCmd("$check_cmd");
+ cmp_ok($result->return_code, '==', 3, "Missing query parameter");
+ like($result->output, $missing_query_output, "Missing query parameter error message");
+
+ $result = NPTest->testCmd("$check_cmd -q 'GET ALL FROM test'");
+ cmp_ok($result->return_code, '==', 2, "Invalid query");
+ like($result->output, $syntax_error_output, "Syntax error message");
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT 2.71828' -w 2 -c 3");
+ cmp_ok($result->return_code, '==', 1, "Got warning");
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT 3.1415' -w 2 -c 3");
+ cmp_ok($result->return_code, '==', 2, "Got critical");
+
+ $result = NPTest->testCmd("$check_cmd -q ''");
+ cmp_ok($result->return_code, '==', 1, "No rows returned");
+ like($result->output, $no_rows_output, "Now rows returned warning message");
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT b FROM test'");
+ cmp_ok($result->return_code, '==', 2, "Value is not a numeric");
+ like($result->output, $not_numeric_output, "Value is not a numeric error message");
+
+ $result = NPTest->testCmd("$check_cmd -m QUERY_RESULT -q 'SELECT b FROM test' -e text1");
+ cmp_ok($result->return_code, '==', 0, "Query result string comparison okay");
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT b FROM test' -r 'eXt[0-9]'");
+ cmp_ok($result->return_code, '==', 2, "Query result case-insensitive regex failure");
+
+ $result = NPTest->testCmd("$check_cmd -q 'SELECT b FROM test' -R 'eXt[0-9]'");
+ cmp_ok($result->return_code, '==', 0, "Query result case-sensitive regex okay");
+
+ $result = NPTest->testCmd("$check_cmd -m CONN_TIME -w 0.5 -c 0.7");
+ cmp_ok($result->return_code, '==', 0, "CONN_TIME metric okay");
+ like($result->output, $conn_time_output, "CONN_TIME metric output okay");
+
+ $result = NPTest->testCmd("$check_cmd -m QUERY_TIME -q 'SELECT 1'");
+ cmp_ok($result->return_code, '==', 0, "QUERY_TIME metric okay");
+ like($result->output, $query_time_output, "QUERY_TIME metric output okay");
+
+ $result = NPTest->testCmd("./check_dbi -d nodriver -q ''");
+ cmp_ok($result->return_code, '==', 3, "Unknown DBI driver");
+ like($result->output, $bad_driver_output, "Correct error message");
+}
+
diff --git a/plugins/t/check_dig.t b/plugins/t/check_dig.t
new file mode 100644
index 0000000..3ed6cc8
--- /dev/null
+++ b/plugins/t/check_dig.t
@@ -0,0 +1,98 @@
+#! /usr/bin/perl -w -I ..
+#
+# Domain Name Server (DNS) Tests via check_dig
+#
+#
+
+use strict;
+use Test::More;
+
+
+use vars qw($tests $has_ipv6);
+BEGIN {
+ plan skip_all => "check_dig not compiled" unless (-x "check_dig");
+ use NPTest;
+ $has_ipv6 = NPTest::has_ipv6();
+ $tests = $has_ipv6 ? 16 : 14;
+ plan tests => $tests;
+}
+
+my $successOutput = '/DNS OK - [\.0-9]+ seconds? response time/';
+
+my $hostname_valid = getTestParameter(
+ "NP_HOSTNAME_VALID",
+ "A valid (known to DNS) hostname",
+ "orwell.monitoring-plugins.org"
+ );
+
+my $hostname_valid_ip = getTestParameter(
+ "NP_HOSTNAME_VALID_IP",
+ "The IP address of the valid hostname $hostname_valid",
+ "130.133.8.40",
+ );
+
+my $hostname_valid_reverse = getTestParameter(
+ "NP_HOSTNAME_VALID_REVERSE",
+ "The hostname of $hostname_valid_ip",
+ "orwell.monitoring-plugins.org.",
+ );
+
+my $hostname_invalid = getTestParameter(
+ "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost.monitoring-plugins.org",
+ );
+
+my $dns_server = getTestParameter(
+ "NP_DNS_SERVER",
+ "A non default (remote) DNS server",
+ );
+
+my $res;
+
+SKIP: {
+ skip "check_dig.t: not enough parameters given",
+ 12 unless ($hostname_valid && $hostname_valid_ip && $hostname_valid_reverse && $hostname_invalid && $dns_server);
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5");
+ cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid");
+ like ( $res->output, $successOutput, "Output OK" );
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5 -w 0.000001 -c 0.00001");
+ cmp_ok( $res->return_code, '==', 2, "Critical threshold passed");
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5 -w 0.000001 -c 5");
+ cmp_ok( $res->return_code, '==', 1, "Warning threshold passed");
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -t 1");
+ cmp_ok( $res->return_code, '==', 3, "Invalid command line -l missing");
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_invalid -t 1");
+ cmp_ok( $res->return_code, '==', 2, "Invalid $hostname_invalid");
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5");
+ cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid on $dns_server");
+ like ( $res->output, $successOutput, "Output OK" );
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5 -4");
+ cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid on $dns_server");
+ like ( $res->output, $successOutput, "Output OK for IPv4" );
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -a $hostname_valid_ip -t 5");
+ cmp_ok( $res->return_code, '==', 0, "Got expected address");
+
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -a 10.10.10.10 -t 5");
+ cmp_ok( $res->return_code, '==', 1, "Got wrong address");
+
+ my $ip_reverse = $hostname_valid_ip;
+ $ip_reverse =~ s/(\d+)\.(\d+)\.(\d+)\.(\d+)/$4.$3.$2.$1.in-addr.arpa/;
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $ip_reverse -a $hostname_valid_reverse -T PTR -t 5");
+ cmp_ok( $res->return_code, '==', 0, "Got expected fqdn");
+ like ( $res->output, $successOutput, "Output OK");
+
+ if($has_ipv6) {
+ $res = NPTest->testCmd("./check_dig -H $dns_server -l $hostname_valid -t 5 -6");
+ cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid on $dns_server");
+ like ( $res->output, $successOutput, "Output OK for IPv6" );
+ }
+}
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
new file mode 100644
index 0000000..ca035ce
--- /dev/null
+++ b/plugins/t/check_disk.t
@@ -0,0 +1,378 @@
+#! /usr/bin/perl -w -I ..
+#
+# Disk Space Tests via check_disk
+#
+#
+
+# TODO: Add in tests for perf data. Need to beef up Monitoring::Plugin::Performance to cater for max, min, etc
+
+use strict;
+use Test::More;
+use NPTest;
+use POSIX qw(ceil floor);
+
+my $successOutput = '/^DISK OK/';
+my $failureOutput = '/^DISK CRITICAL/';
+my $warningOutput = '/^DISK WARNING/';
+
+my $result;
+
+my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
+my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
+
+if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
+ plan skip_all => "Need 2 mountpoints to test";
+} else {
+ plan tests => 88;
+}
+
+$result = NPTest->testCmd(
+ "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid"
+ );
+cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
+my $c = 0;
+$_ = $result->output;
+$c++ while /\(/g; # counts number of "(" - should be two
+cmp_ok( $c, '==', 2, "Got two mountpoints in output");
+
+
+# Get perf data
+# Should use Monitoring::Plugin
+my @perf_data = sort(split(/ /, $result->perf_output));
+
+
+# Calculate avg_free free on mountpoint1 and mountpoint2
+# because if you check in the middle, you should get different errors
+$_ = $result->output;
+my ($free_on_mp1, $free_on_mp2) = (m/\((\d+)%.*\((\d+)%/);
+die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
+my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
+my ($more_free, $less_free);
+if ($free_on_mp1 > $free_on_mp2) {
+ $more_free = $mountpoint_valid;
+ $less_free = $mountpoint2_valid;
+} elsif ($free_on_mp1 < $free_on_mp2) {
+ $more_free = $mountpoint2_valid;
+ $less_free = $mountpoint_valid;
+} else {
+ die "Two mountpoints are the same - cannot do rest of test";
+}
+if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) {
+ die "One mountpoints has average space free - cannot do rest of test";
+}
+
+
+# Do same for inodes
+$_ = $result->output;
+my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/);
+die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2);
+my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2);
+my ($more_inode_free, $less_inode_free);
+if ($free_inode_on_mp1 > $free_inode_on_mp2) {
+ $more_inode_free = $mountpoint_valid;
+ $less_inode_free = $mountpoint2_valid;
+} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) {
+ $more_inode_free = $mountpoint2_valid;
+ $less_inode_free = $mountpoint_valid;
+} else {
+ die "Two mountpoints with same inodes free - cannot do rest of test";
+}
+if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) {
+ die "One mountpoints has average inodes free - cannot do rest of test";
+}
+
+# Verify performance data
+# First check absolute thresholds...
+$result = NPTest->testCmd(
+ "./check_disk -w 20 -c 10 -p $mountpoint_valid"
+ );
+$_ = $result->perf_output;
+my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
+# default unit is MiB, but perfdata is always bytes
+is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds");
+is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds");
+
+# Then check percent thresholds.
+$result = NPTest->testCmd(
+ "./check_disk -w 20% -c 10% -p $mountpoint_valid"
+ );
+$_ = $result->perf_output;
+my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
+is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds");
+is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds");
+
+
+# Check when order of mount points are reversed, that perf data remains same
+$result = NPTest->testCmd(
+ "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid"
+ );
+@_ = sort(split(/ /, $result->perf_output));
+is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
+
+
+# Basic filesystem checks for sizes
+$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" );
+cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free");
+like ( $result->output, $successOutput, "OK output" );
+like ( $result->only_output, qr/free space/, "Have free space text");
+like ( $result->only_output, qr/$more_free/, "Have disk name in text");
+
+$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" );
+cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free");
+$_ = $result->output;
+my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
+my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
+
+
+
+$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" );
+is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs");
+
+$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
+cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
+
+$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
+cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
+
+$result = NPTest->testCmd(
+ "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free"
+ );
+cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" );
+like( $result->output, $failureOutput, "Right output" );
+
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c 0% -p $less_free"
+ );
+cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free");
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c $avg_free% -p $more_free"
+ );
+cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
+ );
+cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
+my $all_disks = $result->output;
+
+$result = NPTest->testCmd(
+ "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
+ );
+isnt( $result->output, $all_disks, "-e gives different output");
+
+# Need spaces around filesystem name in case less_free and more_free are nested
+like( $result->output, qr/ $less_free /, "Found problem $less_free");
+unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
+like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data");
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c 0% -p $more_free"
+ );
+cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c $avg_free% -p $less_free"
+ );
+cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free"
+ );
+cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
+
+$result = NPTest->testCmd(
+ "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free"
+ );
+cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
+
+
+
+# Basic inode checks for sizes
+
+$result = NPTest->testCmd( "./check_disk --icritical 1% --iwarning 1% -p $more_inode_free" );
+is( $result->return_code, 0, "At least 1% free on inodes for both mountpoints");
+
+$result = NPTest->testCmd( "./check_disk -K 100% -W 100% -p $less_inode_free" );
+is( $result->return_code, 2, "Critical requesting 100% free inodes for both mountpoints");
+
+$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
+is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" );
+is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free ");
+is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
+is ($result->return_code, 1, "Combine above two tests, get warning");
+$all_disks = $result->output;
+
+$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
+isnt( $result->output, $all_disks, "-e gives different output");
+like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
+unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
+like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" );
+is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
+is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
+is( $result->return_code, 2, "Combining above two tests, get critical");
+
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" );
+cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
+
+
+
+
+
+
+TODO: {
+ local $TODO = "Invalid percent figures";
+ $result = NPTest->testCmd(
+ "./check_disk -w 10% -c 15% -p $mountpoint_valid"
+ );
+ cmp_ok( $result->return_code, '==', 3, "Invalid command line options" );
+}
+
+$result = NPTest->testCmd(
+ "./check_disk -p $mountpoint_valid -w 10% -c 15%"
+ );
+cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
+
+$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty
+cmp_ok( $result->return_code, "==", 2, "100% empty" );
+like( $result->output, $failureOutput, "Right output" );
+
+$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
+cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
+
+$result = NPTest->testCmd( "./check_disk -w 100 -c 100 -u TB ".${mountpoint_valid} ); # 100 TB empty
+cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
+
+
+# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
+$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
+cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
+like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
+
+$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
+cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
+
+$result = NPTest->testCmd( "./check_disk 0 100 $mountpoint_valid" );
+cmp_ok( $result->return_code, '==', 1, "Old syntax: warn 0% used" );
+
+TODO: {
+ local $TODO = "Invalid values";
+ $result = NPTest->testCmd( "./check_disk 0 200 $mountpoint_valid" );
+ cmp_ok( $result->return_code, '==', 3, "Old syntax: Error with values outside percent range" );
+
+ $result = NPTest->testCmd( "./check_disk 200 200 $mountpoint_valid" );
+ cmp_ok( $result->return_code, '==', 3, "Old syntax: Error with values outside percent range" );
+
+ $result = NPTest->testCmd( "./check_disk 200 0 $mountpoint_valid" );
+ cmp_ok( $result->return_code, '==', 3, "Old syntax: Error with values outside percent range" );
+}
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p /bob" );
+cmp_ok( $result->return_code, '==', 2, "Checking /bob - return error because /bob does not exist" );
+like( $result->output, '/^DISK CRITICAL - /bob is not accessible:.*$/', 'Output OK');
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p /" );
+my $root_output = $result->output;
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p /etc" );
+cmp_ok( $result->return_code, '==', 0, "Checking /etc - should return info for /" );
+cmp_ok( $result->output, 'eq', $root_output, "check_disk /etc gives same as check_disk /");
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -E -p /etc " );
+cmp_ok( $result->return_code, '==', 2, "... unless -E/--exact-match is specified");
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p /etc -E " );
+cmp_ok( $result->return_code, '==', 3, "-E/--exact-match must be specified before -p");
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -r /etc -E " );
+cmp_ok( $result->return_code, '==', 3, "-E/--exact-match must be specified before -r");
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /bob" );
+cmp_ok( $result->return_code, '==', 2, "Checking / and /bob gives critical");
+unlike( $result->perf_output, '/\/bob/', "perf data does not have /bob in it");
+
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
+unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
+
+# are partitions added if -C is given without path selection -p ?
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" );
+like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given");
+
+# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
+$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ."-g group -p $mountpoint_valid -p $mountpoint2_valid" );
+cmp_ok( $result->return_code, '==', 2, "grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit");
+
+# grouping: exit warning if the sum of free megs on mp1+mp2 is between -w and -c
+$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all - 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
+cmp_ok( $result->return_code, '==', 1, "grouping: exit warning if the sum of free megs on mp1+mp2 is between -w and -c ");
+
+# grouping: exit ok if the sum of free megs on mp1+mp2 is more than warn/crit
+$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all - 1) ." -c ". ($free_mb_on_all - 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
+cmp_ok( $result->return_code, '==', 0, "grouping: exit ok if the sum of free megs on mp1+mp2 is more than warn/crit");
+
+# grouping: exit unknown if group name is given after -p
+$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all - 1) ." -c ". ($free_mb_on_all - 1) ." -p $mountpoint_valid -g group -p $mountpoint2_valid" );
+cmp_ok( $result->return_code, '==', 3, "Invalid options: -p must come after groupname");
+
+# regex: exit unknown if given regex is not compilable
+$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -r '('" );
+cmp_ok( $result->return_code, '==', 3, "Exit UNKNOWN if regex is not compilable");
+
+# ignore: exit unknown, if all paths are deselected using -i
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '$mountpoint_valid' -i '$mountpoint2_valid'" );
+cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case sensitive)");
+
+# ignore: exit unknown, if all paths are deselected using -I
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -I '".uc($mountpoint_valid)."' -I '".uc($mountpoint2_valid)."'" );
+cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored (case insensitive)");
+
+# ignore: exit unknown, if all paths are deselected using -i
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '.*'" );
+cmp_ok( $result->return_code, '==', 3, "ignore-ereg: Unknown if all fs are ignored using -i '.*'");
+
+# ignore: test if ignored path is actually ignored
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '^$mountpoint2_valid\$'");
+like( $result->output, qr/$mountpoint_valid/, "output data does have $mountpoint_valid in it");
+unlike( $result->output, qr/$mountpoint2_valid/, "output data does not have $mountpoint2_valid in it");
+
+# ignore: test if all paths are listed when ignore regex doesn't match
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p $mountpoint_valid -p $mountpoint2_valid -i '^barbazJodsf\$'");
+like( $result->output, qr/$mountpoint_valid/, "ignore: output data does have $mountpoint_valid when regex doesn't match");
+like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mountpoint2_valid when regex doesn't match");
+
+# ignore-missing: exit okay, when fs is not accessible
+$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
+cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
+like( $result->output, '/^DISK OK - No disks were found for provided parameters; - ignored paths: /bob;.*$/', 'Output OK');
+
+# ignore-missing: exit okay, when regex does not match
+$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
+cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
+like( $result->output, '/^DISK OK - No disks were found for provided parameters;.*$/', 'Output OK');
+
+# ignore-missing: exit okay, when fs with exact match (-E) is not found
+$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
+cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
+like( $result->output, '/^DISK OK - No disks were found for provided parameters; - ignored paths: /etc;.*$/', 'Output OK');
+
+# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
+$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
+cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
+like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
+
+# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
+$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
+cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
+like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); \ No newline at end of file
diff --git a/plugins/t/check_dns.t b/plugins/t/check_dns.t
new file mode 100644
index 0000000..afb2062
--- /dev/null
+++ b/plugins/t/check_dns.t
@@ -0,0 +1,115 @@
+#! /usr/bin/perl -w -I ..
+#
+# Domain Name Server (DNS) Tests via check_dns
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan skip_all => "check_dns not compiled" unless (-x "check_dns");
+
+plan tests => 23;
+
+my $successOutput = '/DNS OK: [\.0-9]+ seconds? response time/';
+
+my $hostname_valid = getTestParameter(
+ "NP_HOSTNAME_VALID",
+ "A valid (known to DNS) hostname",
+ "monitoring-plugins.org",
+ );
+
+my $hostname_valid_ip = getTestParameter(
+ "NP_HOSTNAME_VALID_IP",
+ "The IP address of the valid hostname $hostname_valid",
+ "130.133.8.40",
+ );
+
+my $hostname_valid_cidr = getTestParameter(
+ "NP_HOSTNAME_VALID_CIDR",
+ "An valid CIDR range containing $hostname_valid_ip",
+ "130.133.8.41/30",
+ );
+
+my $hostname_invalid_cidr = getTestParameter(
+ "NP_HOSTNAME_INVALID_CIDR",
+ "An (valid) CIDR range NOT containing $hostname_valid_ip",
+ "130.133.8.39/30",
+ );
+
+my $hostname_valid_reverse = getTestParameter(
+ "NP_HOSTNAME_VALID_REVERSE",
+ "The hostname of $hostname_valid_ip",
+ "orwell.monitoring-plugins.org.",
+ );
+
+my $hostname_invalid = getTestParameter(
+ "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost.altinity.com",
+ );
+
+my $dns_server = getTestParameter(
+ "NP_DNS_SERVER",
+ "A non default (remote) DNS server",
+ );
+
+my $host_nonresponsive = getTestParameter(
+ "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests",
+ "10.0.0.1",
+ );
+
+my $res;
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -t 5");
+cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid");
+like ( $res->output, $successOutput, "Output OK" );
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -t 5 -w 0 -c 0");
+cmp_ok( $res->return_code, '==', 2, "Critical threshold passed");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -t 5 -w 0 -c 5");
+cmp_ok( $res->return_code, '==', 1, "Warning threshold passed");
+like( $res->output, '/\|time=[\d\.]+s;0.0*;5\.0*;0\.0*/', "Output performance data OK" );
+
+$res = NPTest->testCmd("./check_dns -H $hostname_invalid -t 1");
+cmp_ok( $res->return_code, '==', 2, "Invalid $hostname_invalid");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -s $dns_server -t 5");
+cmp_ok( $res->return_code, '==', 0, "Found $hostname_valid on $dns_server");
+like ( $res->output, $successOutput, "Output OK" );
+
+$res = NPTest->testCmd("./check_dns -H $hostname_invalid -s $dns_server -t 1");
+cmp_ok( $res->return_code, '==', 2, "Invalid $hostname_invalid on $dns_server");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_valid_ip -s $host_nonresponsive -t 2");
+cmp_ok( $res->return_code, '==', 2, "Got no answer from unresponsive server");
+like ( $res->output, "/CRITICAL - /", "Output OK");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_valid_ip -t 5");
+cmp_ok( $res->return_code, '==', 0, "Got expected address");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -a 10.10.10.10 -t 5");
+cmp_ok( $res->return_code, '==', 2, "Got wrong address");
+like ( $res->output, "/^DNS CRITICAL.*expected '10.10.10.10' but got '$hostname_valid_ip'".'$/', "Output OK");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid_ip -a $hostname_valid_reverse -t 5");
+cmp_ok( $res->return_code, '==', 0, "Got expected fqdn");
+like ( $res->output, $successOutput, "Output OK");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_valid_cidr -t 5");
+cmp_ok( $res->return_code, '==', 0, "Got expected address");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -a $hostname_invalid_cidr -t 5");
+cmp_ok( $res->return_code, '==', 2, "Got wrong address");
+like ( $res->output, "/^DNS CRITICAL.*expected '$hostname_invalid_cidr' but got '$hostname_valid_ip'".'$/', "Output OK");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_valid -n");
+cmp_ok( $res->return_code, '==', 2, "Found $hostname_valid");
+like ( $res->output, "/^DNS CRITICAL.*Domain '$hostname_valid' was found by the server:/", "Output OK");
+
+$res = NPTest->testCmd("./check_dns -H $hostname_invalid -n");
+cmp_ok( $res->return_code, '==', 0, "Did not find $hostname_invalid");
+like ( $res->output, $successOutput, "Output OK" );
diff --git a/plugins/t/check_dummy.t b/plugins/t/check_dummy.t
new file mode 100644
index 0000000..15fc157
--- /dev/null
+++ b/plugins/t/check_dummy.t
@@ -0,0 +1,54 @@
+#! /usr/bin/perl -w -I ..
+#
+# check_dummy tests
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan tests => 20;
+
+my $res;
+
+$res = NPTest->testCmd("./check_dummy");
+is( $res->return_code, 3, "No args" );
+like( $res->output, "/Could not parse arguments/", "Correct usage message");
+
+$res = NPTest->testCmd("./check_dummy 0");
+is( $res->return_code, 0, "OK state returned");
+is( $res->output, "OK", "Says 'OK'");
+
+$res = NPTest->testCmd("./check_dummy 0 'some random data'");
+is( $res->return_code, 0, "Still OK");
+is( $res->output, "OK: some random data", "Sample text okay");
+
+$res = NPTest->testCmd("./check_dummy 1");
+is( $res->return_code, 1, "Warning okay");
+is( $res->output, "WARNING", "Says 'WARNING'");
+
+$res = NPTest->testCmd("./check_dummy 1 'more stuff'");
+is( $res->return_code, 1, "Still warning");
+is( $res->output, "WARNING: more stuff", "optional text okay" );
+
+$res = NPTest->testCmd("./check_dummy 2");
+is( $res->return_code, 2, "Critical ok" );
+is( $res->output, "CRITICAL", "Says 'CRITICAL'");
+
+$res = NPTest->testCmd("./check_dummy 2 'roughly drafted'");
+is( $res->return_code, 2, "Still critical");
+is( $res->output, "CRITICAL: roughly drafted", "optional text okay" );
+
+$res = NPTest->testCmd("./check_dummy 3");
+is( $res->return_code, 3, "Unknown ok" );
+is( $res->output, "UNKNOWN", "Says 'UNKNOWN'");
+
+$res = NPTest->testCmd("./check_dummy 3 'daringfireball'");
+is( $res->return_code, 3, "Still unknown");
+is( $res->output, "UNKNOWN: daringfireball", "optional text okay" );
+
+$res = NPTest->testCmd("./check_dummy 4");
+is( $res->return_code, 3, "Invalid error code" );
+is( $res->output, "UNKNOWN: Status 4 is not a supported error state", "With appropriate error message");
+
diff --git a/plugins/t/check_fping.t b/plugins/t/check_fping.t
new file mode 100644
index 0000000..67b357b
--- /dev/null
+++ b/plugins/t/check_fping.t
@@ -0,0 +1,34 @@
+#! /usr/bin/perl -w -I ..
+#
+# FPing Tests via check_fping
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my $host_responsive = getTestParameter("NP_HOST_RESPONSIVE", "The hostname of system responsive to network requests", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+my $res;
+
+my $fping = qx(which fping 2> /dev/null);
+chomp($fping);
+if( ! -x "./check_fping") {
+ plan skip_all => "check_fping not found, skipping tests";
+}
+elsif ( !$fping || !-x $fping ) {
+ plan skip_all => "fping not found or cannot be executed, skipping tests";
+} else {
+ plan tests => 3;
+ $res = NPTest->testCmd( "./check_fping $host_responsive" );
+ cmp_ok( $res->return_code, '==', 0, "Responsive host returns OK");
+
+ $res = NPTest->testCmd( "./check_fping $host_nonresponsive" );
+ cmp_ok( $res->return_code, '==', 2, "Non-Responsive host returns Critical");
+
+ $res = NPTest->testCmd( "./check_fping $hostname_invalid" );
+ cmp_ok( $res->return_code, '==', 3, "Invalid host returns Unknown");
+}
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
new file mode 100644
index 0000000..93a7d7c
--- /dev/null
+++ b/plugins/t/check_ftp.t
@@ -0,0 +1,28 @@
+#! /usr/bin/perl -w -I ..
+#
+# File Transfer Protocol (FTP) Test via check_ftp
+#
+#
+
+use strict;
+use Test;
+use NPTest;
+
+use vars qw($tests);
+BEGIN {$tests = 4; plan tests => $tests}
+
+my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing the FTP Service (an FTP server)", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/';
+
+my $t;
+
+$t += checkCmd( "./check_ftp $host_tcp_ftp -wt 300 -ct 600", 0, $successOutput );
+$t += checkCmd( "./check_ftp $host_nonresponsive -wt 0 -ct 0 -to 1", 2 );
+$t += checkCmd( "./check_ftp $hostname_invalid -wt 0 -ct 0", 2 );
+
+exit(0) if defined($Test::Harness::VERSION);
+exit($tests - $t);
+
diff --git a/plugins/t/check_hpjd.t b/plugins/t/check_hpjd.t
new file mode 100644
index 0000000..4d64852
--- /dev/null
+++ b/plugins/t/check_hpjd.t
@@ -0,0 +1,71 @@
+#! /usr/bin/perl -w -I ..
+#
+# HP JetDirect Test via check_hpjd
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan skip_all => "check_hpjd not compiled" unless (-x "check_hpjd");
+
+
+my $successOutput = '/^Printer ok - /';
+my $failureOutput = '/Timeout: No [Rr]esponse from /';
+
+my $host_tcp_hpjd = getTestParameter(
+ "NP_HOST_TCP_HPJD",
+ "A host (usually a printer) providing the HP-JetDirect Services"
+ );
+
+my $host_hpjd_port_invalid = getTestParameter(
+ "NP_HOST_HPJD_PORT_INVALID",
+ "A port that HP-JetDirect Services is not listening on",
+ "162"
+ );
+
+my $host_hpjd_port_valid = getTestParameter(
+ "NP_HOST_HPJD_PORT_VALID",
+ "The port that HP-JetDirect Services is currently listening on",
+ "161"
+ );
+
+my $host_nonresponsive = getTestParameter(
+ "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests",
+ "10.0.0.1"
+ );
+
+my $hostname_invalid = getTestParameter(
+ "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost"
+ );
+
+my $tests = $host_tcp_hpjd ? 9 : 5;
+plan tests => $tests;
+my $res;
+
+SKIP: {
+ skip "No HP JetDirect defined", 2 unless $host_tcp_hpjd;
+ $res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd");
+ cmp_ok( $res->return_code, 'eq', 0, "Jetdirect responding" );
+ like ( $res->output, $successOutput, "Output correct" );
+
+ $res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd -p $host_hpjd_port_valid");
+ cmp_ok( $res->return_code, 'eq', 0, "Jetdirect responding on port $host_hpjd_port_valid" );
+ like ( $res->output, $successOutput, "Output correct" );
+
+ $res = NPTest->testCmd("./check_hpjd -H $host_tcp_hpjd -p $host_hpjd_port_invalid");
+ cmp_ok( $res->return_code, 'eq', 2, "Jetdirect not responding on port $host_hpjd_port_invalid" );
+ like ( $res->output, $failureOutput, "Output correct" );
+}
+
+$res = NPTest->testCmd("./check_hpjd -H $host_nonresponsive");
+cmp_ok( $res->return_code, 'eq', 2, "Host not responding");
+like ( $res->output, $failureOutput, "Output OK" );
+
+$res = NPTest->testCmd("./check_hpjd -H $hostname_invalid");
+cmp_ok( $res->return_code, 'eq', 3, "Hostname invalid");
+
diff --git a/plugins/t/check_http.t b/plugins/t/check_http.t
new file mode 100644
index 0000000..1f2fbdf
--- /dev/null
+++ b/plugins/t/check_http.t
@@ -0,0 +1,190 @@
+#! /usr/bin/perl -w -I ..
+#
+# HyperText Transfer Protocol (HTTP) Test via check_http
+#
+#
+
+use strict;
+use Test::More;
+use POSIX qw/mktime strftime/;
+use NPTest;
+
+plan tests => 49;
+
+my $successOutput = '/OK.*HTTP.*second/';
+
+my $res;
+my $plugin = 'check_http';
+$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
+
+my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
+my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
+my $host_tls_cert = getTestParameter("NP_HOST_TLS_CERT", "the common name of the certificate.", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
+my $host_tcp_http2 = getTestParameter("NP_HOST_TCP_HTTP2", "A host providing an index page containing the string 'monitoring'", "test.monitoring-plugins.org");
+my $host_tcp_proxy = getTestParameter("NP_HOST_TCP_PROXY", "A host providing a HTTP proxy with CONNECT support", "localhost");
+my $port_tcp_proxy = getTestParameter("NP_PORT_TCP_PROXY", "Port of the proxy with HTTP and CONNECT support", "3128");
+
+my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
+
+
+$res = NPTest->testCmd(
+ "./$plugin $host_tcp_http -wt 300 -ct 600"
+ );
+cmp_ok( $res->return_code, '==', 0, "Webserver $host_tcp_http responded" );
+like( $res->output, $successOutput, "Output OK" );
+
+$res = NPTest->testCmd(
+ "./$plugin $host_tcp_http -wt 300 -ct 600 -v -v -v -k 'bob:there' -k 'carl:frown'"
+ );
+like( $res->output, '/bob:there\r\ncarl:frown\r\n/', "Got headers with multiple -k options" );
+
+$res = NPTest->testCmd(
+ "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
+ );
+cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
+cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK");
+
+$res = NPTest->testCmd(
+ "./$plugin $hostname_invalid -wt 1 -ct 2"
+ );
+cmp_ok( $res->return_code, '==', 2, "Webserver $hostname_invalid not valid" );
+# The first part of the message comes from the OS catalogue, so cannot check this.
+# On Debian, it is Name or service not known, on Darwin, it is No address associated with nodename
+# Is also possible to get a socket timeout if DNS is not responding fast enough
+like( $res->output, "/Unable to open TCP socket|Socket timeout after/", "Output OK");
+
+# host header checks
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http");
+like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.'\s*$/ms', "Host Header OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
+
+$res = NPTest->testCmd("./$plugin -v -H $host_tcp_http:8080 -p 80");
+like( $res->output, '/^Host: '.$host_tcp_http.':8080\s*$/ms', "Host Header OK" );
+
+SKIP: {
+ skip "No internet access", 3 if $internet_access eq "no";
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http -S");
+ like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:8080 -S -p 443");
+ like( $res->output, '/^Host: '.$host_tls_http.':8080\s*$/ms', "Host Header OK" );
+
+ $res = NPTest->testCmd("./$plugin -v -H $host_tls_http:443 -S -p 443");
+ like( $res->output, '/^Host: '.$host_tls_http.'\s*$/ms', "Host Header OK" );
+};
+
+SKIP: {
+ skip "No host serving monitoring in index file", 7 unless $host_tcp_http2;
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring'" );
+ cmp_ok( $res->return_code, "==", 0, "Got a reference to 'monitoring'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
+ cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
+ like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
+ cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
+ cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
+ like ( $res->output, "/pattern found/", "Error message says 'pattern found'");
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
+ cmp_ok( $res->return_code, "==", 0, "And also when not found");
+}
+SKIP: {
+ skip "No internet access", 22 if $internet_access eq "no";
+
+ $res = NPTest->testCmd(
+ "./$plugin --ssl $host_tls_http"
+ );
+ cmp_ok( $res->return_code, '==', 0, "Can read https for $host_tls_http" );
+
+ $res = NPTest->testCmd( "./$plugin -C 1 --ssl $host_tls_http" );
+ cmp_ok( $res->return_code, '==', 0, "Checking certificate for $host_tls_http");
+ like ( $res->output, "/Certificate '$host_tls_cert' will expire on/", "Output OK" );
+ my $saved_cert_output = $res->output;
+
+ $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
+ cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
+ like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
+
+ $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
+ is( $res->return_code, 0, "Old syntax for cert checking okay" );
+ is( $res->output, $saved_cert_output, "Same output as new syntax" );
+
+ $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
+ is( $res->return_code, 0, "Updated syntax for cert checking okay" );
+ is( $res->output, $saved_cert_output, "Same output as new syntax" );
+
+ $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
+ cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
+
+ $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
+ cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
+
+ # run some certificate checks with faketime
+ SKIP: {
+ skip "No faketime binary found", 7 if !$faketime;
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output");
+ is( $res->return_code, 0, "Catch cert output exit code" );
+ my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
+ if(!defined $year) {
+ die("parsing date failed from: ".$res->output);
+ }
+ my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
+ my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
+ my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date");
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
+ like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output");
+ };
+
+ $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
+ like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
+ like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
+
+ $res = NPTest->testCmd( "./$plugin -H www.mozilla.com -u /firefox -f follow" );
+ is( $res->return_code, 0, "Redirection based on location is okay");
+
+ $res = NPTest->testCmd( "./$plugin -H www.mozilla.com --extended-perfdata" );
+ like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
+}
+
+SKIP: {
+ skip "No internet access or proxy configured", 6 if $internet_access eq "no" or ! $host_tcp_proxy;
+
+ $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -u http://$host_tcp_http -e 200,301,302");
+ is( $res->return_code, 0, "Proxy HTTP works");
+ like($res->output, qr/OK: Status line output matched/, "Proxy HTTP Output is sufficient");
+
+ $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -H $host_tls_http -S -j CONNECT");
+ is( $res->return_code, 0, "Proxy HTTP CONNECT works");
+ like($res->output, qr/HTTP OK:/, "Proxy HTTP CONNECT output sufficient");
+
+ $res = NPTest->testCmd( "./$plugin -I $host_tcp_proxy -p $port_tcp_proxy -H $host_tls_http -S -j CONNECT:HEAD");
+ is( $res->return_code, 0, "Proxy HTTP CONNECT works with override method");
+ like($res->output, qr/HTTP OK:/, "Proxy HTTP CONNECT output sufficient");
+}
diff --git a/plugins/t/check_imap.t b/plugins/t/check_imap.t
new file mode 100644
index 0000000..cf2f81c
--- /dev/null
+++ b/plugins/t/check_imap.t
@@ -0,0 +1,38 @@
+#! /usr/bin/perl -w -I ..
+#
+# Internet Mail Access Protocol (IMAP) Server Tests via check_imap
+#
+#
+
+use strict;
+use Test::More tests => 7;
+use NPTest;
+
+my $host_tcp_smtp = getTestParameter("NP_HOST_TCP_SMTP", "A host providing an STMP Service (a mail server)", "mailhost");
+my $host_tcp_imap = getTestParameter("NP_HOST_TCP_IMAP", "A host providing an IMAP Service (a mail server)", $host_tcp_smtp);
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+my $t;
+
+$t = NPTest->testCmd( "./check_imap $host_tcp_imap" );
+cmp_ok( $t->return_code, '==', 0, "Contacted imap" );
+
+$t = NPTest->testCmd( "./check_imap -H $host_tcp_imap -p 143 -w 9 -c 9 -to 10 -e '* OK'" );
+cmp_ok( $t->return_code, '==', 0, "Got right response" );
+
+$t = NPTest->testCmd( "./check_imap $host_tcp_imap -p 143 -wt 9 -ct 9 -to 10 -e '* OK'" );
+cmp_ok( $t->return_code, '==', 0, "Check old parameter options" );
+
+$t = NPTest->testCmd( "./check_imap $host_nonresponsive" );
+cmp_ok( $t->return_code, '==', 2, "Get error with non responsive host" );
+
+$t = NPTest->testCmd( "./check_imap $hostname_invalid" );
+cmp_ok( $t->return_code, '==', 2, "Invalid hostname" );
+
+$t = NPTest->testCmd( "./check_imap -H $host_tcp_imap -e unlikely_string");
+cmp_ok( $t->return_code, '==', 1, "Got warning with bad response" );
+
+$t = NPTest->testCmd( "./check_imap -H $host_tcp_imap -e unlikely_string -M crit");
+cmp_ok( $t->return_code, '==', 2, "Got critical error with bad response" );
+
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
new file mode 100644
index 0000000..fcdae17
--- /dev/null
+++ b/plugins/t/check_jabber.t
@@ -0,0 +1,50 @@
+#! /usr/bin/perl -w -I ..
+#
+# Jabber Server Tests via check_jabber
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan tests => 10;
+
+my $host_tcp_jabber = getTestParameter("NP_HOST_TCP_JABBER", "A host providing the Jabber Service", "jabber.de");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+
+my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/';
+
+my $jabberUnresponsive = '/CRITICAL\s-\sSocket timeout after\s\d+\sseconds/';
+
+my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/';
+
+my $r;
+
+SKIP: {
+ skip "No jabber server defined", 6 unless $host_tcp_jabber;
+
+ $r = NPTest->testCmd( "./check_jabber -H $host_tcp_jabber" );
+ is( $r->return_code, 0, "Connected okay");
+ like( $r->output, $jabberOK, "Output as expected" );
+
+ $r = NPTest->testCmd( "./check_jabber -H $host_tcp_jabber -w 9 -c 9 -t 10" );
+ is( $r->return_code, 0, "Connected okay, within limits" );
+ like( $r->output, $jabberOK, "Output as expected" );
+
+ $r = NPTest->testCmd( "./check_jabber -H $host_tcp_jabber -wt 9 -ct 9 -to 10" );
+ is( $r->return_code, 0, "Old syntax okay" );
+ like( $r->output, $jabberOK, "Output as expected" );
+
+}
+
+$r = NPTest->testCmd( "./check_jabber $host_nonresponsive" );
+is( $r->return_code, 2, "Unresponsive host gives critical" );
+like( $r->output, $jabberUnresponsive );
+
+$r = NPTest->testCmd( "./check_jabber $hostname_invalid" );
+is( $r->return_code, 2, "Invalid hostname gives critical" );
+like( $r->output, $jabberInvalid );
+
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t
new file mode 100644
index 0000000..b8a4a76
--- /dev/null
+++ b/plugins/t/check_ldap.t
@@ -0,0 +1,71 @@
+#!/usr/bin/env perl -I ..
+#
+# Lightweight Directory Access Protocol (LDAP) Test via check_ldap
+#
+#
+
+use strict;
+use warnings;
+use Test::More;
+use NPTest;
+
+my $host_tcp_ldap = getTestParameter("NP_HOST_TCP_LDAP", "A host providing the LDAP Service", "localhost");
+my $ldap_base_dn = getTestParameter("NP_LDAP_BASE_DN", "A base dn for the LDAP Service", "cn=admin");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+my($result, $cmd);
+my $command = './check_ldap';
+
+plan tests => 16;
+
+SKIP: {
+ skip "NP_HOST_NONRESPONSIVE not set", 2 if ! $host_nonresponsive;
+
+ $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1");
+ is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" );
+ is( $result->output, 'CRITICAL - Socket timeout after 2 seconds', "output ok" );
+};
+
+SKIP: {
+ skip "NP_HOSTNAME_INVALID not set", 2 if ! $hostname_invalid;
+
+ $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5");
+ is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" );
+ is( $result->output, 'Could not bind to the LDAP server', "output ok" );
+};
+
+SKIP: {
+ skip "NP_HOST_TCP_LDAP not set", 12 if ! $host_tcp_ldap;
+ skip "NP_LDAP_BASE_DN not set", 12 if ! $ldap_base_dn;
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 0, $cmd );
+ like( $result->output, '/^LDAP OK - \d+.\d+ seconds response time\|time=\d+\.\d+s;2\.0+;3\.0+;0\.0+$/', "output ok" );
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 0, $cmd );
+ like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000;10000001;0\.0+$/', "output ok" );
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 2, $cmd );
+ like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001:;0\.0+$/', "output ok" );
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 2, $cmd );
+ like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;0;0;0\.0+$/', "output ok" );
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 1, $cmd );
+ like( $result->output, '/^LDAP WARNING - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001;0\.0+$/', "output ok" );
+
+ $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 0, $cmd );
+ like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;;10000001;0\.0+$/', "output ok" );
+};
diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t
new file mode 100644
index 0000000..bba8947
--- /dev/null
+++ b/plugins/t/check_load.t
@@ -0,0 +1,43 @@
+#! /usr/bin/perl -w -I ..
+#
+# Load Average Tests via check_load
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my $res;
+
+my $loadValue = "[0-9]+\.?[0-9]+";
+my $successOutput = "/^LOAD OK - total load average: $loadValue, $loadValue, $loadValue/";
+my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
+my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/";
+my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
+
+plan tests => 13;
+
+$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" );
+cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
+like( $res->output, $successOutput, "Output OK");
+
+$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" );
+cmp_ok( $res->return_code, 'eq', 2, "Load over 0");
+like( $res->output, $failureOutput, "Output OK");
+
+$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" );
+cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division");
+like( $res->output, $failurScaledOutput, "Output OK");
+
+$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" );
+cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments");
+like( $res->output, $successOutput, "Output OK");
+like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)");
+like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)");
+like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)");
+
+
+$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" );
+cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
+like( $res->output, $successScaledOutput, "Output OK");
diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t
new file mode 100644
index 0000000..baf3acc
--- /dev/null
+++ b/plugins/t/check_mysql.t
@@ -0,0 +1,74 @@
+#! /usr/bin/perl -w -I ..
+#
+# MySQL Database Server Tests via check_mysql
+#
+#
+#
+# These are the database permissions required for this test:
+# GRANT SELECT ON $db.* TO $user@$host IDENTIFIED BY '$password';
+# GRANT SUPER, REPLICATION CLIENT ON *.* TO $user@$host;
+# Check with:
+# mysql -u$user -p$password -h$host $db
+
+use strict;
+use Test::More;
+use NPTest;
+
+use vars qw($tests);
+
+plan skip_all => "check_mysql not compiled" unless (-x "check_mysql");
+
+plan tests => 15;
+
+my $bad_login_output = '/Access denied for user /';
+my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no slaves setup");
+my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no slaves setup");
+my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest");
+my $with_slave = getTestParameter("NP_MYSQL_WITH_SLAVE", "MySQL server with slaves setup");
+my $with_slave_login = getTestParameter("NP_MYSQL_WITH_SLAVE_LOGIN", "Login details for server with slave (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest");
+
+my $result;
+
+SKIP: {
+ skip "No mysql server defined", 5 unless $mysqlserver;
+ $result = NPTest->testCmd("./check_mysql -H $mysqlserver $mysql_login_details");
+ cmp_ok( $result->return_code, '==', 0, "Login okay");
+
+ $result = NPTest->testCmd("./check_mysql -H $mysqlserver -u dummy -pdummy");
+ cmp_ok( $result->return_code, '==', 2, "Login failure");
+ like( $result->output, $bad_login_output, "Expected login failure message");
+
+ $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details");
+ cmp_ok( $result->return_code, "==", 1, "No slaves defined" );
+ like( $result->output, "/No slaves defined/", "Correct error message");
+}
+
+SKIP: {
+ skip "No mysql socket defined", 5 unless $mysqlsocket;
+ $result = NPTest->testCmd("./check_mysql -s $mysqlsocket $mysql_login_details");
+ cmp_ok( $result->return_code, '==', 0, "Login okay");
+
+ $result = NPTest->testCmd("./check_mysql -s $mysqlsocket -u dummy -pdummy");
+ cmp_ok( $result->return_code, '==', 2, "Login failure");
+ like( $result->output, $bad_login_output, "Expected login failure message");
+
+ $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details");
+ cmp_ok( $result->return_code, "==", 1, "No slaves defined" );
+ like( $result->output, "/No slaves defined/", "Correct error message");
+}
+
+SKIP: {
+ skip "No mysql server with slaves defined", 5 unless $with_slave;
+ $result = NPTest->testCmd("./check_mysql -H $with_slave $with_slave_login");
+ cmp_ok( $result->return_code, '==', 0, "Login okay");
+
+ $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login");
+ cmp_ok( $result->return_code, "==", 0, "Slaves okay" );
+
+ $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60");
+ cmp_ok( $result->return_code, '==', 0, 'Slaves are not > 60 seconds behind');
+
+ $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60:");
+ cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind');
+ like( $result->output, "/^SLOW_SLAVE WARNING:/", "Output okay");
+}
diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t
new file mode 100644
index 0000000..c30245b
--- /dev/null
+++ b/plugins/t/check_mysql_query.t
@@ -0,0 +1,58 @@
+#! /usr/bin/perl -w -I ..
+#
+# MySQL Database Server Tests via check_mysql
+#
+#
+#
+# These are the database permissions required for this test:
+# GRANT SELECT ON $db.* TO $user@$host IDENTIFIED BY '$password';
+# Check with:
+# mysql -u$user -p$password -h$host $db
+
+use strict;
+use Test::More;
+use NPTest;
+
+use vars qw($tests);
+
+plan skip_all => "check_mysql_query not compiled" unless (-x "check_mysql_query");
+
+my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server with no slaves setup");
+my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access", "-u user -ppw -d db");
+my $result;
+
+if (! $mysqlserver) {
+ plan skip_all => "No mysql server defined";
+} else {
+ plan tests => 13;
+}
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 0, "Can run query");
+
+$result = NPTest->testCmd("./check_mysql_query -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 3, "Missing query parameter");
+like( $result->output, "/Must specify a SQL query to run/", "Missing query error message");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver -u dummy -d mysql");
+cmp_ok( $result->return_code, '==', 2, "Login failure");
+like( $result->output, "/Access denied for user /", "Expected login failure message");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SELECT PI()' -w 3 -c 4 -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 1, "Got warning");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SELECT PI()*2' -w 3 -c 4 -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 2, "Got critical");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SELECT * FROM adsf' -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 2, "Bad query");
+like( $result->output, "/Error with query/", "Bad query error message");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES LIKE \"bob\"' -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 1, "No rows");
+like( $result->output, "/No rows returned/", "No rows error message");
+
+$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details");
+cmp_ok( $result->return_code, '==', 2, "Data not numeric");
+like( $result->output, "/Is not a numeric/", "Data not numeric error message");
+
diff --git a/plugins/t/check_nagios.nagios1.status.log b/plugins/t/check_nagios.nagios1.status.log
new file mode 100644
index 0000000..64d9ce7
--- /dev/null
+++ b/plugins/t/check_nagios.nagios1.status.log
@@ -0,0 +1,5 @@
+# Nagios 1.2 Status File
+[1133537544] PROGRAM;1133537484;21980;1;1133537534;0;1;1;1;1;0;1;1;1
+[1133537544] HOST;ADSL;PENDING;0;0;0;0;0;0;0;0;1;1;1;1;0;0.0;0;1;1;(Not enough data to determine host status yet)
+[1133537544] HOST;Internet;UP;1133537486;1132135282;0;1402203;0;0;0;0;1;1;1;1;0;0.00;0;1;1;(Host assumed to be up)
+[1133537544] SERVICE;Internet;TCP/IP;OK;1/3;HARD;1133537486;1133537786;ACTIVE;1;1;1;1132135282;0;OK;1402203;0;0;0;0;0;1;0;4;1;0;0.00;0;1;1;0;PING OK - Packet loss = 0%, RTA = 0.09 ms
diff --git a/plugins/t/check_nagios.nagios2.status.dat b/plugins/t/check_nagios.nagios2.status.dat
new file mode 100644
index 0000000..6f62bac
--- /dev/null
+++ b/plugins/t/check_nagios.nagios2.status.dat
@@ -0,0 +1,127 @@
+########################################
+# NAGIOS STATUS FILE
+#
+# THIS FILE IS AUTOMATICALLY GENERATED
+# BY NAGIOS. DO NOT MODIFY THIS FILE!
+########################################
+
+info {
+ created=1133537302
+ version=2.0b5
+ }
+
+program {
+ modified_host_attributes=0
+ modified_service_attributes=0
+ nagios_pid=2750
+ daemon_mode=1
+ program_start=1133537167
+ last_command_check=1133537297
+ last_log_rotation=0
+ enable_notifications=1
+ active_service_checks_enabled=1
+ passive_service_checks_enabled=1
+ active_host_checks_enabled=1
+ passive_host_checks_enabled=1
+ enable_event_handlers=1
+ obsess_over_services=0
+ obsess_over_hosts=0
+ check_service_freshness=1
+ check_host_freshness=0
+ enable_flap_detection=1
+ enable_failure_prediction=1
+ process_performance_data=0
+ global_host_event_handler=
+ global_service_event_handler=
+ }
+
+host {
+ host_name=ADSL-derby-office
+ modified_attributes=0
+ check_command=check_host_alive_ping
+ event_handler=
+ has_been_checked=0
+ should_be_scheduled=0
+ check_execution_time=0.000
+ check_latency=0.000
+ check_type=0
+ current_state=0
+ last_hard_state=0
+ plugin_output=
+ performance_data=
+ last_check=0
+ next_check=0
+ current_attempt=1
+ max_attempts=3
+ state_type=1
+ last_state_change=0
+ last_hard_state_change=0
+ last_time_up=0
+ last_time_down=0
+ last_time_unreachable=0
+ last_notification=0
+ next_notification=0
+ no_more_notifications=0
+ current_notification_number=0
+ notifications_enabled=1
+ problem_has_been_acknowledged=0
+ acknowledgement_type=0
+ active_checks_enabled=1
+ passive_checks_enabled=1
+ event_handler_enabled=1
+ flap_detection_enabled=1
+ failure_prediction_enabled=1
+ process_performance_data=1
+ obsess_over_host=1
+ last_update=1133537302
+ is_flapping=0
+ percent_state_change=0.00
+ scheduled_downtime_depth=0
+ }
+
+service {
+ host_name=ADSL-derby-office
+ service_description=TCP/IP
+ modified_attributes=0
+ check_command=host5_service23_check_ping
+ event_handler=
+ has_been_checked=0
+ should_be_scheduled=1
+ check_execution_time=0.000
+ check_latency=0.000
+ check_type=0
+ current_state=0
+ last_hard_state=0
+ current_attempt=1
+ max_attempts=3
+ state_type=1
+ last_state_change=0
+ last_hard_state_change=0
+ last_time_ok=0
+ last_time_warning=0
+ last_time_unknown=0
+ last_time_critical=0
+ plugin_output=(Service assumed to be ok)
+ performance_data=
+ last_check=0
+ next_check=1133537317
+ current_notification_number=0
+ last_notification=0
+ next_notification=0
+ no_more_notifications=0
+ notifications_enabled=0
+ active_checks_enabled=1
+ passive_checks_enabled=1
+ event_handler_enabled=1
+ problem_has_been_acknowledged=0
+ acknowledgement_type=0
+ flap_detection_enabled=1
+ failure_prediction_enabled=1
+ process_performance_data=1
+ obsess_over_service=0
+ last_update=1133537302
+ is_flapping=0
+ percent_state_change=0.00
+ scheduled_downtime_depth=0
+ }
+
diff --git a/plugins/t/check_nagios.t b/plugins/t/check_nagios.t
new file mode 100644
index 0000000..f38f5e9
--- /dev/null
+++ b/plugins/t/check_nagios.t
@@ -0,0 +1,92 @@
+#! /usr/bin/perl -w -I ..
+#
+# check_nagios tests
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+if (`uname -s` eq "SunOS\n") {
+ plan skip_all => "Ignoring tests on solaris because of pst3";
+} else {
+ plan tests => 13;
+}
+
+my $successOutput = '/^NAGIOS OK: /';
+my $warningOutput = '/^NAGIOS WARNING: /';
+my $failureOutput = '/^NAGIOS CRITICAL: /';
+
+my $nagios1 = "t/check_nagios.nagios1.status.log";
+my $nagios2 = "t/check_nagios.nagios2.status.dat";
+
+my $result;
+
+# Did use init, but MacOSX 10.4 replaces init with launchd
+# Alternative is to insist that nagios is running to run this test
+# Reasonable to expect cron because build servers will
+# invoke cron to run a build
+my $procname = "cron";
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios1 -e 5 -C $procname"
+ );
+cmp_ok( $result->return_code, '==', 1, "Log over 5 minutes old" );
+like ( $result->output, $warningOutput, "Output for warning correct" );
+
+my $now = time;
+# This substitution is dependent on the testcase
+system( "perl -pe 's/1133537544/$now/' $nagios1 > $nagios1.tmp" ) == 0 or die "Problem with munging $nagios1";
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios1.tmp -e 1 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 0, "Log up to date" );
+like ( $result->output, $successOutput, "Output for success correct" );
+
+my $later = $now - 61;
+system( "perl -pe 's/1133537544/$later/' $nagios1 > $nagios1.tmp" ) == 0 or die "Problem with munging $nagios1";
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios1.tmp -e 1 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 1, "Log correctly seen as over 1 minute old" );
+my ($age) = ($_ = $result->output) =~ /status log updated (\d+) seconds ago/;
+like( $age, '/^6[0-9]$/', "Log correctly seen as between 60-69 seconds old" );
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios1.tmp -e 5 -C unlikely_command_string"
+ );
+cmp_ok( $result->return_code, "==", 2, "Nagios command not found" );
+like ( $result->output, $failureOutput, "Output for failure correct" );
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios2 -e 5 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 1, "Nagios2 for logfile over 5 mins old" );
+
+$now = time;
+system( "perl -pe 's/1133537302/$now/' $nagios2 > $nagios2.tmp" ) == 0 or die "Problem with munging $nagios2";
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios2.tmp -e 1 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 0, "Nagios2 log up to date" );
+
+$later = $now - 61;
+system( "perl -pe 's/1133537302/$later/' $nagios2 > $nagios2.tmp" ) == 0 or die "Problem with munging $nagios2";
+
+$result = NPTest->testCmd(
+ "./check_nagios -F $nagios2.tmp -e 1 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 1, "Nagios2 log correctly seen as over 1 minute old" );
+($age) = ($_ = $result->output) =~ /status log updated (\d+) seconds ago/;
+like( $age, '/^6[0-9]$/', "Log correctly seen as between 60-69 seconds old" );
+
+$result = NPTest->testCmd(
+ "./check_nagios -F t/check_nagios.t -e 1 -C $procname"
+ );
+cmp_ok( $result->return_code, "==", 2, "Invalid log file" );
+
+
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t
new file mode 100644
index 0000000..b8fc8fd
--- /dev/null
+++ b/plugins/t/check_ntp.t
@@ -0,0 +1,110 @@
+#! /usr/bin/perl -w -I ..
+#
+# Testing NTP
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my @PLUGINS1 = ('check_ntp', 'check_ntp_peer', 'check_ntp_time');
+my @PLUGINS2 = ('check_ntp_peer');
+
+plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2));
+
+my $res;
+
+my $ntp_service = getTestParameter( "NP_GOOD_NTP_SERVICE",
+ "A host providing NTP service",
+ "pool.ntp.org");
+
+my $no_ntp_service = getTestParameter( "NP_NO_NTP_SERVICE",
+ "A host NOT providing the NTP service",
+ "localhost" );
+
+my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests",
+ "10.0.0.1" );
+
+my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost");
+
+my $ntp_okmatch1 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
+my $ntp_warnmatch1 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
+my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs/';
+my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
+my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/';
+my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
+my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/';
+my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';
+
+
+foreach my $plugin (@PLUGINS1) {
+ SKIP: {
+ skip "No NTP server defined", 6 unless $ntp_service;
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000 -c 2000"
+ );
+ cmp_ok( $res->return_code, '==', 0, "$plugin: Good NTP result (simple check)" );
+ like( $res->output, $ntp_okmatch1, "$plugin: Output match OK (simple check)" );
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000: -c 2000"
+ );
+ cmp_ok( $res->return_code, '==', 1, "$plugin: Warning NTP result (simple check)" );
+ like( $res->output, $ntp_warnmatch1, "$plugin: Output match WARNING (simple check)" );
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000 -c 2000:"
+ );
+ cmp_ok( $res->return_code, '==', 2, "$plugin: Critical NTP result (simple check)" );
+ like( $res->output, $ntp_critmatch1, "$plugin: Output match CRITICAL (simple check)" );
+ }
+
+ SKIP: {
+ skip "No bad NTP server defined", 1 unless $no_ntp_service;
+ $res = NPTest->testCmd(
+ "./$plugin -H $no_ntp_service -t 3"
+ );
+ cmp_ok( $res->return_code, '==', 2, "$plugin: No NTP service" );
+ like( $res->output, $ntp_noresponse, "$plugin: Output match no NTP service" );
+ }
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $host_nonresponsive -t 3"
+ );
+ cmp_ok( $res->return_code, '==', 2, "$plugin: Server not responding" );
+ like( $res->output, $ntp_noresponse, "$plugin: Output match non-responsive" );
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $hostname_invalid"
+ );
+ cmp_ok( $res->return_code, '==', 3, "$plugin: Invalid hostname/address" );
+ like( $res->output, $ntp_nosuchhost, "$plugin: Output match invalid hostname/address" );
+
+}
+
+foreach my $plugin (@PLUGINS2) {
+ SKIP: {
+ skip "No NTP server defined", 6 unless $ntp_service;
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000 -c 2000 -W 20 -C 21 -j 100000 -k 200000 -m 1: -n 0:"
+ );
+ cmp_ok( $res->return_code, '==', 0, "$plugin: Good NTP result with jitter, stratum, and truechimers check" );
+ like( $res->output, $ntp_okmatch2, "$plugin: Output match OK with jitter, stratum, and truechimers" );
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000 -c 2000 -W \\~:-1 -C 21 -j 100000 -k 200000 -m 1: -n 0:"
+ );
+ cmp_ok( $res->return_code, '==', 1, "$plugin: Warning NTP result with jitter, stratum, and truechimers check" );
+ like( $res->output, $ntp_warnmatch2, "$plugin: Output match WARNING with jitter, stratum, and truechimers" );
+
+ $res = NPTest->testCmd(
+ "./$plugin -H $ntp_service -w 1000 -c 2000 -W 20 -C 21 -j 100000 -k \\~:-1 -m 1: -n 0:"
+ );
+ cmp_ok( $res->return_code, '==', 2, "$plugin: Critical NTP result with jitter, stratum, and truechimers check" );
+ like( $res->output, $ntp_critmatch2, "$plugin: Output match CRITICAL with jitter, stratum, and truechimers" );
+ }
+}
diff --git a/plugins/t/check_ping.t b/plugins/t/check_ping.t
new file mode 100644
index 0000000..1604f8f
--- /dev/null
+++ b/plugins/t/check_ping.t
@@ -0,0 +1,109 @@
+#! /usr/bin/perl -w -I ..
+#
+# Ping Response Tests via check_ping
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan tests => 20;
+
+my $successOutput = '/PING (ok|OK) - Packet loss = +[0-9]{1,2}\%, +RTA = [\.0-9]+ ms/';
+my $failureOutput = '/Packet loss = +[0-9]{1,2}\%, +RTA = [\.0-9]+ ms/';
+
+my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE",
+ "The hostname of system responsive to network requests",
+ "localhost" );
+
+my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests",
+ "10.0.0.1" );
+
+my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost" );
+
+my $res;
+
+$res = NPTest->testCmd(
+ "./check_ping -H $host_responsive -w 10,100% -c 10,100% -p 1"
+ );
+is( $res->return_code, 0, "Syntax ok" );
+like( $res->output, $successOutput, "Output OK" );
+
+$res = NPTest->testCmd(
+ "./check_ping -H $host_responsive -w 0,0% -c 10,100% -p 1"
+ );
+is( $res->return_code, 1, "Syntax ok, with forced warning" );
+like( $res->output, $failureOutput, "Output OK" );
+
+$res = NPTest->testCmd(
+ "./check_ping -H $host_responsive -w 0,0% -c 0,0% -p 1"
+ );
+is( $res->return_code, 2, "Syntax ok, with forced critical" );
+like( $res->output, $failureOutput, "Output OK" );
+
+$res = NPTest->testCmd(
+ "./check_ping $host_responsive 100 100 1000 1000 -p 1"
+ );
+is( $res->return_code, 0, "Old syntax ok" );
+like( $res->output, $successOutput, "Output OK" );
+
+$res = NPTest->testCmd(
+ "./check_ping $host_responsive 0 0 0 0 -p 1"
+ );
+is( $res->return_code, 2, "Old syntax, with forced critical" );
+like( $res->output, $failureOutput, "Output OK" );
+
+
+# check_ping results will depend on whether the ping command discovered by
+# ./configure has a timeout option. If it does, then the timeout will
+# be set, so check_ping will always get a response. If it doesn't
+# then check_ping will timeout. We do 2 tests for check_ping's timeout
+# - 1 second
+# - 15 seconds
+# The latter should be higher than normal ping timeouts, so should always give a packet loss result
+open(F, "../config.h") or die "Cannot open ../config.h";
+@_ = grep /define PING_HAS_TIMEOUT 1|define PING_PACKETS_FIRST 1/, <F>;
+my $has_timeout;
+$has_timeout = 1 if (scalar @_ == 2); # Need both defined
+close F;
+$res = NPTest->testCmd(
+ "./check_ping -H $host_nonresponsive -w 10,100% -c 10,100% -p 1 -t 1"
+ );
+is( $res->return_code, 2, "Timeout 1 second - host nonresponsive" );
+if ($has_timeout) {
+ like( $res->output, '/100%/', "Error contains '100%' string (for 100% packet loss)" );
+} else {
+ like( $res->output, '/timed out/', "Error contains 'timed out' string" );
+}
+
+$res = NPTest->testCmd(
+ "./check_ping -H $host_nonresponsive -w 10,100% -c 10,100% -p 1 -t 15"
+ );
+is( $res->return_code, 2, "Timeout 15 seconds - host nonresponsive" );
+like( $res->output, '/100%/', "Error contains '100%' string (for 100% packet loss)" );
+
+
+
+
+$res = NPTest->testCmd(
+ "./check_ping $host_nonresponsive -p 1 -t 15 100 100 1000 10000"
+ );
+is( $res->return_code, 2, "Old syntax: Timeout - host nonresponsive" );
+like( $res->output, '/100%/', "Error contains '100%' string (for 100% packet loss)" );
+
+$res = NPTest->testCmd(
+ "./check_ping $hostname_invalid 0 0 0 0 -p 1 -t 1"
+ );
+is( $res->return_code, 3, "Invalid hostname" );
+like( $res->output, '/invalid hostname/i', "Error contains 'invalid hostname' string");
+
+$res = NPTest->testCmd(
+ "./check_ping -w 100,10% -c 200,20%"
+ );
+is( $res->return_code, 3, "No hostname" );
+like( $res->output, '/You must specify a server address or host name/', "Output with appropriate error message");
+
diff --git a/plugins/t/check_pop.t b/plugins/t/check_pop.t
new file mode 100644
index 0000000..62352fd
--- /dev/null
+++ b/plugins/t/check_pop.t
@@ -0,0 +1,55 @@
+#! /usr/bin/perl -w -I ..
+#
+# Post Office Protocol (POP) Server Tests via check_pop
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+plan tests => 5;
+
+my $host_tcp_smtp = getTestParameter(
+ "NP_HOST_TCP_SMTP",
+ "A host providing an STMP Service (a mail server)",
+ "mailhost"
+ );
+
+my $host_tcp_pop = getTestParameter(
+ "NP_HOST_TCP_POP",
+ "A host providing a POP Service (a mail server)",
+ $host_tcp_smtp
+ );
+
+my $host_nonresponsive = getTestParameter(
+ "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests",
+ "10.0.0.1",
+ );
+
+my $hostname_invalid = getTestParameter(
+ "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname",
+ "nosuchhost",
+ );
+
+my %exceptions = ( 2 => "No POP Server present?" );
+
+my $t;
+my $res;
+
+$res = NPTest->testCmd( "./check_pop $host_tcp_pop" );
+cmp_ok( $res->return_code, '==', 0, "POP server ok");
+
+$res = NPTest->testCmd( "./check_pop -H $host_tcp_pop -p 110 -w 9 -c 9 -t 10 -e '+OK'");
+cmp_ok( $res->return_code, '==', 0, "POP server returned +OK");
+
+$res = NPTest->testCmd( "./check_pop $host_tcp_pop -p 110 -wt 9 -ct 9 -to 10 -e '+OK'");
+cmp_ok( $res->return_code, '==', 0, "Old syntax");
+
+$res = NPTest->testCmd( "./check_pop $host_nonresponsive" );
+cmp_ok( $res->return_code, '==', 2, "Non responsive host");
+
+$res = NPTest->testCmd( "./check_pop $hostname_invalid" );
+cmp_ok( $res->return_code, '==', 2, "Invalid host");
diff --git a/plugins/t/check_procs.t b/plugins/t/check_procs.t
new file mode 100644
index 0000000..abe7284
--- /dev/null
+++ b/plugins/t/check_procs.t
@@ -0,0 +1,49 @@
+#! /usr/bin/perl -w -I ..
+#
+# Process Tests via check_procs
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my $t;
+
+if (`uname -s` eq "SunOS\n" && ! -x "/usr/local/nagios/libexec/pst3") {
+ plan skip_all => "Ignoring tests on solaris because of pst3";
+} else {
+ plan tests => 14;
+}
+
+my $result;
+
+$result = NPTest->testCmd( "./check_procs -w 100000 -c 100000" );
+is( $result->return_code, 0, "Checking less than 10000 processes" );
+like( $result->output, '/^PROCS OK: [0-9]+ process(es)? | procs=[0-9]+;100000;100000;0;$/', "Output correct" );
+
+$result = NPTest->testCmd( "./check_procs -w 100000 -c 100000 -s Z" );
+is( $result->return_code, 0, "Checking less than 100000 zombie processes" );
+like( $result->output, '/^PROCS OK: [0-9]+ process(es)? with /', "Output correct" );
+
+if(fork() == 0) { exec("sleep 7"); } else { sleep(1) } # fork a test process in child and give child time to fork in parent
+$result = NPTest->testCmd( "./check_procs -a 'sleep 7'" );
+is( $result->return_code, 0, "Parent process is ignored" );
+like( $result->output, '/^PROCS OK: 1 process?/', "Output correct" );
+
+$result = NPTest->testCmd( "./check_procs -w 0 -c 100000" );
+is( $result->return_code, 1, "Checking warning if processes > 0" );
+like( $result->output, '/^PROCS WARNING: [0-9]+ process(es)? | procs=[0-9]+;0;100000;0;$/', "Output correct" );
+
+$result = NPTest->testCmd( "./check_procs -w 0 -c 0" );
+is( $result->return_code, 2, "Checking critical if processes > 0" );
+like( $result->output, '/^PROCS CRITICAL: [0-9]+ process(es)? | procs=[0-9]+;0;0;0;$/', "Output correct" );
+
+$result = NPTest->testCmd( "./check_procs -w 0 -c 0 -s Ss" );
+is( $result->return_code, 2, "Checking critical if sleeping processes" );
+like( $result->output, '/^PROCS CRITICAL: [0-9]+ process(es)? with /', "Output correct" );
+
+$result = NPTest->testCmd( "./check_procs -w 0 -c 100000 -p 1" );
+is( $result->return_code, 1, "Checking warning for processes by parentid = 1" );
+like( $result->output, '/^PROCS WARNING: [0-9]+ process(es)? with PPID = 1/', "Output correct" );
+
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
new file mode 100644
index 0000000..1a1ebe3
--- /dev/null
+++ b/plugins/t/check_smtp.t
@@ -0,0 +1,84 @@
+#! /usr/bin/perl -w -I ..
+#
+# Simple Mail Transfer Protocol (SMTP) Test via check_smtp
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my $host_tcp_smtp = getTestParameter( "NP_HOST_TCP_SMTP",
+ "A host providing an SMTP Service (a mail server)", "mailhost");
+my $host_tcp_smtp_starttls = getTestParameter( "NP_HOST_TCP_SMTP_STARTTLS",
+ "A host providing SMTP with STARTTLS", $host_tcp_smtp);
+my $host_tcp_smtp_nostarttls = getTestParameter( "NP_HOST_TCP_SMTP_NOSTARTTLS",
+ "A host providing SMTP without STARTTLS", "");
+my $host_tcp_smtp_tls = getTestParameter( "NP_HOST_TCP_SMTP_TLS",
+ "A host providing SMTP with TLS", $host_tcp_smtp);
+
+my $host_nonresponsive = getTestParameter( "NP_HOST_NONRESPONSIVE",
+ "The hostname of system not responsive to network requests", "10.0.0.1" );
+
+my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
+ "An invalid (not known to DNS) hostname", "nosuchhost" );
+my $res;
+
+plan tests => 16;
+
+SKIP: {
+ skip "No SMTP server defined", 4 unless $host_tcp_smtp;
+ $res = NPTest->testCmd( "./check_smtp $host_tcp_smtp" );
+ is ($res->return_code, 0, "OK");
+
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp -p 25 -w 9 -c 9 -t 10 -e 220" );
+ is ($res->return_code, 0, "OK, within 9 second response");
+
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp -p 25 -wt 9 -ct 9 -to 10 -e 220" );
+ is ($res->return_code, 0, "OK, old syntax");
+
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp -e 221" );
+ is ($res->return_code, 1, "WARNING - got correct error when expecting 221 instead of 220" );
+
+ TODO: {
+ local $TODO = "Output is over two lines";
+ like ( $res->output, qr/^SMTP WARNING/, "Correct error message" );
+ }
+
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" );
+ is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" );
+ like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port");
+}
+
+SKIP: {
+ skip "No SMTP server with STARTTLS defined", 1 unless $host_tcp_smtp_starttls;
+ # SSL connection for STARTTLS
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_starttls -p 25 -S" );
+ is ($res->return_code, 0, "OK, with STARTTLS" );
+}
+
+SKIP: {
+ skip "No SMTP server without STARTTLS defined", 2 unless $host_tcp_smtp_nostarttls;
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_nostarttls -p 25 -S" );
+ is ($res->return_code, 1, "OK, got warning from server without STARTTLS");
+ is ($res->output, "WARNING - TLS not supported by server", "Right error message" );
+}
+
+SKIP: {
+ skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls;
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" );
+ is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" );
+ like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" );
+
+ my $unused_port = 4465;
+ $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
+ is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" );
+ like ($res->output, qr/^connect to address $host_tcp_smtp_tls and port $unused_port: Connection refused/, "Check output of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port");
+}
+
+$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );
+is ($res->return_code, 2, "CRITICAL - host non responding" );
+
+$res = NPTest->testCmd( "./check_smtp $hostname_invalid" );
+is ($res->return_code, 3, "UNKNOWN - hostname invalid" );
+
diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t
new file mode 100644
index 0000000..576cc50
--- /dev/null
+++ b/plugins/t/check_snmp.t
@@ -0,0 +1,176 @@
+#! /usr/bin/perl -w -I ..
+#
+# Simple Network Management Protocol (SNMP) Test via check_snmp
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+BEGIN {
+ plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp";
+ plan tests => 63;
+}
+
+my $res;
+
+my $host_snmp = getTestParameter("NP_HOST_SNMP", "A host providing an SNMP Service", "localhost");
+my $snmp_community = getTestParameter("NP_SNMP_COMMUNITY", "The SNMP Community string for SNMP Testing (assumes snmp v1)", "public");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_md5");
+
+
+$res = NPTest->testCmd( "./check_snmp -t 1" );
+is( $res->return_code, 3, "No host name" );
+is( $res->output, "No host specified" );
+
+$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" );
+is( $res->return_code, 3, "No OIDs specified" );
+is( $res->output, "No OIDs specified" );
+
+$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" );
+is( $res->return_code, 3, "Invalid seclevel" );
+like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" );
+
+$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" );
+is( $res->return_code, 3, "Invalid protocol" );
+like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" );
+
+SKIP: {
+ skip "no snmp host defined", 50 if ( ! $host_snmp );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" );
+ like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK");
+ $res->output =~ /^SNMP OK - (\d+)/;
+ my $value = $1;
+ cmp_ok( $value, ">", 0, "Got a time value" );
+ like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it");
+
+
+ # some more threshold tests
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1");
+ cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:");
+ cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1");
+ cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10");
+ cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10");
+ cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1");
+ cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" );
+
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:");
+ cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" );
+ like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" );
+ unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" );
+ like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" );
+ like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" );
+ like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:");
+ cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " );
+ like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0");
+ cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" );
+ like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2");
+ cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" );
+ like($res->output, "/^SNMP OK - 2 1/", "Got two values back" );
+ like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" );
+ like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2");
+ cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" );
+ like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" );
+ like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" );
+ like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses");
+ like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0");
+ cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds");
+ like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3");
+ $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/;
+ my $lower = $1 - 0.05;
+ my $higher = $1 + 0.05;
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher");
+ cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2");
+ cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold");
+ like($res->output, '/^SNMP WARNING - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s+\*1\*\s.*$/', "First OID returned as string, 2nd checked for thresholds");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''");
+ cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2");
+ cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check");
+ like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,");
+ cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds");
+ like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'");
+ cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold");
+ like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0");
+ cmp_ok( $res->return_code, '==', 0, "Timetick used as a string");
+ like($res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "Timetick used as a string, result printed rather than parsed");
+
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1");
+ cmp_ok( $res->return_code, '==', 0, "snmp response without datatype");
+ like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" );
+}
+
+SKIP: {
+ skip "no SNMP user defined", 1 if ( ! $user_snmp );
+ $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv");
+ like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" );
+}
+
+# These checks need a complete command line. An invalid community is used so
+# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway
+SKIP: {
+ skip "no non responsive host defined", 2 if ( ! $host_nonresponsive );
+ $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:");
+ cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" );
+ like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem");
+}
+
+SKIP: {
+ skip "no non invalid host defined", 2 if ( ! $hostname_invalid );
+ $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:");
+ cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" );
+ like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host");
+}
diff --git a/plugins/t/check_ssh.t b/plugins/t/check_ssh.t
new file mode 100644
index 0000000..a5cd23c
--- /dev/null
+++ b/plugins/t/check_ssh.t
@@ -0,0 +1,41 @@
+#! /usr/bin/perl -w -I ..
+#
+# check_ssh tests
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+# Required parameters
+my $ssh_host = getTestParameter("NP_SSH_HOST", "A host providing SSH service", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1" );
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost" );
+
+
+plan skip_all => "SSH_HOST must be defined" unless $ssh_host;
+plan tests => 6;
+
+
+my $result = NPTest->testCmd(
+ "./check_ssh -H $ssh_host"
+ );
+cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
+like($result->output, '/^SSH OK - /', "Status text if command returned none (OK)");
+
+
+$result = NPTest->testCmd(
+ "./check_ssh -H $host_nonresponsive -t 2"
+ );
+cmp_ok($result->return_code, '==', 2, "Exit with return code 0 (OK)");
+like($result->output, '/^CRITICAL - Socket timeout after 2 seconds/', "Status text if command returned none (OK)");
+
+
+
+$result = NPTest->testCmd(
+ "./check_ssh -H $hostname_invalid -t 2"
+ );
+cmp_ok($result->return_code, '==', 3, "Exit with return code 0 (OK)");
+like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)");
+
diff --git a/plugins/t/check_swap.t b/plugins/t/check_swap.t
new file mode 100644
index 0000000..de9e0f0
--- /dev/null
+++ b/plugins/t/check_swap.t
@@ -0,0 +1,31 @@
+#! /usr/bin/perl -w -I ..
+#
+# Swap Space Tests via check_swap
+#
+#
+
+use strict;
+use Test::More tests => 8;
+use NPTest;
+
+my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
+my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
+my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
+
+my $result;
+
+$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576" ); # 1 MB free
+cmp_ok( $result->return_code, "==", 0, "At least 1MB free" );
+like( $result->output, $successOutput, "Right output" );
+
+$result = NPTest->testCmd( "./check_swap -w 1% -c 1%" ); # 1% free
+cmp_ok( $result->return_code, "==", 0, 'At least 1% free' );
+like( $result->output, $successOutput, "Right output" );
+
+$result = NPTest->testCmd( "./check_swap -w 100% -c 100%" ); # 100% (always critical)
+cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' );
+like( $result->output, $failureOutput, "Right output" );
+
+$result = NPTest->testCmd( "./check_swap -w 100% -c 1%" ); # 100% (always warn)
+cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' );
+like( $result->output, $warnOutput, "Right output" );
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
new file mode 100644
index 0000000..cb4de53
--- /dev/null
+++ b/plugins/t/check_tcp.t
@@ -0,0 +1,55 @@
+#! /usr/bin/perl -w -I ..
+#
+# TCP Connection Based Tests via check_tcp
+#
+#
+
+use strict;
+use Test;
+
+use vars qw($tests $has_ipv6);
+BEGIN {
+ use NPTest;
+ $has_ipv6 = NPTest::has_ipv6();
+ $tests = $has_ipv6 ? 14 : 11;
+}
+
+
+my $host_tcp_http = getTestParameter("NP_HOST_TCP_HTTP", "A host providing the HTTP Service (a web server)", "localhost");
+my $host_tls_http = getTestParameter("NP_HOST_TLS_HTTP", "A host providing the HTTPS Service (a tls web server)", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
+
+my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/';
+
+my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/';
+
+my $t;
+
+$tests = $tests - 4 if $internet_access eq "no";
+plan tests => $tests;
+
+$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput );
+$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test
+$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 );
+$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 );
+if($internet_access ne "no") {
+ $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
+ $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );
+ $t += checkCmd( "./check_tcp -S -D 9000 -H $host_tls_http -p 443", 1 );
+ $t += checkCmd( "./check_tcp -S -D 9000,8999 -H $host_tls_http -p 443", 2 );
+}
+
+# Need the \r\n to make it more standards compliant with web servers. Need the various quotes
+# so that perl doesn't interpret the \r\n and is passed onto command line correctly
+$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -E -s ".'"GET / HTTP/1.1\r\n\r\n"'." -e 'ThisShouldntMatch' -j", 1, $failedExpect );
+
+# IPv6 checks
+if($has_ipv6) {
+ $t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600 -6 ", 0, $successOutput );
+ $t += checkCmd( "./check_tcp -6 -p 80 www.heise.de", 0 );
+}
+
+exit(0) if defined($Test::Harness::VERSION);
+exit($tests - $t);
diff --git a/plugins/t/check_time.t b/plugins/t/check_time.t
new file mode 100644
index 0000000..92c2f89
--- /dev/null
+++ b/plugins/t/check_time.t
@@ -0,0 +1,36 @@
+#! /usr/bin/perl -w -I ..
+#
+# System Time Tests via check_time
+#
+#
+
+use strict;
+use Test;
+use NPTest;
+
+use vars qw($tests);
+BEGIN {$tests = 8; plan tests => $tests}
+
+my $host_udp_time = getTestParameter("NP_HOST_UDP_TIME", "A host providing the UDP Time Service", "localhost");
+my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
+my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
+
+my $successOutput = '/^TIME OK - [0-9]+ second time difference/';
+
+my %exceptions = ( 3 => "No time server present?");
+
+my $t;
+
+# standard mode
+$t += checkCmd( "./check_time -H $host_udp_time -w 999999,59 -c 999999,59 -t 60", 0, $successOutput, %exceptions );
+$t += checkCmd( "./check_time -H $host_udp_time -w 999999 -W 59 -c 999999 -C 59 -t 60", 0, $successOutput, %exceptions );
+
+# reverse compatibility mode
+$t += checkCmd( "./check_time $host_udp_time -wt 59 -ct 59 -cd 999999 -wd 999999 -to 60", 0, $successOutput, %exceptions );
+
+# failure mode
+$t += checkCmd( "./check_time -H $host_nonresponsive -t 1", 2 );
+$t += checkCmd( "./check_time -H $hostname_invalid -t 1", 3 );
+
+exit(0) if defined($Test::Harness::VERSION);
+exit($tests - $t);
diff --git a/plugins/t/check_udp.t b/plugins/t/check_udp.t
new file mode 100644
index 0000000..6c47d09
--- /dev/null
+++ b/plugins/t/check_udp.t
@@ -0,0 +1,71 @@
+#! /usr/bin/perl -w -I ..
+#
+# UDP Connection Based Tests via check_udp
+#
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+my $res;
+
+alarm(120); # make sure tests don't hang
+
+plan tests => 14;
+
+$res = NPTest->testCmd( "./check_udp -H localhost -p 3333" );
+cmp_ok( $res->return_code, '==', 3, "Need send/expect string");
+like ( $res->output, '/With UDP checks, a send/expect string must be specified./', "Output OK");
+
+$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s send" );
+cmp_ok( $res->return_code, '==', 3, "Need expect string");
+like ( $res->output, '/With UDP checks, a send/expect string must be specified./', "Output OK");
+
+$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -e expect" );
+cmp_ok( $res->return_code, '==', 3, "Need send string");
+like ( $res->output, '/With UDP checks, a send/expect string must be specified./', "Output OK");
+
+$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
+cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
+like ( $res->output, '/No data received from host/', "Output OK");
+
+my $nc;
+if(system("which nc.traditional >/dev/null 2>&1") == 0) {
+ $nc = 'nc.traditional -w 3 -l -u -p 3333';
+}
+elsif(system("which nc >/dev/null 2>&1") == 0) {
+ $nc = 'nc -w 3 -l -u -4 localhost 3333';
+}
+elsif(system("which netcat >/dev/null 2>&1") == 0) {
+ $nc = 'netcat -w 3 -l -u -p 3333';
+}
+
+SKIP: {
+ skip "solaris netcat does not listen to udp", 6 if $^O eq 'solaris';
+ skip "No netcat available", 6 unless $nc;
+ open (NC, "echo 'barbar' | $nc |");
+ sleep 1;
+ $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
+ cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
+ like ( $res->output, '/\[barbar\]/', "Output OK");
+ close NC;
+
+ # Start up a udp server listening on port 3333, quit after 3 seconds
+ # Otherwise will hang at close
+ my $pid = open(NC, "$nc </dev/null |");
+ sleep 1; # Allow nc to startup
+
+ my $start = time;
+ $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foofoo -e barbar -t 5 -4" );
+ my $duration = time - $start;
+ cmp_ok( $res->return_code, '==', '2', "Hung waiting for response");
+ like ( $res->output, '/Socket timeout after 5 seconds/', "Timeout message");
+ like ( $duration, '/^[56]$/', "Timeout after 5 (possibly 6) seconds");
+ my $read_nc = <NC> || '';
+ close NC;
+ cmp_ok( $read_nc, 'eq', "foofoo", "Data received correctly" );
+}
+
+
+alarm(0); # disable alarm
diff --git a/plugins/t/check_users.t b/plugins/t/check_users.t
new file mode 100644
index 0000000..9ebc2fc
--- /dev/null
+++ b/plugins/t/check_users.t
@@ -0,0 +1,30 @@
+#! /usr/bin/perl -w -I ..
+#
+# Logged in Users Tests via check_users
+#
+# Trick: This check requires at least 1 user logged in. These commands should
+# leave a session open forever in the background:
+#
+# $ ssh -tt localhost </dev/null >/dev/null 2>/dev/null &
+# $ disown %1
+
+use strict;
+use Test;
+use NPTest;
+
+use vars qw($tests);
+BEGIN {$tests = 8; plan tests => $tests}
+
+my $successOutput = '/^USERS OK - [0-9]+ users currently logged in/';
+my $failureOutput = '/^USERS CRITICAL - [0-9]+ users currently logged in/';
+
+my $t;
+
+$t += checkCmd( "./check_users 1000 1000", 0, $successOutput );
+$t += checkCmd( "./check_users 0 0", 2, $failureOutput );
+$t += checkCmd( "./check_users -w 0:1000 -c 0:1000", 0, $successOutput );
+$t += checkCmd( "./check_users -w 0:0 -c 0:0", 2, $failureOutput );
+
+exit(0) if defined($Test::Harness::VERSION);
+exit($tests - $t);
+
diff --git a/plugins/t/negate.t b/plugins/t/negate.t
new file mode 100644
index 0000000..5ec1c84
--- /dev/null
+++ b/plugins/t/negate.t
@@ -0,0 +1,90 @@
+#! /usr/bin/perl -w -I ..
+#
+# negate checks
+# Need check_dummy to work for testing
+#
+
+use strict;
+use Test::More;
+use Cwd;
+use NPTest;
+
+# 15 tests in the first part, 9 in timeout tests and 2 * 32 in the last loops
+plan tests => 88;
+
+my $res;
+
+my $PWD = getcwd();
+
+$res = NPTest->testCmd( "./negate" );
+is( $res->return_code, 3, "Not enough parameters");
+like( $res->output, "/Could not parse arguments/", "Could not parse arguments");
+
+$res = NPTest->testCmd( "./negate bobthebuilder" );
+is( $res->return_code, 3, "Require full path" );
+like( $res->output, "/Require path to command/", "Appropriate error message");
+
+$res = NPTest->testCmd( "./negate $PWD/check_dummy 0 'a dummy okay'" );
+is( $res->return_code, 2, "OK changed to CRITICAL" );
+is( $res->output, "OK: a dummy okay", "Output as expected" );
+
+$res = NPTest->testCmd( "./negate '$PWD/check_dummy 0 redsweaterblog'");
+is( $res->return_code, 2, "OK => CRIT with a single quote for command to run" );
+is( $res->output, "OK: redsweaterblog", "Output as expected" );
+
+$res = NPTest->testCmd( "./negate $PWD/check_dummy 1 'a warn a day keeps the managers at bay'" );
+is( $res->return_code, 1, "WARN stays same" );
+
+$res = NPTest->testCmd( "./negate $PWD/check_dummy 3 mysterious");
+is( $res->return_code, 3, "UNKNOWN stays same" );
+
+$res = NPTest->testCmd( "./negate \"$PWD/check_dummy 0 'a dummy okay'\"" );
+is( $res->output, "OK: a dummy okay", "Checking slashed quotes - the single quotes are re-evaluated at shell" );
+
+# Output is "OK: a" because check_dummy only returns the first arg
+$res = NPTest->testCmd( "./negate $PWD/check_dummy 0 a dummy okay" );
+is( $res->output, "OK: a", "Multiple args passed as arrays" );
+
+$res = NPTest->testCmd( "./negate $PWD/check_dummy 0 'a dummy okay'" );
+is( $res->output, "OK: a dummy okay", "The quoted string is passed through to subcommand correctly" );
+
+$res = NPTest->testCmd( "./negate '$PWD/check_dummy 0' 'a dummy okay'" );
+is( $res->output, "No data returned from command", "Bad command, as expected (trying to execute './check_dummy 0')");
+
+$res = NPTest->testCmd( './negate '.$PWD.'/check_dummy 0 \'$$ a dummy okay\'' );
+is( $res->output, 'OK: $$ a dummy okay', 'Proves that $$ is not being expanded again' );
+
+my %state = (
+ ok => 0,
+ warning => 1,
+ critical => 2,
+ unknown => 3,
+ );
+
+# Timeout tests
+$res = NPTest->testCmd( "./negate -t 2 /bin/sh -c 'sleep 5'" );
+is( $res->output, 'CRITICAL - Plugin timed out after 2 seconds' );
+
+foreach my $state (keys(%state)) {
+ $res = NPTest->testCmd( "./negate -t 2 -T $state /bin/sh -c 'sleep 5'" );
+ is( $res->return_code, $state{$state}, "Got timeout state $state" );
+ is( $res->output, uc($state)." - Plugin timed out after 2 seconds", "Timeout state $state output");
+}
+
+foreach my $current_state (keys(%state)) {
+ foreach my $new_state (keys(%state)) {
+ $res = NPTest->testCmd( "./negate --$current_state=$new_state ./check_dummy ".$state{$current_state}." 'Fake $new_state'" );
+ is( $res->return_code, $state{$new_state}, "Got fake $new_state" );
+ is( $res->output, uc($current_state).": Fake $new_state", "Fake $new_state output");
+ }
+}
+
+# Same as above with substitute
+foreach my $current_state (keys(%state)) {
+ foreach my $new_state (keys(%state)) {
+ $res = NPTest->testCmd( "./negate -s --$current_state=$new_state ./check_dummy ".$state{$current_state}." 'Fake $new_state'" );
+ is( $res->return_code, $state{$new_state}, "Got fake $new_state (with substitute)" );
+ is( $res->output, uc($new_state).": Fake $new_state", "Substituted fake $new_state output");
+ }
+}
+
diff --git a/plugins/tests/certs/.gitignore b/plugins/tests/certs/.gitignore
new file mode 100644
index 0000000..79acaaa
--- /dev/null
+++ b/plugins/tests/certs/.gitignore
@@ -0,0 +1,2 @@
+/*.csr
+/*.srl
diff --git a/plugins/tests/certs/client-cert.pem b/plugins/tests/certs/client-cert.pem
new file mode 100644
index 0000000..5709750
--- /dev/null
+++ b/plugins/tests/certs/client-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtDCCApwCAQIwDQYJKoZIhvcNAQELBQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYD
+VQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3Jp
+bmcgUGx1Z2luczEkMCIGA1UEAwwbTW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENB
+MSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMB4X
+DTIxMDIyODIxMDIxMloXDTMwMTEyODIxMDIxMlowgZ4xCzAJBgNVBAYTAkRFMRAw
+DgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0
+b3JpbmcgUGx1Z2luczEiMCAGA1UEAwwZTW9uaXRvcmluZyBQbHVnaW5zIENsaWVu
+dDErMCkGCSqGSIb3DQEJARYcZGV2ZWxAbW9uaXRvcmluZy1wbHVnaW5zLm9yZzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM3EiqfFPomm5dZQPGYG5SrF
+rPvyqseXTzCkwUIUzGf+Sfm3s13zx7e3ije/04yKhTXgK59EQ793q7E2aWhSOz3s
+hwKKdylFkOIyc5jgbAfF1/pLZMK209rLt/mMRksXCRXYrHdTjRMx1ev4C2407+8Y
+8qkf77DuYQmUqCQe7DPOvqLeagdw9JcLGmQNTKHg3fl6wyRl5K1Bsy+qXu2XvEjZ
+0Ng7n8LHjOUkTqUEJndOxci9gL5cHU5ttul/GW34dKOtTuMU/pQX6/ywYusOGVOx
+RYI76OolRqj5BqbNctDIB/obe2RLo+UVx74/0jAxtH4XS23pYjO7NUpJcytsVG8C
+AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAYfaY5n4pCq0NWPCdeVVRr4nr+GAfv1TC
+/PKcGuEoJZKt7TQT+OOA5yeZMZb53OvtA49D1r9aoJzWe946KElWOEBqxDRi5Cdr
+wkqpwGcPT2RfAqA3/cvQZ1XsquboXrCf7ajdl5OC64bs2jkqCFh9gnxuI140g8Ar
+Njol8BFxRPaYWOnwuQwmh/2t0FJqr3WSD85HrNqtxUSNGbTdSsvCfgF0v7QVkvLG
+3/cbx6z5hxzj2JUjhMnCvn+EbasoJt4xyBFvg67Q2229SMwu9YNqS63GVoKUqhCB
+4Gl5v31qx8dAFKuRvnez3ze/6oohwmakZkst4hcQdgZocHhzesvKlg==
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/client-key.pem b/plugins/tests/certs/client-key.pem
new file mode 100644
index 0000000..09b6761
--- /dev/null
+++ b/plugins/tests/certs/client-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNxIqnxT6JpuXW
+UDxmBuUqxaz78qrHl08wpMFCFMxn/kn5t7Nd88e3t4o3v9OMioU14CufREO/d6ux
+NmloUjs97IcCincpRZDiMnOY4GwHxdf6S2TCttPay7f5jEZLFwkV2Kx3U40TMdXr
++AtuNO/vGPKpH++w7mEJlKgkHuwzzr6i3moHcPSXCxpkDUyh4N35esMkZeStQbMv
+ql7tl7xI2dDYO5/Cx4zlJE6lBCZ3TsXIvYC+XB1Obbbpfxlt+HSjrU7jFP6UF+v8
+sGLrDhlTsUWCO+jqJUao+QamzXLQyAf6G3tkS6PlFce+P9IwMbR+F0tt6WIzuzVK
+SXMrbFRvAgMBAAECggEBALtc2pB3p0E6KpAiEU0pvCRdSO1FgsIpAd+eNadRPur2
+fi+XWQkUwGeGBaJL1npja3aqP65PP40pj7nWfNaUAgOZyznCEU0QXiPJor6yo0vU
+l5v+aKpwRao107i0RRF80TYGTMx+1LeEqnCqNOZN56gERHlBbkTiWpOZvBzf1143
+oegTcyM6+Ee6+FYNhHaDyIYD0md1S2wGR+IBPet6HwWiakLNKahFPa7lOLIKfmmD
+iTtifcbf4724wSe44a0uTeP4JrquZSeIKakm8MEmffmYqpycnaakYefd0Xc5UEsH
++VbhKpOWGY3d8FKHqUsTa+6QyXb2uFPo6A+yWm0pdJECgYEA7Prd5sbWACvXOcHT
+ONDBAgyfAVDQwOXi3D4dk6D5mg+/jxl5ZQY5slszJrwsLFtoEzXtYpNfTy3cpNOp
+JLbBDZYnqty+5tD8t3/Zv2IBXCAgvuk5CgfJWP5FNAfiyUEE6Vbp6J/5/vAnODsa
+fxZryN5UsH0X8ew7AlbfcVNyj4kCgYEA3khetIgn+GR6sv9jFRdCT6aJbp0xMsms
+6F4v3L5FG4Kp+SwDHL1bVOhieJ5g8odYp9hDbgTEEqbJfNmyCOu9+OQmZ/mztku7
+6reU8HhYBIvi+hFeJmvqKpdIgU0Zveg4Bst5QordmhPk8AHjBC4xvQ++uh7rwYKd
+WVsS08bGDjcCgYEAlAuNARUKsASzakOqHv5a9VrJIttH7povBYRQmd+gzxwzgcRa
+UEB5XvEWnYZE2lkoRYgVCtYiXqa6BsasDmGVbVV25okNQckhd8mJUMR7MQBpNJsi
+pR+EK/J9bSnYBf52gQdpDYiTdy60ca6KuQZaw5wRsEgV426+1pFK+dM16HECgYBY
+cTsdYb9lmbUoW201CxgbUQwFsw3MQ2pE2pT4o8wjcg3nUpe6a61XT08+5uV0Gl4w
+CmBp+gN52Fr7DjNEUWg5C64sWLIkqmWOspTUSU3cITyiex6W8wEtCRyUNfU0Fp2U
+Nol87HvXvmqtBFMraqXnr8gXjg4H5MxurUoEcWaEaQKBgCT4iIGZwW0Qf2rkFC7B
+xObzVGefivVVbaf8/c/LRO8TMLdnExkShMOmCzHeHV4mMEZDLbMOusHCI7xm10EX
+l3L1I1Kyqnhm1RH3e7TVWgkTmIDW3V5Fgrhm1jx5Iz6et4sb4Uh+bZq9tTLyqfZY
+8s0yJUrfpjRggfk7eUs5s7aY
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientca-cert.pem b/plugins/tests/certs/clientca-cert.pem
new file mode 100644
index 0000000..9ce7cd7
--- /dev/null
+++ b/plugins/tests/certs/clientca-cert.pem
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEIzCCAwugAwIBAgIUL9Jfp5zv5B29NgDsNEFU2OM/UHswDQYJKoZIhvcNAQEL
+BQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
+dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEkMCIGA1UEAwwbTW9u
+aXRvcmluZyBQbHVnaW5zIENsaWVudENBMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBt
+b25pdG9yaW5nLXBsdWdpbnMub3JnMB4XDTIxMDIyODIxMDIxMVoXDTMwMTEyODIx
+MDIxMVowgaAxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQH
+DAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEkMCIGA1UEAwwb
+TW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENBMSswKQYJKoZIhvcNAQkBFhxkZXZl
+bEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAyxiWsGrsJFHw3VR0pqHviXUfbfKMw8LaCxI5EQZfInsMVkBIGWEW
+tFW6qDuAOsMdzsrKOnQRNNt852ts/0Uz++z8zysoauAGpc4JnCZuM5A1DU5CFXBx
+w6Ax+1ft3UsTt8C6kfLfs8mPCbtNVqAHrMrIqDxsNSRRxQSqkzp1vD8rwSKcbB1h
+u2+lut1bEqMe7dp89jKOtc6G/1tHUFQuLAGFoX/qk9yPscmQNzL6YbLP4m9r/416
+PsxWsAfyY97hmoYo6mSCue5LmeanOsjf4Kzq90hIJRwrpiUGmxGjW+tPLEhQBZw6
+C2wHyN74YIJYX2xREz2ijT0mgsqdhO5ZxwIDAQABo1MwUTAdBgNVHQ4EFgQUtsP9
+Z3fKkhmFp97Kh/cW/UqHMIMwHwYDVR0jBBgwFoAUtsP9Z3fKkhmFp97Kh/cW/UqH
+MIMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEApO5o+YECwTEv
+s+elDJZQ20UYwDSiU9Lpf4EcdnRv6FAb5UlhfRTH3ZdKCc/HX7kcKuy3PsF+b8Pw
+EusoKito9OlNEOF5HYAI9/J54/qceqn+SC0INsISeE19PvT0dma7lBSj4OvBv0IS
+GYbdztVaKLWqYgYs0mcEzteUc4MZcy1/C+Ru1i1Kp2s9/vIeAw2PV2+kpWtw88Pb
+FRJomGngP/hQdwniayCltG/Q1smS4iFEHNI5ayLZj1qJGMHwzqGiRr4KknJKfHzv
+fl4NQaFyMY31s1FRIS6QVIRFHVzUAlKZTdzwqEJygg3fUS9n9uDBnyDI/sW7DQuj
+yjSmYRS1hw==
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientca-key.pem b/plugins/tests/certs/clientca-key.pem
new file mode 100644
index 0000000..a939f03
--- /dev/null
+++ b/plugins/tests/certs/clientca-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLGJawauwkUfDd
+VHSmoe+JdR9t8ozDwtoLEjkRBl8iewxWQEgZYRa0VbqoO4A6wx3Oyso6dBE023zn
+a2z/RTP77PzPKyhq4AalzgmcJm4zkDUNTkIVcHHDoDH7V+3dSxO3wLqR8t+zyY8J
+u01WoAesysioPGw1JFHFBKqTOnW8PyvBIpxsHWG7b6W63VsSox7t2nz2Mo61zob/
+W0dQVC4sAYWhf+qT3I+xyZA3Mvphss/ib2v/jXo+zFawB/Jj3uGahijqZIK57kuZ
+5qc6yN/grOr3SEglHCumJQabEaNb608sSFAFnDoLbAfI3vhgglhfbFETPaKNPSaC
+yp2E7lnHAgMBAAECggEAJqAWiJbNMlsjI/Tb+pTxqYLM52wpuVFlhpWApOxBS517
+SywOikUcvE9RoI0wZfyVvq5yp4tLenID3z9fC21t5Yu8yOm8VhclLINy8G+epc/X
+RyCLEOjBuiLNXq/qXRvaNChDU16NjPPYcFFe9AqbaxFl+BkFu1Wc94tbpYSIv7Qt
+L6iBxUTXdgvLM5doa9AazIQzJx+jUsVCgRVQQf3zsLqtp9hH0Pfq+KWFIy5TA+bG
+0NFmYyQndRjtT0ihWGuNU7D8AXa+z7abzk+HydIlx4D//vGgdNq92QYPdnu2BBya
+5Fs6LkmkUonX/I8FbkLbRKkQWNPMt+Ks21t3xcVBgQKBgQDn4HuHVCPwxgU6Mv+5
+0sHJXYBq1fDzrUt0+iTtYkRqViX+9Mp4sUpYgXext/wXFLcKzQQp5B0g1dLYLSRS
+KwhsdiN0J7ZcoP1GMStw8zsayRTf8C3WRU6aACqyFiylYbyh56XomfYgwhja/7l9
+pzpVJD9ecG+mLVAyAkJtK2JolQKBgQDgOZfvrQj0L4QG+9E5VmFc3PE+6k3g+zDO
+MWqTSh0fOHqdTEyet4bMC4DogXGVsvw0/UKwbrGHOk0+ltA5VyKUtK/whSutr/+S
+nhCHljhV0XUN/I3OFcvezFjM3g0oC4uy1cL30hoM4IfeHM1d3EYse9N1Y/Op+mR6
+Sx+fEku16wKBgQC0KQ7RjuZ95N2a4pUe5En9EtD8MU4Nhs/iC5k1d+yAUn8jIT9P
+lzCUo8NEKheMN2Qg2Dor8jlPkdNIc4qM7TKWUxQo49IlFlCzgPCnydRac3HsrMhw
+e1ke/pIt3FzEArR1d27I0xcRTL3TKm4M2ynPjWJPFj0peHue33KNL/A+IQKBgEpL
+awd0Sxo1wEZcG9gmwf32C01wbzuTn3lCsHB7Ryj4GtCR3nVclCJ50U24zjzu4Fhi
+bj1tgA8xhzSs3fOR5phlQkKsrWtQfJtFGm8CnEn7LBDlVMsrN7Dr/qRrEuro4HHy
+GDbq+8y2fO5glr955BqLMOadprf0imRnDeQ0OLffAoGBAJio+X+xpglgMOC4BeH9
+9LcYi9nUEw8MDJNGo9/3e0XKA7spd3HShLDvt8YZhFJ2m168qBpGfezuw0+jpWxy
+PV9q0dokAgDx4pvCzIKaptZ1D30CWXJZHq25VK1tA41PCUIOh8JD5+R0MpxA5rn2
+DbqL4Vq7K7K0imGENYhHdyM+
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientchain-cert.pem b/plugins/tests/certs/clientchain-cert.pem
new file mode 100644
index 0000000..acd1e3e
--- /dev/null
+++ b/plugins/tests/certs/clientchain-cert.pem
@@ -0,0 +1,45 @@
+-----BEGIN CERTIFICATE-----
+MIIDuTCCAqECAQQwDQYJKoZIhvcNAQELBQAwgaAxCzAJBgNVBAYTAkRFMRAwDgYD
+VQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0b3Jp
+bmcgUGx1Z2luczEkMCIGA1UEAwwbTW9uaXRvcmluZyBQbHVnaW5zIENsaWVudENB
+MSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMub3JnMB4X
+DTIxMDIyODIxMDIxMloXDTMwMTEyODIxMDIxMlowgaMxCzAJBgNVBAYTAkRFMRAw
+DgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gxGzAZBgNVBAoMEk1vbml0
+b3JpbmcgUGx1Z2luczEnMCUGA1UEAwweTW9uaXRvcmluZyBQbHVnaW5zIENsaWVu
+dENoYWluMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdpbnMu
+b3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAphvoJBbi/rDvm3+X
+8xok0sLCJvCRuUpSbU5wEmREQlkoOGmWK4l6r1JyOphKRBo8+n2MxPiCMvAmTrqx
+VlBmkcmyrwWj392Nga+2SLWTziASk5nFrrhV6U79PkgXnETV2Wk1/FNVIFkB8N+B
+undsTce8LLiCs7hfA5CK7ctJg8fqsAsmgKBNGzBRWwkbvxZPd6xlY6foIJeD7PQ2
+elvTmrD6WXSZq7GshFpDEkL3AifqrPMdsTnbBpyGgJ/fBM1b2dx9k53e25mgEQmn
+iSuYQxn08BsUT0FOvav8ksZLBQz859fuqCtwhikpODO635fD9zK5YkBPlVl+/5xo
+SvKOywIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBh4zeSKjENfY+VDLtPssaNQz2a
+R1ioY40lZ0WoihDSrfG32dqTK/R2YsLKBABjJ7uRYS1NIBMrtS2OktK8BWD5IUTF
+FuGuWilu6IWiTKZrLiZh1rsilNDVqwhorRPxDnbF+qVt9EMIvzKnKdJLGF+CWHN9
+yYJDeTD8MK5uR7zUJR3PsgW4ve5pFTi7z2UJ/xRvgOds6bmeeQnvaWDEL7k2+hrr
+0G899A086NL3htzaOnIllg0xo2D1o4ToncAJn+cUQVJmHZSg9HYiD4Lg3z8uXPAl
+rt/MX7dBm4dnImLXbSg7N3e8FdUtz+kZT9z+beKAeIe9JTbpxtsVUTzUZBBA
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID2jCCAsKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBoDELMAkGA1UEBhMCREUx
+EDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwSTW9u
+aXRvcmluZyBQbHVnaW5zMSQwIgYDVQQDDBtNb25pdG9yaW5nIFBsdWdpbnMgQ2xp
+ZW50Q0ExKzApBgkqhkiG9w0BCQEWHGRldmVsQG1vbml0b3JpbmctcGx1Z2lucy5v
+cmcwHhcNMjEwMjI4MjEwMjEyWhcNMzAxMTI4MjEwMjEyWjCBqjELMAkGA1UEBhMC
+REUxEDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwS
+TW9uaXRvcmluZyBQbHVnaW5zMS4wLAYDVQQDDCVNb25pdG9yaW5nIFBsdWdpbnMg
+Q2xpZW50SW50ZXJtZWRpYXRlMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9y
+aW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+6rUgOZ9pAOxrcgeeOT3Vmu1YmY2O/C9tXhpKzDzjTaWUzcdDg00KdsjXfgbDzSiV
+uvMzjX63aKpmqeFG+05D2VzQGit3knqerUgl10FnTotiJGF5CU5/gY1aPxTJ7rj2
+tD6LINBkJcPTyQ4MoJT19pssvCax9erY1RxoXxLblJ+31C+VvrftdmBP4nVKXK26
+4anb1oUQhkgpXpJimJBmF+v7NbDs1Wh21Be80KXUh9SKgePhSQblr2QlRcA7jLgJ
+4PMjZ+KYF+da+4RB7s+DvTXVDMn9AL84E1w5Ut1E8XZV+u4RjWPvNdhK/7GnuxOR
+C9SdxonqkPQ8hiI7thP9bQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBCwUAA4IBAQDKQeiDbyr0/7sEhX33MmTDv84GeWgKl9qqHecx+d/0vImb
+c8XHK0PDa4lVqo/BW4P1hjKzpt2DW35kbOhuqGqM0lasIczef43aCDDEBLwstAe6
+qMoyWGVGoAQbpwT3li2pMrsIYoPwMvoSGNUphjrkdpviff2POkLly7a5RrR1X3qt
+Dai6eYbeMCr9NdgW7AZ5++/sKlFoe+zVk/Ed31s4D2lh3awrApZhVgcoquPmEwpt
+gm+OgRmHw50U4SF3ZaJPwDyLMbx+clH/bgUg0+Za9e53Br1NtGKmw7hh/7CG/hy0
+yxeLd930pH4vZu7s0XM56N/ckkfUzRkAH8dSmhH4
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientchain-key.pem b/plugins/tests/certs/clientchain-key.pem
new file mode 100644
index 0000000..0263604
--- /dev/null
+++ b/plugins/tests/certs/clientchain-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmG+gkFuL+sO+b
+f5fzGiTSwsIm8JG5SlJtTnASZERCWSg4aZYriXqvUnI6mEpEGjz6fYzE+IIy8CZO
+urFWUGaRybKvBaPf3Y2Br7ZItZPOIBKTmcWuuFXpTv0+SBecRNXZaTX8U1UgWQHw
+34G6d2xNx7wsuIKzuF8DkIrty0mDx+qwCyaAoE0bMFFbCRu/Fk93rGVjp+ggl4Ps
+9DZ6W9OasPpZdJmrsayEWkMSQvcCJ+qs8x2xOdsGnIaAn98EzVvZ3H2Tnd7bmaAR
+CaeJK5hDGfTwGxRPQU69q/ySxksFDPzn1+6oK3CGKSk4M7rfl8P3MrliQE+VWX7/
+nGhK8o7LAgMBAAECggEAAfTqMyKh4eYrrGVAYPi53lG0/8htrwUVG3yFDXJo628p
+biCwSCsCavZJqi8JEOxOM5UvB1L2FauGh/7i/+VKkAUUOcOTPpvZguGTACBDcXYn
+Qd3Z2kkJmgn4Kbenr4uQCVOX8zT4F710rGW1nYCyoefsa4pw37UYSW52dH6kiwzW
+9k4X251nDMl/twBdOcjZbL768IEa5l4nySLpUNwfrVbSb1NzBoH0dVioh3DTLjt6
+gaShW4eIpaKczht1U97n6/7WNLl6vHX/mR99k/py8OhzhR1ccYpd2IfSHAWyQT0M
+K8BoNnkjICrr9oc0FCr2BVJa3IzKHlhukF4GTZiGYQKBgQDWCHTwAmwL4FFEBVhj
+pZne/sjaZc8TzPPxA8SkmxwDIZrM7tSu7qUuYgWTM432jZbLILWTyGfXf2PpqyF6
+wOpoBJj1ETkre8ZfRmYvsSvS5vtjF3Drszol+XvZnOclfB5VG3m5P2vYkQ8wI9OE
+Y5jUBgDj0RsCNd8QnrC1u54U/wKBgQDGrd5y8S9kUT0P0lkZit7bYjSPJExtClXt
+V7YNTjELrVCdc0jranxBWaub8NP3e6TGTi9HiQWvk2eOAS2qyccqlK4+YAK5XO3D
+EpFUNNcClq8CErw2POuCAKajrPuSp6vd6q8h4lTzDExVctQS4R9fRKKFBKkPUV5G
+UiKFllnKNQKBgQDBGIQXfLfpxwjKK2BhFihKDOc8UhmOrZtvV4zzTJTrJkg4l0f+
+QoN34ytQcHSleXwP6oSmvWkh/GYxjBj6XE2eZndwsYc4ecSwdB0A7gCxl345Gg7g
+NqRBWmGoJGxNXzsmYVFiFZvAmK5xKgFMMWbR8lCfOCn7xopmviSC8K9gFQKBgFRb
+KmH/SbH8VELNews/TVQ0pEBKlzCM/OLjJOcNVgGxOtM/Say677sHibeST0168AFK
+3QQwh3t+yK8gjPVA6xGHQ1w0g7OUY1c6IP5x2QC+XdwxfDxDLXNrN1WzcrVX/78f
+j/CBGrR/ekGlmanSb/GRQLfdvLJGSBLveLzjk4gpAoGBANN9RUm/aRz3dDBWex46
+kJ15xKJfLZiUeyDvY5+5d7YF4/tw5LU4XmKQNhiojHecykrTzPUMaGyMrbMPNn32
+WFW9CKMjuBEwWpMDJJb1/5NLEvpwu++sr7bUPZkQl76ot6OqgNHodbP8ATqrNr80
+5b8FrEN1LyfkTbabxNyAWcA0
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/clientintermediate-cert.pem b/plugins/tests/certs/clientintermediate-cert.pem
new file mode 100644
index 0000000..608a8fa
--- /dev/null
+++ b/plugins/tests/certs/clientintermediate-cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID2jCCAsKgAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBoDELMAkGA1UEBhMCREUx
+EDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwSTW9u
+aXRvcmluZyBQbHVnaW5zMSQwIgYDVQQDDBtNb25pdG9yaW5nIFBsdWdpbnMgQ2xp
+ZW50Q0ExKzApBgkqhkiG9w0BCQEWHGRldmVsQG1vbml0b3JpbmctcGx1Z2lucy5v
+cmcwHhcNMjEwMjI4MjEwMjEyWhcNMzAxMTI4MjEwMjEyWjCBqjELMAkGA1UEBhMC
+REUxEDAOBgNVBAgMB0JhdmFyaWExDzANBgNVBAcMBk11bmljaDEbMBkGA1UECgwS
+TW9uaXRvcmluZyBQbHVnaW5zMS4wLAYDVQQDDCVNb25pdG9yaW5nIFBsdWdpbnMg
+Q2xpZW50SW50ZXJtZWRpYXRlMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9y
+aW5nLXBsdWdpbnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+6rUgOZ9pAOxrcgeeOT3Vmu1YmY2O/C9tXhpKzDzjTaWUzcdDg00KdsjXfgbDzSiV
+uvMzjX63aKpmqeFG+05D2VzQGit3knqerUgl10FnTotiJGF5CU5/gY1aPxTJ7rj2
+tD6LINBkJcPTyQ4MoJT19pssvCax9erY1RxoXxLblJ+31C+VvrftdmBP4nVKXK26
+4anb1oUQhkgpXpJimJBmF+v7NbDs1Wh21Be80KXUh9SKgePhSQblr2QlRcA7jLgJ
+4PMjZ+KYF+da+4RB7s+DvTXVDMn9AL84E1w5Ut1E8XZV+u4RjWPvNdhK/7GnuxOR
+C9SdxonqkPQ8hiI7thP9bQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBCwUAA4IBAQDKQeiDbyr0/7sEhX33MmTDv84GeWgKl9qqHecx+d/0vImb
+c8XHK0PDa4lVqo/BW4P1hjKzpt2DW35kbOhuqGqM0lasIczef43aCDDEBLwstAe6
+qMoyWGVGoAQbpwT3li2pMrsIYoPwMvoSGNUphjrkdpviff2POkLly7a5RrR1X3qt
+Dai6eYbeMCr9NdgW7AZ5++/sKlFoe+zVk/Ed31s4D2lh3awrApZhVgcoquPmEwpt
+gm+OgRmHw50U4SF3ZaJPwDyLMbx+clH/bgUg0+Za9e53Br1NtGKmw7hh/7CG/hy0
+yxeLd930pH4vZu7s0XM56N/ckkfUzRkAH8dSmhH4
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/clientintermediate-key.pem b/plugins/tests/certs/clientintermediate-key.pem
new file mode 100644
index 0000000..13f6887
--- /dev/null
+++ b/plugins/tests/certs/clientintermediate-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqtSA5n2kA7Gty
+B545PdWa7ViZjY78L21eGkrMPONNpZTNx0ODTQp2yNd+BsPNKJW68zONfrdoqmap
+4Ub7TkPZXNAaK3eSep6tSCXXQWdOi2IkYXkJTn+BjVo/FMnuuPa0Posg0GQlw9PJ
+DgyglPX2myy8JrH16tjVHGhfEtuUn7fUL5W+t+12YE/idUpcrbrhqdvWhRCGSCle
+kmKYkGYX6/s1sOzVaHbUF7zQpdSH1IqB4+FJBuWvZCVFwDuMuAng8yNn4pgX51r7
+hEHuz4O9NdUMyf0AvzgTXDlS3UTxdlX67hGNY+812Er/sae7E5EL1J3GieqQ9DyG
+Iju2E/1tAgMBAAECggEACyYJXtNUoIeaXvM/r8ZhJBfMEpcnyJDUKBklnmfyABky
+ZUfmzBDXw2as3b6ihFc+LYAp3bm8KouVjtI1lfBUxrli5StVZa7PZLm9mmjv6Eo0
+ojfDEQ8afWPieoaZRO6iQVOLNkbPyv9vSuiQ7vvEZy9dw54u69h47j6IMqPprDiG
+ropUNeGAvTnh1Vf9/8aCHEvHUNHcc4zjzGiQ+E60JgnbpGVeJKoeiMgrQE0yjweo
+KyKA47Y6vqP6+AxAaPplXtmrx2UCbMjktHNvLvg42+2UlLS5roiwmJYEN9c6iT6t
+y82MJrjEFGZyLG2u6ZQANSJiIWaCnOyT1o2deJ8NoQKBgQD7UxivDTuljQD0so+E
+JX9UaFZ9PgS+8LC9v56PciL4XQ7bcCVP5vVgZZPABiQ9i989Wq7qI042Jrfu5qtE
+SthlOAu80GvAQV+Oujwo7ZzM6ciQtjMsj63r2uayWXnmQ07QcIg7x7y161Pt9Bqr
+LIDrqHziIj/lzT7+6QKZaQwFaQKBgQDvEuSC14CBlMhy2jji71kB/3Ya3c+8dP+A
+kQZL9wEWK4a4dm8IaTS8jl1/luhQUzFRMyh2rWaTqqigSe3dvs5DRblhE5NPwTSI
+9TO7t1EnzjW3R8LxZZsySyiSFnZ/8mR0empxq0Mov37OdXBj0tXuuzREf/hwijWh
+WuLxJUSjZQKBgAIDZ2Y3l+u6lnBfYdDwL/XwJAk6zvTsnq3WdCG4C1mr/St62YGr
+WvnbtnRKWE356d7m9BHCGKVMaBrM1EBmzRb6fPWVQde3blmJWmQFi0UE9mtaWkyY
+Fg+WoFR7bQOQNHhs/lpkPjnC2dhFJVWLtLiuj9mL5rEjlMab/T5XXhZJAoGBAMEP
+FZ8fXbPGrTQqSwPfWpZFcF9zvbynEmkFM/uGRMddcNZnNXSqWJ7nrFNLTuEGvW2g
+DU4A6zPV/YQrDz4hRjmHBZOCFlSyZbUvpY4yFAQ7/p66AY+kiHZNwT5vi1P5Luvs
+qyaNsZcnRMR+i7rg2EeHv0aNvNdMlNBvL5KikNINAoGAU2P/phdwJOUcqgHavQcQ
+ureTEyZ5i5AeNomNeHSj0slG24V9nxOqEL7D00JKln7oAPovYBUWocEnF39uBJe0
+p0Hy7fCCK6EI8/0QyiQuuZmJfDEEvjQqE6irONNH63r2UwDEpDNGFvGsZNuWHLZc
+SXADu5oSNu6o6IydiyOx528=
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/expired-cert.pem b/plugins/tests/certs/expired-cert.pem
new file mode 100644
index 0000000..87fc8e4
--- /dev/null
+++ b/plugins/tests/certs/expired-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEETCCAvmgAwIBAgIUVDKkhcUoYFnjYCw12tScPIqQzqIwDQYJKoZIhvcNAQEL
+BQAwgZcxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
+dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9u
+aXRvcmluZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5n
+LXBsdWdpbnMub3JnMB4XDTA4MDEwMTEyMDAwMFoXDTA4MDEwMjEyMDAwMFowgZcx
+CzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gx
+GzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9uaXRvcmlu
+ZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdp
+bnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwg1dmGT3rVqM
+beVWWLy8EAiq9re07AF8sTERy9oIYF5EUq9f0xO53mwwqIWV77O9mF99/kDFGQuQ
+NOnICMSHXNtMXEXzfBaMighw0uyCh1o/VCejNQ5x/HU8aLh930g5DIcOJQ3fZ4v9
+8kBaie7+aPgRMVDM1vIrILfedq9Kt56zvPizkXhDeqxjKyIZdrdoBlX5zAfftWtY
+HpQ+lkThSSXqQnchN6S2JFejmRtsNnceDVOBBdvlzmH0NlfwjynLK3/EJooTsINy
+i9dXD8/Oe8r+UA+nokWvnWC2IAUJjpxW+XAyTG/NofGwX+PwquT0YD5cSlODIwZA
+WAimygWLqQIDAQABo1MwUTAdBgNVHQ4EFgQUsKyJAwR9OXWEcSZMQz73GfpxCJIw
+HwYDVR0jBBgwFoAUsKyJAwR9OXWEcSZMQz73GfpxCJIwDwYDVR0TAQH/BAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAQEAYKFGX7J3Fc/T9s278w61E2dSsY4DS/mjSDik
+fMWvod6eKw0fE3wJOnkWxjEH3VywTY6CmHd/oiJOaD8lr/Vk+BJfYNVBaVNmguyg
+4LXoWz9Benx0bAIeuDbNAhOvA4H4aIz8UrD9lKFvKdRp42gPMLtMEbzbLcBdT95D
+6BX7EhYm7vTnpitLPgFxVCsJ1JFqv2AQfUm+IkqQkezPs5x0tWLyrvCDNRGJ0kfv
+UuowpUZXDOh3k1vB+xaSOFviieLaCW8TSdd5FZgI2HQj4e6vCKsMGuKKZXrMUTI/
+qtrFlUfsOuwourfC5LMHtCyYo5B3uvAWT1eTXxhrGqyleSlxJQ==
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/expired-key.pem b/plugins/tests/certs/expired-key.pem
new file mode 100644
index 0000000..c5bba56
--- /dev/null
+++ b/plugins/tests/certs/expired-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCDV2YZPetWoxt
+5VZYvLwQCKr2t7TsAXyxMRHL2ghgXkRSr1/TE7nebDCohZXvs72YX33+QMUZC5A0
+6cgIxIdc20xcRfN8FoyKCHDS7IKHWj9UJ6M1DnH8dTxouH3fSDkMhw4lDd9ni/3y
+QFqJ7v5o+BExUMzW8isgt952r0q3nrO8+LOReEN6rGMrIhl2t2gGVfnMB9+1a1ge
+lD6WROFJJepCdyE3pLYkV6OZG2w2dx4NU4EF2+XOYfQ2V/CPKcsrf8QmihOwg3KL
+11cPz857yv5QD6eiRa+dYLYgBQmOnFb5cDJMb82h8bBf4/Cq5PRgPlxKU4MjBkBY
+CKbKBYupAgMBAAECggEBAJ2mdCKJ7LoWdT4W8pZ3BqZUFGkKCF8wOhhOUDH3+ZQp
+IYK3XbdDMF7mMIXIuW4a7W4sLlTwU/Ar98U1JMESwRIMS7YvUke+ngDKKLcDVGwY
+Qpjg9vP0v2Al8qT1NbW/nDF0S2aJJbWfAvnblHK5ClFHL9iL107NQYJ8PqzXbnFL
+gCQRiZxVHlrbn/73ZUMHPGEoU0711U9hSjrsqrRuSAMC+V38s4HxOomZWutlVAHF
+HwClNZBqRO+a2njPyUuV9DM/rl5Tm9IQ89iFo3/QEORICK77HjJYhi+UzdfI5F35
+UntRJt+WLaiAP+K6Vt6oxHSm58qXnOkeLzaAunTTie0CgYEA6OLYfme8xe5zYXWX
+rqmKNYdcVfMkvL+vUfVT475o/piRtE54JC1LYWEFAN8paxEWHD5HZMy0+ONNXfGm
+zyNNTN/Lagz4WcpdFzKQmhfdro7DzRiDfdvwSLmaZDyE41PPPVVvfrI9IeDiUNY4
+nWLSb3sWo96Iuns+RoMqeA9wkqsCgYEA1U/UqeVQVTPlrWyiB2VXoI1xvFCCJTf8
+4NC0gcisxLRrtINk0BwrUJrRy0x1OLpJWiKwUl/W1GgvPPfhbYcUOb669JNtTIjY
+FeIZblCTjz9GzKKmXeDciXvccyEdCJVUlPO3/e2JiJ4mCDjULprifq0a2gcQevFS
+PfqVULhBOvsCgYB5KfS7J1vGmv36ucSWAe0/VlKLATqe3RfpCzt/JQTZWSWNaroF
+EG/ElUaWIoUZCEW5oglg/0Q0rYYGF4DTCingkhrx7ReVF70BIbSsBzi15d8nKNbY
+t4I3RCF4fyggYe1TmsysXS2DH85/gkToVY7oo2CvF0uJwi8vXnTNDDNkiwKBgHKs
+mAc94BHt9GtnGzQepx0I7TvvjAe2MZwqlt+uojKdS8mfWXMHscGDeYVxdRMqEoUC
+YQfnvfYyjDKaj/XxyE3C237gQsICTyh0hHdpmepIeidIyWdumyDOFZVPF+ylWvM4
+kpFQQb/QRWHmKyti2KCBLw5G/fUaBryLGfprE6ZBAoGBANy5rr41A679UQZ0abev
+bOZb7YWOHYp/wReJaQbvLAyR30os3aEY/0ht9S+OWdrgGMezPKvsx2Sqr/CwoFXI
+esiklpknr11maEPxnQJYi4FYiXS1a3NCg7yBvKzFEgx2XnMAC3s6zhuZXaFq4zNu
+pm5Btrq/NZqtVXovS+UhGLvJ
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/certs/ext.cnf b/plugins/tests/certs/ext.cnf
new file mode 100644
index 0000000..d09cee1
--- /dev/null
+++ b/plugins/tests/certs/ext.cnf
@@ -0,0 +1,2 @@
+[ client_ca ]
+basicConstraints = critical, CA:true
diff --git a/plugins/tests/certs/generate-certs.sh b/plugins/tests/certs/generate-certs.sh
new file mode 100755
index 0000000..78660a2
--- /dev/null
+++ b/plugins/tests/certs/generate-certs.sh
@@ -0,0 +1,63 @@
+#!/bin/sh -e
+#
+# Recreates the https server certificates
+#
+# Set the GEN_EXPIRED environment variable to also regenerate
+# the expired certificate.
+
+cd "$(dirname "$0")"
+trap 'rm -f *.csr; rm -f clientca-cert.srl' EXIT
+
+subj() {
+ c="DE"
+ st="Bavaria"
+ l="Munich"
+ o="Monitoring Plugins"
+ cn="Monitoring Plugins"
+ emailAddress="devel@monitoring-plugins.org"
+
+ if [ -n "$1" ]; then
+ # Add to CN
+ cn="$cn $1"
+ fi
+
+ printf "/C=%s/ST=%s/L=%s/O=%s/CN=%s/emailAddress=%s" \
+ "$c" "$st" "$l" "$o" "$cn" "$emailAddress"
+}
+
+# server
+openssl req -new -x509 -days 3560 -nodes \
+ -keyout server-key.pem -out server-cert.pem \
+ -subj "$(subj)"
+# server, expired
+# there is generally no need to regenerate this, as it will stay epxired
+[ -n "$GEN_EXPIRED" ] && TZ=UTC faketime -f '2008-01-01 12:00:00' \
+ openssl req -new -x509 -days 1 -nodes \
+ -keyout expired-key.pem -out expired-cert.pem \
+ -subj "$(subj)"
+
+# client, ca
+openssl req -new -x509 -days 3560 -nodes \
+ -keyout clientca-key.pem -out clientca-cert.pem \
+ -subj "$(subj ClientCA)"
+echo "01" >clientca-cert.srl
+# client
+openssl req -new -nodes \
+ -keyout client-key.pem -out client-cert.csr \
+ -subj "$(subj Client)"
+openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
+ -in client-cert.csr -out client-cert.pem
+# client, intermediate
+openssl req -new -nodes \
+ -keyout clientintermediate-key.pem -out clientintermediate-cert.csr \
+ -subj "$(subj ClientIntermediate)"
+openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
+ -extfile ext.cnf -extensions client_ca \
+ -in clientintermediate-cert.csr -out clientintermediate-cert.pem
+# client, chain
+openssl req -new -nodes \
+ -keyout clientchain-key.pem -out clientchain-cert.csr \
+ -subj "$(subj ClientChain)"
+openssl x509 -days 3560 -req -CA clientca-cert.pem -CAkey clientca-key.pem \
+ -in clientchain-cert.csr -out clientchain-cert.pem
+cat clientintermediate-cert.pem >>clientchain-cert.pem
diff --git a/plugins/tests/certs/server-cert.pem b/plugins/tests/certs/server-cert.pem
new file mode 100644
index 0000000..d1249ef
--- /dev/null
+++ b/plugins/tests/certs/server-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEETCCAvmgAwIBAgIUZwOhY4myaCUaPek3NM+MxbLG9vwwDQYJKoZIhvcNAQEL
+BQAwgZcxCzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZN
+dW5pY2gxGzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9u
+aXRvcmluZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5n
+LXBsdWdpbnMub3JnMB4XDTIxMDIyODIxMDIxMVoXDTMwMTEyODIxMDIxMVowgZcx
+CzAJBgNVBAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMQ8wDQYDVQQHDAZNdW5pY2gx
+GzAZBgNVBAoMEk1vbml0b3JpbmcgUGx1Z2luczEbMBkGA1UEAwwSTW9uaXRvcmlu
+ZyBQbHVnaW5zMSswKQYJKoZIhvcNAQkBFhxkZXZlbEBtb25pdG9yaW5nLXBsdWdp
+bnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/3eBA4WG6xz
+LfM6xcWywxThb1Rp7XAW3ewQd9/PdoWXEe8BJWlLfyYi1drLMcsDywhLkKmW4Vp9
+1R4PAkiljjrB/ZaUMDLJ1ri3dwX4RvXG7crsU3QWFWCBOrf5V2FTRQ2m/H/KyB/6
+rVZANsU47HqTFSPiUm2j7P3wx/wtHeYC+qmNG7zZTjAYPYxfKiod0lytTSmb+h54
+6lxn3+VPEXZAQZlLvPnm/58JnXGrUv7B2yocf5MhKkLJOrGxH2hfwKISfaj2gpOV
+m4PUVYiDzCSpq1fPvwbUxIvdO27xprx+mrGOFM6f2UCEOc35w8FSmYiR2yQTnEJK
+pbSQD6t1jQIDAQABo1MwUTAdBgNVHQ4EFgQUMeYgglT2aWDlF8KEeF2376AlTGYw
+HwYDVR0jBBgwFoAUMeYgglT2aWDlF8KEeF2376AlTGYwDwYDVR0TAQH/BAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAQEAFcEg83rTJdgkp7JLYqK0j8JogSHNlDYchr/r
+VxKBgQwfnjSp5A8d5+uTQ9s3QDabw8v7YeSrzYXbbjuWZ61mnl84tzOQ8LMeESnC
+CBXRCxB8Ow22WsVTVJq279SGYT+cZrdsmqGVWDi1A0C5kH+XTLAioG5CZmmxemD/
+S92ZoRxGyYfg33r+3X6EMcEYtHKGxCUa3EPcPOL4dq2F3nOnyjiWPZm3786H3NY2
+nsYwrEhAdUFtbYSsV5O0c/Zlc33fmTfh654ab35io1DtwmFo7q8J532dUE007EN0
+mIQmhdrjNJJHIftgSt0fuN5m48oLOnX7vvkz+X0WLWfVTtMr0w==
+-----END CERTIFICATE-----
diff --git a/plugins/tests/certs/server-key.pem b/plugins/tests/certs/server-key.pem
new file mode 100644
index 0000000..0de63f8
--- /dev/null
+++ b/plugins/tests/certs/server-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDb/d4EDhYbrHMt
+8zrFxbLDFOFvVGntcBbd7BB33892hZcR7wElaUt/JiLV2ssxywPLCEuQqZbhWn3V
+Hg8CSKWOOsH9lpQwMsnWuLd3BfhG9cbtyuxTdBYVYIE6t/lXYVNFDab8f8rIH/qt
+VkA2xTjsepMVI+JSbaPs/fDH/C0d5gL6qY0bvNlOMBg9jF8qKh3SXK1NKZv6Hnjq
+XGff5U8RdkBBmUu8+eb/nwmdcatS/sHbKhx/kyEqQsk6sbEfaF/AohJ9qPaCk5Wb
+g9RViIPMJKmrV8+/BtTEi907bvGmvH6asY4Uzp/ZQIQ5zfnDwVKZiJHbJBOcQkql
+tJAPq3WNAgMBAAECggEBAIvJDUjQVpXxByL8eazviT5SR0jBf6mC3tTWykQRb7ck
+/bBEiRrnhDRf3CS9KP4TvO5G8BUU3a2GHYzM08akuKXeiiODidfyfbQ1nUZBAdi9
+FVFF7tK8YcflkVfpTMOMMSggm6m33fc58sQvmQ/0U85XuJvnOEkeJ9pQJa49e8GR
+lpCQImF7ygltHPEz4o8qOtNMuPxiHOxpc517+ozQULZk153NTfGok1XctDFFZ3YX
+8okLSfcqZ28mdHYSvI9xf60Cm7cT9tunXHwZ0f1esTFiVYpAp+oTJqtdYxr/fYlL
+oO8G8iIQ7LjdJfgo84PscpKdSRCq3BfnmER1Eyg6hrUCgYEA/0hL5Y/haz/2jYGy
+aa8yZSuD1ZcWtj7pLKrBQnHPHIHsjSBggWhopvonCFvCjgSS1pOFOUAwMGc0T+Dw
+rWo3w8cEUyECl3Bw8gbCWtRXaigzU9TPgCWyx1j5dTopQhLObzS/m7fJFElnYNru
+jqhsUfWS+NKk8a5+A7i9lv4iBLMCgYEA3Jws3Lfj/Xs7LljrvryTMpPthvUGBcyt
+U9Qmf1Hmur90RP5V1rx4FqPQzIeaGQyZDNIUnkhBSqQZNCts3Rzay7N4uQzk8OEg
+S8Llnw76wLwi0SJ4okDtT5tpTR6fcS0M9lGN+zvvfUB4+ul8oub0pMcyme/pywEz
+ap+x3xAQPL8CgYEAiYOBVtTNof9fqdRurh1w8SyipKDx3BRBeQ02c7tozLt0GIWT
+VsJOdXwVIJyFTglKrAnlXvSjwL8nX8wU+eVYyr5fJwSGJ9urC8T2VwVBXW7wTz04
+1Zf5GQdlwW8mIHCPATqR6Kj0yVfNN1BX50L0rqWxmRWnQoUzXn/aqQaWfp8CgYAW
+9693/zEeR8EejyVkAy/z+RCml0XcPrXg31pusPErihkpwazgIVkDSmTHlmqFpxkc
+C5cX73/UrIbvNoIr9wAUawfrhBsltNpu6MiNKbsTa8LYMRWMFuReAFkTLVf+KWmL
+D2yPtmq1iIvP25UdRJw9t3teKWsWtnZK6HtVNM/r8wKBgQDKlqUpy8r4KK+S2w80
+H7rAQJo1DgXsYrgSa2gfppSKro4lm3ltyAfVIrKQKP7uCo9xTGKVQAUPttMs2+17
+nwbwvt7/nG7G1Dk/C/t6b7SJ80VY5b9ZZKIJ0wOjajLufSjPNCe0ZTRn32XusZUn
+nYGB5/QXYr5WGV9YhAkRsFJYgA==
+-----END PRIVATE KEY-----
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
new file mode 100755
index 0000000..3c91483
--- /dev/null
+++ b/plugins/tests/check_curl.t
@@ -0,0 +1,526 @@
+#! /usr/bin/perl -w -I ..
+#
+# Test check_http by having an actual HTTP server running
+#
+# To create the https server certificate:
+# openssl req -new -x509 -keyout server-key.pem -out server-cert.pem -days 3650 -nodes
+# to create a new expired certificate:
+# faketime '2008-01-01 12:00:00' openssl req -new -x509 -keyout expired-key.pem -out expired-cert.pem -days 1 -nodes
+# Country Name (2 letter code) [AU]:DE
+# State or Province Name (full name) [Some-State]:Bavaria
+# Locality Name (eg, city) []:Munich
+# Organization Name (eg, company) [Internet Widgets Pty Ltd]:Monitoring Plugins
+# Organizational Unit Name (eg, section) []:
+# Common Name (e.g. server FQDN or YOUR name) []:Monitoring Plugins
+# Email Address []:devel@monitoring-plugins.org
+
+use strict;
+use Test::More;
+use NPTest;
+use FindBin qw($Bin);
+
+$ENV{'LC_TIME'} = "C";
+
+my $common_tests = 73;
+my $ssl_only_tests = 8;
+# Check that all dependent modules are available
+eval "use HTTP::Daemon 6.01;";
+plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@;
+eval {
+ require HTTP::Status;
+ require HTTP::Response;
+};
+
+my $plugin = 'check_http';
+$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
+
+# look for libcurl version to see if some advanced checks are possible (>= 7.49.0)
+my $advanced_checks = 12;
+my $use_advanced_checks = 0;
+my $required_version = '7.49.0';
+my $virtual_host = 'www.somefunnyhost.com';
+my $virtual_port = 42;
+my $curl_version = '';
+open (my $fh, '-|', "./$plugin --version") or die;
+while (<$fh>) {
+ if (m{libcurl/([\d.]+)\s}) {
+ $curl_version = $1;
+ last;
+ }
+}
+close ($fh);
+if ($curl_version) {
+ my ($major, $minor, $release) = split (/\./, $curl_version);
+ my ($req_major, $req_minor, $req_release) = split (/\./, $required_version);
+ my $check = ($major <=> $req_major or $minor <=> $req_minor or $release <=> $req_release);
+ if ($check >= 0) {
+ $use_advanced_checks = 1;
+ print "Found libcurl $major.$minor.$release. Using advanced checks\n";
+ }
+}
+
+if ($@) {
+ plan skip_all => "Missing required module for test: $@";
+} else {
+ if (-x "./$plugin") {
+ plan tests => $common_tests * 2 + $ssl_only_tests + $advanced_checks;
+ } else {
+ plan skip_all => "No $plugin compiled";
+ }
+}
+
+my $servers = { http => 0 }; # HTTP::Daemon should always be available
+eval { require HTTP::Daemon::SSL };
+if ($@) {
+ diag "Cannot load HTTP::Daemon::SSL: $@";
+} else {
+ $servers->{https} = 0;
+}
+
+# set a fixed version, so the header size doesn't vary
+$HTTP::Daemon::VERSION = "1.00";
+
+my $port_http = 50000 + int(rand(1000));
+my $port_https = $port_http + 1;
+my $port_https_expired = $port_http + 2;
+
+# This array keeps sockets around for implementing timeouts
+my @persist;
+
+# Start up all servers
+my @pids;
+my $pid = fork();
+if ($pid) {
+ # Parent
+ push @pids, $pid;
+ if (exists $servers->{https}) {
+ # Fork a normal HTTPS server
+ $pid = fork();
+ if ($pid) {
+ # Parent
+ push @pids, $pid;
+ # Fork an expired cert server
+ $pid = fork();
+ if ($pid) {
+ push @pids, $pid;
+ } else {
+ my $d = HTTP::Daemon::SSL->new(
+ LocalPort => $port_https_expired,
+ LocalAddr => "127.0.0.1",
+ SSL_cert_file => "$Bin/certs/expired-cert.pem",
+ SSL_key_file => "$Bin/certs/expired-key.pem",
+ ) || die;
+ print "Please contact https expired at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ exit;
+ }
+ } else {
+ my $d = HTTP::Daemon::SSL->new(
+ LocalPort => $port_https,
+ LocalAddr => "127.0.0.1",
+ SSL_cert_file => "$Bin/certs/server-cert.pem",
+ SSL_key_file => "$Bin/certs/server-key.pem",
+ ) || die;
+ print "Please contact https at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ exit;
+ }
+ }
+} else {
+ # Child
+ #print "child\n";
+ my $d = HTTP::Daemon->new(
+ LocalPort => $port_http,
+ LocalAddr => "127.0.0.1",
+ ) || die;
+ print "Please contact http at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ exit;
+}
+
+# give our webservers some time to startup
+sleep(3);
+
+# Run the same server on http and https
+sub run_server {
+ my $d = shift;
+ MAINLOOP: while (my $c = $d->accept ) {
+ while (my $r = $c->get_request) {
+ if ($r->method eq "GET" and $r->url->path =~ m^/statuscode/(\d+)^) {
+ $c->send_basic_header($1);
+ $c->send_crlf;
+ } elsif ($r->method eq "GET" and $r->url->path =~ m^/file/(.*)^) {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_file_response("$Bin/var/$1");
+ } elsif ($r->method eq "GET" and $r->url->path eq "/slow") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ sleep 1;
+ $c->send_response("slow");
+ } elsif ($r->url->path eq "/method") {
+ if ($r->method eq "DELETE") {
+ $c->send_error(HTTP::Status->RC_METHOD_NOT_ALLOWED);
+ } elsif ($r->method eq "foo") {
+ $c->send_error(HTTP::Status->RC_NOT_IMPLEMENTED);
+ } else {
+ $c->send_status_line(200, $r->method);
+ }
+ } elsif ($r->url->path eq "/postdata") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response($r->method.":".$r->content);
+ } elsif ($r->url->path eq "/redirect") {
+ $c->send_redirect( "/redirect2" );
+ } elsif ($r->url->path eq "/redir_external") {
+ $c->send_redirect(($d->isa('HTTP::Daemon::SSL') ? "https" : "http") . "://169.254.169.254/redirect2" );
+ } elsif ($r->url->path eq "/redirect2") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, 'redirected' ));
+ } elsif ($r->url->path eq "/redir_timeout") {
+ $c->send_redirect( "/timeout" );
+ } elsif ($r->url->path eq "/timeout") {
+ # Keep $c from being destroyed, but prevent severe leaks
+ unshift @persist, $c;
+ delete($persist[1000]);
+ next MAINLOOP;
+ } elsif ($r->url->path eq "/header_check") {
+ $c->send_basic_header;
+ $c->send_header('foo');
+ $c->send_crlf;
+ } elsif ($r->url->path eq "/header_broken_check") {
+ $c->send_basic_header;
+ $c->send_header('foo');
+ print $c "Test1:: broken\n";
+ print $c " Test2: leading whitespace\n";
+ $c->send_crlf;
+ } elsif ($r->url->path eq "/virtual_port") {
+ # return sent Host header
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, $r->header ('Host')));
+ } elsif ($r->url->path eq "/chunked") {
+ my $chunks = ["chunked", "encoding", "test\n"];
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, sub {
+ my $chunk = shift @{$chunks};
+ return unless $chunk;
+ sleep(1);
+ return($chunk);
+ }));
+ } else {
+ $c->send_error(HTTP::Status->RC_FORBIDDEN);
+ }
+ $c->close;
+ }
+ }
+}
+
+END {
+ foreach my $pid (@pids) {
+ if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
+ }
+};
+
+if ($ARGV[0] && $ARGV[0] eq "-d") {
+ while (1) {
+ sleep 100;
+ }
+}
+
+my $result;
+my $command = "./$plugin -H 127.0.0.1";
+
+run_common_tests( { command => "$command -p $port_http" } );
+SKIP: {
+ skip "HTTP::Daemon::SSL not installed", $common_tests + $ssl_only_tests if ! exists $servers->{https};
+ run_common_tests( { command => "$command -p $port_https", ssl => 1 } );
+
+ my $expiry = "Thu Nov 28 21:02:11 2030 +0000";
+
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
+ is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
+ is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" );
+
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
+ is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
+ like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
+
+ # Expired cert tests
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
+ is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
+ like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
+
+ $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
+ is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
+ is( $result->output,
+ 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.',
+ "output ok" );
+
+}
+
+my $cmd;
+
+# advanced checks with virtual hostname and virtual port
+SKIP: {
+ skip "libcurl version is smaller than $required_version", 6 unless $use_advanced_checks;
+
+ # http without virtual port
+ $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # http with virtual port (!= 80)
+ $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # http with virtual port (80)
+ $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+}
+
+# and the same for SSL
+SKIP: {
+ skip "libcurl version is smaller than $required_version and/or HTTP::Daemon::SSL not installed", 6 if ! exists $servers->{https} or not $use_advanced_checks;
+ # https without virtual port
+ $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # https with virtual port (!= 443)
+ $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # https with virtual port (443)
+ $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+}
+
+
+sub run_common_tests {
+ my ($opts) = @_;
+ my $command = $opts->{command};
+ if ($opts->{ssl}) {
+ $command .= " --ssl";
+ }
+
+ $result = NPTest->testCmd( "$command -u /file/root" );
+ is( $result->return_code, 0, "/file/root");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /file/root -s Root" );
+ is( $result->return_code, 0, "/file/root search for string");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
+ is( $result->return_code, 2, "Missing string check");
+ like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
+
+ $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
+ is( $result->return_code, 2, "Missing string check");
+ like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
+
+ $result = NPTest->testCmd( "$command -u /header_check -d foo" );
+ is( $result->return_code, 0, "header_check search for string");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /header_check -d bar" );
+ is( $result->return_code, 2, "Missing header string check");
+ like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
+
+ $result = NPTest->testCmd( "$command -u /header_broken_check" );
+ is( $result->return_code, 0, "header_check search for string");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" );
+
+ my $cmd;
+ $cmd = "$command -u /slow";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, "$cmd");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+ $result->output =~ /in ([\d\.]+) second/;
+ cmp_ok( $1, ">", 1, "Time is > 1 second" );
+
+ $cmd = "$command -u /statuscode/200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/200 -e 200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 201";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/200 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/203 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j HEAD -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j POST -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j GET -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -P foo -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j DELETE -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 1, $cmd);
+ like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j foo -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output );
+
+ $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # To confirm that the free doesn't segfault
+ $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /redirect";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f follow -u /redirect";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f follow -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f sticky -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # These tests may block
+ print "ALRM\n";
+
+ # stickyport - on full urlS port is set back to 80 otherwise
+ $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected";
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(2);
+ $result = NPTest->testCmd( $cmd );
+ };
+ alarm(0);
+ isnt( $@, "alarm\n", $cmd );
+ is( $result->return_code, 0, $cmd );
+
+ # Let's hope there won't be any web server on :80 returning "redirected"!
+ $cmd = "$command -f sticky -u /redir_external -t 5 -s redirected";
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(2);
+ $result = NPTest->testCmd( $cmd );
+ };
+ alarm(0);
+ isnt( $@, "alarm\n", $cmd );
+ isnt( $result->return_code, 0, $cmd );
+
+ # Test an external address - timeout
+ SKIP: {
+ skip "This doesn't seem to work all the time", 1 unless ($ENV{HTTP_EXTERNAL});
+ $cmd = "$command -f follow -u /redir_external -t 5";
+ eval {
+ $result = NPTest->testCmd( $cmd, 2 );
+ };
+ like( $@, "/timeout in command: $cmd/", $cmd );
+ }
+
+ $cmd = "$command -u /timeout -t 5";
+ eval {
+ $result = NPTest->testCmd( $cmd, 2 );
+ };
+ like( $@, "/timeout in command: $cmd/", $cmd );
+
+ $cmd = "$command -f follow -u /redir_timeout -t 2";
+ eval {
+ $result = NPTest->testCmd( $cmd, 5 );
+ };
+ is( $@, "", $cmd );
+
+ $cmd = "$command -u /chunked -s 'chunkedencodingtest' -d 'Transfer-Encoding: chunked'";
+ eval {
+ $result = NPTest->testCmd( $cmd, 5 );
+ };
+ is( $@, "", $cmd );
+}
diff --git a/plugins/tests/check_http.t b/plugins/tests/check_http.t
new file mode 100755
index 0000000..6078b27
--- /dev/null
+++ b/plugins/tests/check_http.t
@@ -0,0 +1,581 @@
+#! /usr/bin/perl -w -I ..
+#
+# Test check_http by having an actual HTTP server running
+#
+# To create the https server certificate:
+# ./certs/generate-certs.sh
+
+use strict;
+use Test::More;
+use NPTest;
+use FindBin qw($Bin);
+use IO::Socket::INET;
+
+$ENV{'LC_TIME'} = "C";
+
+my $common_tests = 71;
+my $virtual_port_tests = 8;
+my $ssl_only_tests = 12;
+my $chunked_encoding_special_tests = 1;
+# Check that all dependent modules are available
+eval "use HTTP::Daemon 6.01;";
+plan skip_all => 'HTTP::Daemon >= 6.01 required' if $@;
+eval {
+ require HTTP::Status;
+ require HTTP::Response;
+};
+
+my $plugin = 'check_http';
+$plugin = 'check_curl' if $0 =~ m/check_curl/mx;
+
+if ($@) {
+ plan skip_all => "Missing required module for test: $@";
+} else {
+ if (-x "./$plugin") {
+ plan tests => $common_tests * 2 + $ssl_only_tests + $virtual_port_tests + $chunked_encoding_special_tests;
+ } else {
+ plan skip_all => "No $plugin compiled";
+ }
+}
+
+my $servers = { http => 0 }; # HTTP::Daemon should always be available
+eval { require HTTP::Daemon::SSL };
+if ($@) {
+ diag "Cannot load HTTP::Daemon::SSL: $@";
+} else {
+ $servers->{https} = 0;
+}
+
+# set a fixed version, so the header size doesn't vary
+$HTTP::Daemon::VERSION = "1.00";
+
+my $port_http = 50000 + int(rand(1000));
+my $port_https = $port_http + 1;
+my $port_https_expired = $port_http + 2;
+my $port_https_clientcert = $port_http + 3;
+my $port_hacked_http = $port_http + 4;
+
+# This array keeps sockets around for implementing timeouts
+my @persist;
+
+# Start up all servers
+my @pids;
+# Fork a HTTP server
+my $pid = fork;
+defined $pid or die "Failed to fork";
+if (!$pid) {
+ undef @pids;
+ my $d = HTTP::Daemon->new(
+ LocalPort => $port_http,
+ LocalAddr => "127.0.0.1",
+ ) || die;
+ print "Please contact http at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ die "webserver stopped";
+}
+push @pids, $pid;
+
+# Fork the hacked HTTP server
+undef $pid;
+$pid = fork;
+defined $pid or die "Failed to fork";
+if (!$pid) {
+ # this is the fork
+ undef @pids;
+ my $socket = new IO::Socket::INET (
+ LocalHost => '0.0.0.0',
+ LocalPort => $port_hacked_http,
+ Proto => 'tcp',
+ Listen => 5,
+ Reuse => 1
+ );
+ die "cannot create socket $!n" unless $socket;
+ my $local_sock = $socket->sockport();
+ print "server waiting for client connection on port $local_sock\n";
+ run_hacked_http_server ( $socket );
+ die "hacked http server stopped";
+}
+push @pids, $pid;
+
+if (exists $servers->{https}) {
+ # Fork a normal HTTPS server
+ $pid = fork;
+ defined $pid or die "Failed to fork";
+ if (!$pid) {
+ undef @pids;
+ # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
+ local $SIG{'PIPE'} = 'IGNORE';
+ my $d = HTTP::Daemon::SSL->new(
+ LocalPort => $port_https,
+ LocalAddr => "127.0.0.1",
+ SSL_cert_file => "$Bin/certs/server-cert.pem",
+ SSL_key_file => "$Bin/certs/server-key.pem",
+ ) || die;
+ print "Please contact https at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ die "webserver stopped";
+ }
+ push @pids, $pid;
+
+ # Fork an expired cert server
+ $pid = fork;
+ defined $pid or die "Failed to fork";
+ if (!$pid) {
+ undef @pids;
+ # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
+ local $SIG{'PIPE'} = 'IGNORE';
+ my $d = HTTP::Daemon::SSL->new(
+ LocalPort => $port_https_expired,
+ LocalAddr => "127.0.0.1",
+ SSL_cert_file => "$Bin/certs/expired-cert.pem",
+ SSL_key_file => "$Bin/certs/expired-key.pem",
+ ) || die;
+ print "Please contact https expired at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ die "webserver stopped";
+ }
+ push @pids, $pid;
+
+ # Fork an client cert expecting server
+ $pid = fork;
+ defined $pid or die "Failed to fork";
+ if (!$pid) {
+ undef @pids;
+ # closing the connection after -C cert checks make the daemon exit with a sigpipe otherwise
+ local $SIG{'PIPE'} = 'IGNORE';
+ my $d = HTTP::Daemon::SSL->new(
+ LocalPort => $port_https_clientcert,
+ LocalAddr => "127.0.0.1",
+ SSL_cert_file => "$Bin/certs/server-cert.pem",
+ SSL_key_file => "$Bin/certs/server-key.pem",
+ SSL_verify_mode => IO::Socket::SSL->SSL_VERIFY_PEER | IO::Socket::SSL->SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ SSL_ca_file => "$Bin/certs/clientca-cert.pem",
+ ) || die;
+ print "Please contact https client cert at: <URL:", $d->url, ">\n";
+ run_server( $d );
+ die "webserver stopped";
+ }
+ push @pids, $pid;
+}
+
+# give our webservers some time to startup
+sleep(3);
+
+# Run the same server on http and https
+sub run_server {
+ my $d = shift;
+ while (1) {
+ MAINLOOP: while (my $c = $d->accept) {
+ while (my $r = $c->get_request) {
+ if ($r->method eq "GET" and $r->url->path =~ m^/statuscode/(\d+)^) {
+ $c->send_basic_header($1);
+ $c->send_crlf;
+ } elsif ($r->method eq "GET" and $r->url->path =~ m^/file/(.*)^) {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_file_response("$Bin/var/$1");
+ } elsif ($r->method eq "GET" and $r->url->path eq "/slow") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ sleep 1;
+ $c->send_response("slow");
+ } elsif ($r->url->path eq "/method") {
+ if ($r->method eq "DELETE") {
+ $c->send_error(HTTP::Status->RC_METHOD_NOT_ALLOWED);
+ } elsif ($r->method eq "foo") {
+ $c->send_error(HTTP::Status->RC_NOT_IMPLEMENTED);
+ } else {
+ $c->send_status_line(200, $r->method);
+ }
+ } elsif ($r->url->path eq "/postdata") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response($r->method.":".$r->content);
+ } elsif ($r->url->path eq "/redirect") {
+ $c->send_redirect( "/redirect2" );
+ } elsif ($r->url->path eq "/redir_external") {
+ $c->send_redirect(($d->isa('HTTP::Daemon::SSL') ? "https" : "http") . "://169.254.169.254/redirect2" );
+ } elsif ($r->url->path eq "/redirect2") {
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, 'redirected' ));
+ } elsif ($r->url->path eq "/redir_timeout") {
+ $c->send_redirect( "/timeout" );
+ } elsif ($r->url->path eq "/timeout") {
+ # Keep $c from being destroyed, but prevent severe leaks
+ unshift @persist, $c;
+ delete($persist[1000]);
+ next MAINLOOP;
+ } elsif ($r->url->path eq "/header_check") {
+ $c->send_basic_header;
+ $c->send_header('foo');
+ $c->send_crlf;
+ } elsif ($r->url->path eq "/virtual_port") {
+ # return sent Host header
+ $c->send_basic_header;
+ $c->send_crlf;
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, $r->header ('Host')));
+ } elsif ($r->url->path eq "/chunked") {
+ my $chunks = ["chunked", "encoding", "test\n"];
+ $c->send_response(HTTP::Response->new( 200, 'OK', undef, sub {
+ my $chunk = shift @{$chunks};
+ return unless $chunk;
+ sleep(1);
+ return($chunk);
+ }));
+ } else {
+ $c->send_error(HTTP::Status->RC_FORBIDDEN);
+ }
+ $c->close;
+ }
+ }
+ }
+}
+
+sub run_hacked_http_server {
+ my $socket = shift;
+
+ # auto-flush on socket
+ $| = 1;
+
+
+ while(1)
+ {
+ # waiting for a new client connection
+ my $client_socket = $socket->accept();
+
+ # get information about a newly connected client
+ my $client_address = $client_socket->peerhost();
+ my $client_portn = $client_socket->peerport();
+ print "connection from $client_address:$client_portn";
+
+ # read up to 1024 characters from the connected client
+ my $data = "";
+ $client_socket->recv($data, 1024);
+ print "received data: $data";
+
+ # write response data to the connected client
+ $data = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n";
+ $client_socket->send($data);
+
+ # notify client that response has been sent
+ shutdown($client_socket, 1);
+ }
+}
+
+END {
+ foreach my $pid (@pids) {
+ if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
+ }
+};
+
+if ($ARGV[0] && $ARGV[0] eq "-d") {
+ while (1) {
+ sleep 100;
+ }
+}
+
+my $result;
+my $command = "./$plugin -H 127.0.0.1";
+
+run_chunked_encoding_special_test( {command => "$command -p $port_hacked_http"});
+run_common_tests( { command => "$command -p $port_http" } );
+SKIP: {
+ skip "HTTP::Daemon::SSL not installed", $common_tests + $ssl_only_tests if ! exists $servers->{https};
+ run_common_tests( { command => "$command -p $port_https", ssl => 1 } );
+
+ my $expiry = "Thu Nov 28 21:02:11 2030 +0000";
+
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
+ is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
+ is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" );
+
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
+ is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
+ like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
+
+ # Expired cert tests
+ $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
+ is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
+ like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
+
+ $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
+ is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
+ is( $result->output,
+ 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.',
+ "output ok" );
+
+ # client cert tests
+ my $cmd;
+ $cmd = "$command -p $port_https_clientcert"
+ . " -J \"$Bin/certs/client-cert.pem\""
+ . " -K \"$Bin/certs/client-key.pem\""
+ . " -u /statuscode/200";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -p $port_https_clientcert"
+ . " -J \"$Bin/certs/clientchain-cert.pem\""
+ . " -K \"$Bin/certs/clientchain-key.pem\""
+ . " -u /statuscode/200";
+ $result = NPTest->testCmd($cmd);
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+}
+
+my $cmd;
+# check virtual port behaviour
+#
+# http without virtual port
+$cmd = "$command -p $port_http -u /virtual_port -r ^127.0.0.1:$port_http\$";
+$result = NPTest->testCmd( $cmd );
+is( $result->return_code, 0, $cmd);
+like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+# http with virtual port
+$cmd = "$command:80 -p $port_http -u /virtual_port -r ^127.0.0.1\$";
+$result = NPTest->testCmd( $cmd );
+is( $result->return_code, 0, $cmd);
+like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+SKIP: {
+ skip "HTTP::Daemon::SSL not installed", 4 if ! exists $servers->{https};
+ # https without virtual port
+ $cmd = "$command -p $port_https --ssl -u /virtual_port -r ^127.0.0.1:$port_https\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # https with virtual port
+ $cmd = "$command:443 -p $port_https --ssl -u /virtual_port -r ^127.0.0.1\$";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+}
+
+
+sub run_common_tests {
+ my ($opts) = @_;
+ my $command = $opts->{command};
+ if ($opts->{ssl}) {
+ $command .= " --ssl";
+ }
+
+ $result = NPTest->testCmd( "$command -u /file/root" );
+ is( $result->return_code, 0, "/file/root");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /file/root -s Root" );
+ is( $result->return_code, 0, "/file/root search for string");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
+ is( $result->return_code, 2, "Missing string check");
+ like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
+
+ $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
+ is( $result->return_code, 2, "Missing string check");
+ like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
+
+ $result = NPTest->testCmd( "$command -u /header_check -d foo" );
+ is( $result->return_code, 0, "header_check search for string");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u /header_check -d bar" );
+ is( $result->return_code, 2, "Missing header string check");
+ like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
+
+ my $cmd;
+ $cmd = "$command -u /slow";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, "$cmd");
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+ $result->output =~ /in ([\d\.]+) second/;
+ cmp_ok( $1, ">", 1, "Time is > 1 second" );
+
+ $cmd = "$command -u /statuscode/200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/200 -e 200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 201";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 200";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/200 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/201 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /statuscode/203 -e 200,201,202";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j HEAD -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j POST -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j GET -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -P foo -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j DELETE -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 1, $cmd);
+ like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j foo -u /method";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 2, $cmd);
+ like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output );
+
+ $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # To confirm that the free doesn't segfault
+ $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /redirect";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f follow -u /redirect";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f follow -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f sticky -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ $cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
+ $result = NPTest->testCmd( $cmd );
+ is( $result->return_code, 0, $cmd);
+ like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
+
+ # These tests may block
+ print "ALRM\n";
+
+ # stickyport - on full urlS port is set back to 80 otherwise
+ $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected";
+ alarm(2);
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ $result = NPTest->testCmd( $cmd );
+ };
+ isnt( $@, "alarm\n", $cmd );
+ alarm(0);
+ is( $result->return_code, 0, $cmd );
+
+ # Let's hope there won't be any web server on :80 returning "redirected"!
+ $cmd = "$command -f sticky -u /redir_external -t 5 -s redirected";
+ alarm(2);
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ $result = NPTest->testCmd( $cmd );
+ };
+ isnt( $@, "alarm\n", $cmd );
+ alarm(0);
+ isnt( $result->return_code, 0, $cmd );
+
+ # Test an external address - timeout
+ SKIP: {
+ skip "This doesn't seem to work all the time", 1 unless ($ENV{HTTP_EXTERNAL});
+ $cmd = "$command -f follow -u /redir_external -t 5";
+ eval {
+ $result = NPTest->testCmd( $cmd, 2 );
+ };
+ like( $@, "/timeout in command: $cmd/", $cmd );
+ }
+
+ $cmd = "$command -u /timeout -t 5";
+ eval {
+ $result = NPTest->testCmd( $cmd, 2 );
+ };
+ like( $@, "/timeout in command: $cmd/", $cmd );
+
+ $cmd = "$command -f follow -u /redir_timeout -t 2";
+ eval {
+ $result = NPTest->testCmd( $cmd, 5 );
+ };
+ is( $@, "", $cmd );
+
+ $cmd = "$command -u /chunked -s 'chunkedencodingtest' -d 'Transfer-Encoding: chunked'";
+ eval {
+ $result = NPTest->testCmd( $cmd, 5 );
+ };
+ is( $@, "", $cmd );
+}
+
+sub run_chunked_encoding_special_test {
+ my ($opts) = @_;
+ my $command = $opts->{command};
+
+ $cmd = "$command -u / -s 'ChunkedEncodingSpecialTest'";
+ eval {
+ $result = NPTest->testCmd( $cmd, 5 );
+ };
+ is( $@, "", $cmd );
+}
diff --git a/plugins/tests/check_nt.t b/plugins/tests/check_nt.t
new file mode 100755
index 0000000..223d493
--- /dev/null
+++ b/plugins/tests/check_nt.t
@@ -0,0 +1,80 @@
+#! /usr/bin/perl -w -I ..
+#
+# Test check_nt by having a stub check_nt daemon
+#
+
+use strict;
+use Test::More;
+use NPTest;
+use FindBin qw($Bin);
+
+use IO::Socket;
+use IO::Select;
+use POSIX;
+
+my $port = 50000 + int(rand(1000));
+
+my $pid = fork();
+if ($pid) {
+ # Parent
+ #print "parent\n";
+ # give our webserver some time to startup
+ sleep(1);
+} else {
+ # Child
+ #print "child\n";
+
+ my $server = IO::Socket::INET->new(
+ LocalPort => $port,
+ Type => SOCK_STREAM,
+ Reuse => 1,
+ Proto => "tcp",
+ Listen => 10,
+ ) or die "Cannot be a tcp server on port $port: $@";
+
+ $server->autoflush(1);
+
+ print "Please contact me at port $port\n";
+ while (my $client = $server->accept ) {
+ my $data = "";
+ my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
+
+ my ($password, $command, $arg) = split('&', $data);
+
+ if ($command eq "4") {
+ if ($arg eq "c") {
+ print $client "930000000&1000000000";
+ } elsif ($arg eq "d") {
+ print $client "UNKNOWN: Drive is not a fixed drive";
+ }
+ }
+ }
+ exit;
+}
+
+END { if ($pid) { print "Killing $pid\n"; kill "INT", $pid } };
+
+if ($ARGV[0] && $ARGV[0] eq "-d") {
+ sleep 1000;
+}
+
+if (-x "./check_nt") {
+ plan tests => 5;
+} else {
+ plan skip_all => "No check_nt compiled";
+}
+
+my $result;
+my $command = "./check_nt -H 127.0.0.1 -p $port";
+
+$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l c" );
+is( $result->return_code, 0, "USEDDISKSPACE c");
+is( $result->output, q{c:\ - total: 0.93 Gb - used: 0.07 Gb (7%) - free 0.87 Gb (93%) | 'c:\ Used Space'=0.07Gb;0.00;0.00;0.00;0.93}, "Output right" );
+
+$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l d" );
+is( $result->return_code, 3, "USEDDISKSPACE d - invalid");
+is( $result->output, "Free disk space : Invalid drive", "Output right" );
+
+$result = NPTest->testCmd( "./check_nt -v USEDDISKSPACE -l d" );
+is( $result->return_code, 3, "Fail if -H missing");
+
diff --git a/plugins/tests/check_procs.t b/plugins/tests/check_procs.t
new file mode 100755
index 0000000..b3a0a30
--- /dev/null
+++ b/plugins/tests/check_procs.t
@@ -0,0 +1,148 @@
+#! /usr/bin/perl -w -I ..
+#
+# Test check_procs using input files
+#
+
+use strict;
+use Test::More;
+use NPTest;
+
+if (-x "./check_procs") {
+ plan tests => 54;
+} else {
+ plan skip_all => "No check_procs compiled";
+}
+
+my $result;
+my $command = "./check_procs --input-file=tests/var/ps-axwo.darwin";
+my $cmd_etime = "./check_procs --input-file=tests/var/ps-axwo.debian";
+
+$result = NPTest->testCmd( "$command" );
+is( $result->return_code, 0, "Run with no options" );
+is( $result->output, "PROCS OK: 95 processes | procs=95;;;0;", "Output correct" );
+
+$result = NPTest->testCmd( "$command -w 5" );
+is( $result->return_code, 1, "Checking > 5 processes" );
+is( $result->output, "PROCS WARNING: 95 processes | procs=95;5;;0;", "Output correct" );
+
+$result = NPTest->testCmd( "$command -w 4 -c 44" );
+is( $result->return_code, 2, "Checking critical" );
+is( $result->output, "PROCS CRITICAL: 95 processes | procs=95;4;44;0;", "Output correct" );
+
+$result = NPTest->testCmd( "$command -w 100 -c 200" );
+is( $result->return_code, 0, "Checking no threshold breeched" );
+is( $result->output, "PROCS OK: 95 processes | procs=95;100;200;0;", "Output correct" );
+
+$result = NPTest->testCmd( "$command -C launchd -c 5" );
+is( $result->return_code, 2, "Checking processes matched by command name" );
+is( $result->output, "PROCS CRITICAL: 6 processes with command name 'launchd' | procs=6;;5;0;", "Output correct" );
+
+$result = NPTest->testCmd( "$command -X bash -c 5" );
+is( $result->return_code, 2, "Checking processes excluded by command name" );
+is( $result->output, "PROCS CRITICAL: 95 processes with exclude progs 'bash' | procs=95;;5;0;", "Output correct" );
+
+SKIP: {
+ skip 'user with uid 501 required', 4 unless getpwuid(501);
+
+ $result = NPTest->testCmd( "$command -u 501 -w 39 -c 41" );
+ is( $result->return_code, 1, "Checking processes filtered by userid" );
+ like( $result->output, '/^PROCS WARNING: 40 processes with UID = 501 (.*)$/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -C launchd -u 501" );
+ is( $result->return_code, 0, "Checking processes filtered by command name and userid" );
+ like( $result->output, '/^PROCS OK: 1 process with command name \'launchd\', UID = 501 (.*)$/', "Output correct" );
+}
+
+SKIP: {
+ skip 'user with uid -2 required', 8 unless getpwuid(-2);
+ skip 'uid -2 must have name "nobody"', 8 unless getpwuid(-2) eq 'nobody';
+
+ $result = NPTest->testCmd( "$command -u -2 -w 2:2" );
+ is( $result->return_code, 1, "Checking processes with userid=-2" );
+ like( $result->output, '/^PROCS WARNING: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u -2 -w 3:3" );
+ is( $result->return_code, 0, "Checking processes with userid=-2 past threshold" );
+ like( $result->output, '/^PROCS OK: 3 processes with UID = -2 \(nobody\)$/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u -2 -a usb" );
+ is( $result->return_code, 0, "Checking processes with userid=-2 and usb in arguments" );
+ like( $result->output, '/^PROCS OK: 1 process with UID = -2 \(nobody\), args \'usb\'/', "Output correct" );
+
+ $result = NPTest->testCmd( "$command -u -2 -a UsB" );
+ is( $result->return_code, 0, "Checking case sensitivity of args" );
+ like( $result->output, '/^PROCS OK: 0 processes with UID = -2 \(nobody\), args \'UsB\'/', "Output correct" );
+};
+
+SKIP: {
+ skip 'check_procs is compiled with etime format support', 2 if `$command -vvv` =~ m/etime/mx;
+
+ $result = NPTest->testCmd( "$command --ereg-argument-array='mdworker.*501'" );
+ is( $result->return_code, 0, "Checking regexp search of arguments" );
+ is( $result->output, "PROCS OK: 1 process with regex args 'mdworker.*501' | procs=1;;;0;", "Output correct" );
+}
+
+SKIP: {
+ skip 'check_procs is compiled without etime format support', 2 if `$cmd_etime -vvv` !~ m/etime/mx;
+
+ $result = NPTest->testCmd( "$cmd_etime -m ELAPSED -C apache2 -w 1000 -c 2000" );
+ is( $result->return_code, 2, "Checking elapsed time threshold" );
+ is( $result->output, "ELAPSED CRITICAL: 10 crit, 0 warn out of 10 processes with command name 'apache2' | procs=10;;;0; procs_warn=0;;;0; procs_crit=10;;;0;", "Output correct" );
+}
+
+$result = NPTest->testCmd( "$command --vsz 1000000" );
+is( $result->return_code, 0, "Checking filter by VSZ" );
+is( $result->output, 'PROCS OK: 24 processes with VSZ >= 1000000 | procs=24;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command --rss 100000" );
+is( $result->return_code, 0, "Checking filter by RSS" );
+is( $result->output, 'PROCS OK: 3 processes with RSS >= 100000 | procs=3;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command -s S" );
+is( $result->return_code, 0, "Checking filter for sleeping processes" );
+like( $result->output, '/^PROCS OK: 88 processes with STATE = S/', "Output correct" );
+
+$result = NPTest->testCmd( "$command -s Z" );
+is( $result->return_code, 0, "Checking filter for zombies" );
+like( $result->output, '/^PROCS OK: 1 process with STATE = Z/', "Output correct" );
+
+$result = NPTest->testCmd( "$command -p 1 -c 30" );
+is( $result->return_code, 2, "Checking filter for parent id = 1" );
+like( $result->output, '/^PROCS CRITICAL: 39 processes with PPID = 1/', "Output correct" );
+
+$result = NPTest->testCmd( "$command -P 0.71" );
+is( $result->return_code, 0, "Checking filter for percentage cpu > 0.71" );
+is( $result->output, 'PROCS OK: 7 processes with PCPU >= 0.71 | procs=7;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command -P 0.70" );
+is( $result->return_code, 0, "Checking filter for percentage cpu > 0.70" );
+is( $result->output, 'PROCS OK: 8 processes with PCPU >= 0.70 | procs=8;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command --metric=CPU -w 8" );
+is( $result->return_code, 1, "Checking against metric of CPU > 8" );
+is( $result->output, 'CPU WARNING: 1 warn out of 95 processes | procs=95;;;0; procs_warn=1;;;0; procs_crit=0;;;0;', "Output correct" );
+
+# TODO: Because of a conversion to int, if CPU is 1.45%, will not alert, but 2.01% will.
+SKIP: {
+ skip 'user with uid 501 required', 2 unless getpwuid(501);
+
+ $result = NPTest->testCmd( "$command --metric=CPU -w 1 -u 501 -v" );
+ is( $result->return_code, 1, "Checking against metric of CPU > 1 with uid=501 - TODO" );
+ is( $result->output, 'CPU WARNING: 2 warn out of 40 processes with UID = 501 (tonvoon) [Skype, PubSubAgent]', "Output correct" );
+};
+
+$result = NPTest->testCmd( "$command --metric=VSZ -w 1200000 -v" );
+is( $result->return_code, 1, "Checking against VSZ > 1.2GB" );
+is( $result->output, 'VSZ WARNING: 4 warn out of 95 processes [WindowServer, Safari, Mail, Skype] | procs=95;;;0; procs_warn=4;;;0; procs_crit=0;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command --metric=VSZ -w 1200000 -v" );
+is( $result->return_code, 1, "Checking against VSZ > 1.2GB" );
+is( $result->output, 'VSZ WARNING: 4 warn out of 95 processes [WindowServer, Safari, Mail, Skype] | procs=95;;;0; procs_warn=4;;;0; procs_crit=0;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command --metric=RSS -c 70000 -v" );
+is( $result->return_code, 2, "Checking against RSS > 70MB" );
+is( $result->output, 'RSS CRITICAL: 5 crit, 0 warn out of 95 processes [WindowServer, SystemUIServer, Safari, Mail, Safari] | procs=95;;;0; procs_warn=0;;;0; procs_crit=5;;;0;', "Output correct" );
+
+$result = NPTest->testCmd( "$command --ereg-argument-array='(nosuchname|nosuch2name)'" );
+is( $result->return_code, 0, "Checking no pipe symbol in output" );
+is( $result->output, "PROCS OK: 0 processes with regex args '(nosuchname,nosuch2name)' | procs=0;;;0;", "Output correct" );
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t
new file mode 100755
index 0000000..bfe42e1
--- /dev/null
+++ b/plugins/tests/check_snmp.t
@@ -0,0 +1,286 @@
+#! /usr/bin/perl -w -I ..
+#
+# Test check_snmp by having an actual SNMP agent running
+#
+
+use strict;
+use Test::More;
+use NPTest;
+use FindBin qw($Bin);
+use POSIX qw/strftime/;
+
+my $tests = 81;
+# Check that all dependent modules are available
+eval {
+ require NetSNMP::OID;
+ require NetSNMP::agent;
+ require NetSNMP::ASN;
+};
+
+if ($@) {
+ plan skip_all => "Missing required module for test: $@";
+} else {
+ if (-x "./check_snmp") {
+ # check if snmpd has perl support
+ my $test = `snmpd -c tests/conf/snmpd.conf -C -r -H 2>&1`;
+ if(!defined $test) {
+ plan skip_all => "snmpd required";
+ }
+ elsif($test =~ m/Warning: Unknown token: perl/) {
+ plan skip_all => "snmpd has no perl support";
+ } else {
+ plan tests => $tests;
+ }
+ } else {
+ plan skip_all => "No check_snmp compiled";
+ }
+}
+
+my $port_snmp = 16100 + int(rand(100));
+
+my $faketime = -x '/usr/bin/faketime' ? 1 : 0;
+
+# Start up server
+my @pids;
+my $pid = fork();
+if ($pid) {
+ # Parent
+ push @pids, $pid;
+ # give our agent some time to startup
+ sleep(1);
+} else {
+ # Child
+ #print "child\n";
+
+ print "Please contact SNMP at: $port_snmp\n";
+ close(STDERR); # Comment out to debug snmpd problems (most errors sent there are OK)
+ exec("snmpd -c tests/conf/snmpd.conf -C -f -r udp:$port_snmp");
+}
+
+END {
+ foreach my $pid (@pids) {
+ if ($pid) { print "Killing $pid\n"; kill "INT", $pid }
+ }
+};
+
+if ($ARGV[0] && $ARGV[0] eq "-d") {
+ while (1) {
+ sleep 100;
+ }
+}
+
+# We should merge that with $ENV{'NPTEST_CACHE'}, use one dir for all test data
+$ENV{'MP_STATE_PATH'} ||= "/var/tmp";
+
+my $res;
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0");
+cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" );
+like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
+like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software |
+.1.3.6.1.4.1.8072.3.2.67.0:
+"Cisco Internetwork Operating System Software
+IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
+12.2(20)EWA, RELEASE SOFTWARE (fc1)
+Technical Support: http://www.cisco.com/techsupport
+Copyright (c) 1986-2004 by cisco Systems, Inc.
+"').'/m', "String contains all lines");
+
+# sysContact.0 is "Alice" (from our snmpd.conf)
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1");
+cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
+like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
+like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software ').'"?Alice"?'.quotemeta(' Kisco Outernetwork Oserating Gystem Totware |
+.1.3.6.1.4.1.8072.3.2.67.0:
+"Cisco Internetwork Operating System Software
+IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
+12.2(20)EWA, RELEASE SOFTWARE (fc1)
+Technical Support: http://www.cisco.com/techsupport
+Copyright (c) 1986-2004 by cisco Systems, Inc.
+"
+.1.3.6.1.4.1.8072.3.2.67.1:
+"Kisco Outernetwork Oserating Gystem Totware
+Copyleft (c) 2400-2689 by kisco Systrems, Inc."').'/m', "String contains all lines with multiple OIDs");
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2");
+like($res->output, '/'.quotemeta('SNMP OK - This should not confuse check_snmp \"parser\" |
+.1.3.6.1.4.1.8072.3.2.67.2:
+"This should not confuse check_snmp \"parser\"
+into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1");
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3");
+like($res->output, '/'.quotemeta('SNMP OK - It\'s getting even harder if the line |
+.1.3.6.1.4.1.8072.3.2.67.3:
+"It\'s getting even harder if the line
+ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2");
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4");
+like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C:\\\\\" |
+.1.3.6.1.4.1.8072.3.2.67.4:
+"And now have fun with with this: \"C:\\\\\"
+because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3");
+
+system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*");
+
+# run rate checks with faketime. rate checks depend on the exact amount of time spend between the
+# plugin runs which may fail on busy machines.
+# using faketime removes this race condition and also saves all the sleeps in between.
+SKIP: {
+ skip "No faketime binary found", 28 if !$faketime;
+
+ my $ts = time();
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
+ is($res->return_code, 0, "Returns OK");
+ is($res->output, "No previous data to calculate rate - assume okay");
+
+ # test rate 1 second later
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
+ is($res->return_code, 1, "WARNING - due to going above rate calculation" );
+ is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 ");
+
+ # test rate with same time
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
+ is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" );
+ is($res->output, "Time duration between plugin calls is invalid");
+
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
+ is($res->return_code, 0, "OK for first call" );
+ is($res->output, "No previous data to calculate rate - assume okay" );
+
+ # test rate 1 second later
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label");
+
+ # test rate 3 seconds later
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval");
+
+
+ # label performance data check
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label");
+
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label");
+
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label");
+
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label");
+
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label");
+
+ $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label");
+
+
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
+ is($res->return_code, 0, "OK for first call" );
+ is($res->output, "No previous data to calculate rate - assume okay" );
+
+ # test 1 second later
+ $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
+ is($res->return_code, 0, "OK as no thresholds" );
+ is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier");
+};
+
+
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" );
+is($res->return_code, 0, "OK as string matches" );
+is($res->output, 'SNMP OK - "stringtests" | ', "Good string match" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" );
+is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" );
+is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Failed string match" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s '\"stringtests\"'" );
+is($res->return_code, 2, "CRITICAL as string matches but inverted" );
+is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Inverted string match" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" );
+is($res->return_code, 0, "OK as string doesn't match but inverted" );
+is($res->output, 'SNMP OK - "stringtests" | ', "OK as inverted string no match" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" );
+is($res->return_code, 1, "Numeric in string test" );
+is($res->output, 'SNMP WARNING - *3.5* | iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5 ', "WARNING threshold checks for string masquerading as number" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" );
+is($res->return_code, 0, "Not really numeric test" );
+is($res->output, 'SNMP OK - "87.4startswithnumberbutshouldbestring" | ', "Check string with numeric start is still string" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" );
+is($res->return_code, 0, "Not really numeric test (trying best to fool it)" );
+is($res->output, 'SNMP OK - "555\"I said\"" | ', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" );
+is($res->return_code, 0, "String check should check whole string, not a parsed number" );
+is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check with numbers returns whole string");
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
+is($res->return_code, 0, "Negative integer check OK" );
+is($res->output, 'SNMP OK - -2 | iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3: ', "Negative integer check OK output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
+is($res->return_code, 1, "Negative integer check WARNING" );
+is($res->output, 'SNMP WARNING - *-3* | iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3: ', "Negative integer check WARNING output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
+is($res->return_code, 2, "Negative integer check CRITICAL" );
+is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3: ', "Negative integer check CRITICAL output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" );
+is($res->return_code, 1, "Negative integer as string, WARNING" );
+is($res->output, 'SNMP WARNING - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6: ', "Negative integer as string, WARNING output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" );
+is($res->return_code, 2, "Negative integer as string, CRITICAL" );
+is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3: ', "Negative integer as string, CRITICAL output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" );
+is($res->return_code, 0, "Negative float OK" );
+is($res->output, 'SNMP OK - -6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" );
+is($res->return_code, 1, "Negative float WARNING" );
+is($res->output, 'SNMP WARNING - *-6.6* | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;@-6.65:~;@-6.55:~ ', "Negative float WARNING output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" );
+is($res->return_code, 0, "Multiple OIDs with thresholds" );
+like($res->output, '/SNMP OK - \d+ -4 | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" );
+is($res->return_code, 1, "Multiple OIDs with thresholds" );
+like($res->output, '/SNMP WARNING - \d+ \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1" );
+is($res->return_code, 2, "Multiple OIDs with some thresholds" );
+like($res->output, '/SNMP CRITICAL - \*\d+\* \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19");
+is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" );
+is($res->output,'SNMP OK - 42 | iso.3.6.1.4.1.8072.3.2.67.19=42 ', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1");
+is($res->return_code, 0, "Test multiply RC" );
+is($res->output,'SNMP OK - 4.200000 | iso.3.6.1.4.1.8072.3.2.67.19=4.200000 ' , "Test multiply .1 output" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' ");
+is($res->return_code, 0, "Test multiply RC + format" );
+is($res->output, 'SNMP OK - 4.20 | iso.3.6.1.4.1.8072.3.2.67.19=4.20 ', "Test multiply .1 output + format" );
+
+$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' -w 1");
+is($res->return_code, 1, "Test multiply RC + format + thresholds" );
+is($res->output, 'SNMP WARNING - *4.20* | iso.3.6.1.4.1.8072.3.2.67.19=4.20;1 ', "Test multiply .1 output + format + thresholds" );
diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl
new file mode 100644
index 0000000..38912e9
--- /dev/null
+++ b/plugins/tests/check_snmp_agent.pl
@@ -0,0 +1,111 @@
+#! /usr/bin/perl -w -I ..
+#
+# Subagent for testing check_snmp
+#
+
+#use strict; # Doesn't work
+use NetSNMP::OID qw(:all);
+use NetSNMP::agent;
+use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64);
+#use Math::Int64 qw(uint64); # Skip that module while we don't need it
+sub uint64 { return $_ }
+
+if (!$agent) {
+ print "This program must run as an embedded NetSNMP agent\n";
+ exit 1;
+}
+
+my $baseoid = '.1.3.6.1.4.1.8072.3.2.67';
+my $multiline = 'Cisco Internetwork Operating System Software
+IOS (tm) Catalyst 4000 "L3" Switch Software (cat4000-I9K91S-M), Version
+12.2(20)EWA, RELEASE SOFTWARE (fc1)
+Technical Support: http://www.cisco.com/techsupport
+Copyright (c) 1986-2004 by cisco Systems, Inc.
+';
+my $multilin2 = "Kisco Outernetwork Oserating Gystem Totware
+Copyleft (c) 2400-2689 by kisco Systrems, Inc.";
+my $multilin3 = 'This should not confuse check_snmp "parser"
+into thinking there is no 2nd line';
+my $multilin4 = 'It\'s getting even harder if the line
+ends with with this: C:\\';
+my $multilin5 = 'And now have fun with with this: "C:\\"
+because we\'re not done yet!';
+
+# Next are arrays of indexes (Type, initial value and increments)
+# 0..19 <---- please update comment when adding/removing fields
+my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED, ASN_COUNTER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER );
+my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32)), 64000, "stringtests", "3.5", "87.4startswithnumberbutshouldbestring", '555"I said"', 'CUSTOM CHECK OK: foo is 12345', -2, '-4', '-6.6', 42 );
+# undef increments are randomized
+my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef, 0 );
+
+# Number of elements in our OID
+my $oidelts;
+{
+ my @oid = split(/\./, $baseoid);
+ $oidelts = scalar(@oid);
+}
+
+my $regoid = new NetSNMP::OID($baseoid);
+$agent->register('check_snmp_agent', $regoid, \&my_snmp_handler);
+
+sub my_snmp_handler {
+ my ($handler, $registration_info, $request_info, $requests) = @_;
+
+ for (my $request = $requests; $request; $request = $request->next) {
+ my $oid = $request->getOID();
+ my $index;
+ my $next_index;
+
+ # Validate the OID
+ my @numarray = $oid->to_array();
+ if (@numarray != $oidelts) {
+ if ($request_info->getMode() == MODE_GETNEXT && @numarray == ($oidelts - 1)) {
+ # GETNEXT for the base oid; set it to the first index
+ push(@numarray, 0);
+ $next_index = 0;
+ } else {
+ # We got a request for the base OID or with extra elements
+ $request->setError($request_info, SNMP_ERR_NOERROR);
+ next;
+ }
+ }
+
+ $index = pop(@numarray);
+ if ($index >= scalar(@fields)) {
+ # Index is out of bounds
+ $request->setError($request_info, SNMP_ERR_NOERROR);
+ next;
+ }
+
+ # Handle the request
+ if ($request_info->getMode() == MODE_GETNEXT) {
+ if (++$index >= scalar(@fields)) {
+ # Index will grow out of bounds
+ $request->setError($request_info, SNMP_ERR_NOERROR);
+ next;
+ }
+ $index = (defined($next_index) ? $next_index : $index);
+ $request->setOID("$baseoid.$index");
+ } elsif ($request_info->getMode() != MODE_GET) {
+ # Everything else is write-related modes
+ $request->setError($request_info, SNMP_ERR_READONLY);
+ next;
+ }
+
+ # Set the response... setValue is a bit touchy about the data type, but accepts plain strings.
+ my $value = sprintf("%s", $values[$index]);
+ $request->setValue($fields[$index], $value);
+
+ # And update the value
+ if (defined($incrts[$index])) {
+ $values[$index] += $incrts[$index];
+ } elsif ($fields[$index] != ASN_OCTET_STR) {
+ my $minus = int(rand(2))*-1;
+ $minus = 1 unless ($minus);
+ my $exp = 32;
+ $exp = 64 if ($fields[$index] == ASN_COUNTER64 || $fields[$index] == ASN_INTEGER64 || $fields[$index] == ASN_UNSIGNED64);
+ $values[$index] = int(rand(2**$exp));
+ }
+ }
+}
+
diff --git a/plugins/tests/conf/snmpd.conf b/plugins/tests/conf/snmpd.conf
new file mode 100644
index 0000000..eff5b0b
--- /dev/null
+++ b/plugins/tests/conf/snmpd.conf
@@ -0,0 +1,23 @@
+###############################################################################
+# Access Control
+###############################################################################
+
+com2sec readonly localhost public
+
+group MyROGroup v1 readonly
+group MyROGroup v2c readonly
+
+view all included .1 80
+
+access MyROGroup "" any noauth exact all none none
+
+syslocation Wonderland
+syscontact Alice
+
+
+###############################################################################
+# Embedded Subagents
+###############################################################################
+
+perl do "tests/check_snmp_agent.pl";
+
diff --git a/plugins/tests/var/ps-axwo.darwin b/plugins/tests/var/ps-axwo.darwin
new file mode 100644
index 0000000..b71d834
--- /dev/null
+++ b/plugins/tests/var/ps-axwo.darwin
@@ -0,0 +1,96 @@
+STAT UID PID PPID VSZ RSS %CPU UCOMM COMMAND
+Ss 0 1 0 603456 976 0.0 launchd /sbin/launchd
+Ss 0 10 1 612820 3608 0.0 kextd /usr/libexec/kextd
+Ss 0 11 1 632980 8680 0.0 DirectoryService /usr/sbin/DirectoryService
+Ss 0 12 1 602832 720 0.0 notifyd /usr/sbin/notifyd
+Ss 0 13 1 603916 1136 0.0 syslogd /usr/sbin/syslogd
+Ss 0 14 1 614928 4928 0.0 configd /usr/sbin/configd
+Ss 65 15 1 615496 5616 0.0 mDNSResponder /usr/sbin/mDNSResponder -launchd
+Ss 1 16 1 608960 2212 0.0 distnoted /usr/sbin/distnoted
+Ss 65 18 1 602432 504 0.0 launchd /sbin/launchd
+Ss 0 20 1 614836 5844 0.3 securityd /usr/sbin/securityd -i
+Ss 0 24 1 610536 2704 0.0 ntpd /usr/sbin/ntpd -n -g -p /var/run/ntpd.pid -f /var/db/ntp.drift
+Ss 0 25 1 602228 496 0.0 update /usr/sbin/update
+Ss 0 26 1 609900 2320 0.0 SystemStarter /sbin/SystemStarter
+Ss 0 30 1 834352 36264 0.3 mds /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
+Ss 501 31 1 1110572 23948 0.0 loginwindow /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow console
+Ss 0 32 1 609448 2616 0.0 KernelEventAgent /usr/sbin/KernelEventAgent
+Ss 0 34 1 609892 2204 0.0 hidd /usr/libexec/hidd
+Ss 0 35 1 624704 4284 0.0 fseventsd /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Support/fseventsd
+Ss 0 36 1 610256 2876 0.0 dynamic_pager /sbin/dynamic_pager -F /private/var/vm/swapfile
+Ss 0 39 1 613408 4140 0.0 diskarbitrationd /usr/sbin/diskarbitrationd
+Ss 0 43 1 665708 8024 0.0 blued /usr/sbin/blued
+Ss 0 44 1 609408 2828 0.0 autofsd autofsd
+Ss 0 45 1 654084 9600 0.0 socketfilterfw /usr/libexec/ApplicationFirewall/socketfilterfw
+Ss 0 46 1 704764 12788 0.0 ccc_helper /Applications/Carbon Copy Cloner.app/Contents/Resources/ccc_helper.app/Contents/MacOS/ccc_helper 3231BC22-F30F-45D8-BDE8-47A098D57ABD
+Ss 0 54 1 667956 19212 0.0 coreservicesd /System/Library/CoreServices/coreservicesd
+Ss 88 56 1 1205840 85700 1.6 WindowServer /System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/WindowServer -daemon
+Ss 0 67 1 602992 612 0.0 llipd /Library/StartupItems/ParallelsTransporter/llipd
+S 0 83 1 613352 2312 0.0 pvsnatd /Library/StartupItems/Parallels/pvsnatd
+Ss 0 94 1 712036 15056 0.0 coreaudiod /usr/sbin/coreaudiod
+Ss 501 102 1 602432 1040 0.0 launchd /sbin/launchd
+S 501 109 102 1176668 28068 0.0 Spotlight /System/Library/CoreServices/Spotlight.app/Contents/MacOS/Spotlight
+S 501 110 102 941796 10988 0.0 UserEventAgent /usr/sbin/UserEventAgent -l Aqua
+S 501 112 102 610028 2056 0.0 pboard /usr/sbin/pboard
+S 501 114 102 1090056 29196 1.3 Dock /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock -psn_0_24582
+S 501 115 102 685360 14048 0.0 ATSServer /System/Library/Frameworks/ApplicationServices.framework/Frameworks/ATS.framework/Support/ATSServer
+S 501 117 102 1121904 94432 0.1 SystemUIServer /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer -psn_0_32776
+S 501 118 102 1110388 42064 1.4 Finder /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder -psn_0_36873
+S 501 123 102 718264 34752 0.0 FileSyncAgent /System/Library/CoreServices/FileSyncAgent.app/Contents/MacOS/FileSyncAgent -launchedByLaunchd
+S 501 127 102 1048388 25344 0.0 smcFanControl /Applications/smcFanControl.app/Contents/MacOS/smcFanControl -psn_0_53261
+S 501 128 102 970912 12924 0.0 iTunesHelper /Applications/iTunes.app/Contents/Resources/iTunesHelper.app/Contents/MacOS/iTunesHelper -psn_0_57358
+S 501 129 102 1095920 23364 1.4 Activity Monitor /Applications/Utilities/Activity Monitor.app/Contents/MacOS/Activity Monitor -psn_0_61455
+S 501 132 102 657212 8356 0.0 dmnotifyd /System/Library/PrivateFrameworks/DMNotification.framework/Versions/Current/Resources/dmnotifyd
+Ss -2 133 1 610464 2328 0.0 usbmuxd /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/Resources/usbmuxd -launchd
+Ss 0 136 129 637456 6340 10.6 pmTool /Applications/Utilities/Activity Monitor.app/Contents/Resources/pmTool
+Ss 501 142 1 676652 8984 0.1 diskimages-helpe /System/Library/PrivateFrameworks/DiskImages.framework/Resources/diskimages-helper -uuid F2225770-5EFF-467C-91FD-C990F056B22F -post-exec
+Ss 0 147 1 627640 5928 0.0 hdiejectd /System/Library/PrivateFrameworks/DiskImages.framework/Resources/hdiejectd
+S 501 157 102 1045492 27480 0.0 GrowlHelperApp /Library/PreferencePanes/Growl.prefPane/Contents/Resources/GrowlHelperApp.app/Contents/MacOS/GrowlHelperApp -psn_0_81940
+U 501 158 102 1878012 388136 0.7 Safari /Applications/Safari.app/Contents/MacOS/Safari -psn_0_86037
+S 501 172 102 645560 11344 0.0 AppleSpell /System/Library/Services/AppleSpell.service/Contents/MacOS/AppleSpell -psn_0_98328
+S 501 175 102 1055412 33396 0.0 Terminal /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_102425
+Z 501 186 158 0 0 0.0 Meeting Manager (Meeting Manager)
+S 501 214 102 616988 3808 0.0 ssh-agent /usr/bin/ssh-agent -l
+Ss 502 217 1 602432 1016 0.0 launchd /sbin/launchd
+S 501 499 102 1313808 130396 0.3 Mail /Applications/Mail.app/Contents/MacOS/Mail -psn_0_180268
+S 501 502 102 1091652 52168 0.0 NetNewsWire Lite /Applications/NetNewsWire Lite.app/Contents/MacOS/NetNewsWire Lite -psn_0_184365
+Ss 502 572 56 818908 20988 0.0 loginwindow /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow
+S 502 585 217 741824 19056 0.0 Spotlight /System/Library/CoreServices/Spotlight.app/Contents/MacOS/Spotlight
+S 502 586 217 941900 11044 0.0 UserEventAgent /usr/sbin/UserEventAgent -l Aqua
+S 502 588 217 757320 18080 0.0 Dock /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock -psn_0_237626
+S 502 590 217 610072 2068 0.0 pboard /usr/sbin/pboard
+S 502 592 217 794140 25456 0.0 SystemUIServer /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer -psn_0_245820
+S 502 593 217 845552 30596 0.0 Finder /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder -psn_0_249917
+S 502 594 217 671780 7872 0.0 ATSServer /System/Library/Frameworks/ApplicationServices.framework/Frameworks/ATS.framework/Support/ATSServer
+U 502 605 217 938844 64964 0.0 Pages /Applications/iWork '08/Pages.app/Contents/MacOS/Pages -psn_0_266305
+S 502 609 217 644432 10828 0.0 AppleSpell /System/Library/Services/AppleSpell.service/Contents/MacOS/AppleSpell -psn_0_270402
+S 502 610 217 638552 5216 0.0 AppleSpell /System/Library/Services/AppleSpell.service/Contents/MacOS/AppleSpell -psn_0_274499
+U 502 710 217 1029148 223312 0.0 Safari /Applications/Safari.app/Contents/MacOS/Safari -psn_0_331857
+S 502 712 217 904056 62928 0.3 Mail /Applications/Mail.app/Contents/MacOS/Mail -psn_0_335954
+U 501 998 102 1068272 26532 0.0 Address Book /Applications/Address Book.app/Contents/MacOS/Address Book -psn_0_417894
+S 502 2228 217 820940 30600 0.0 TextEdit /Applications/TextEdit.app/Contents/MacOS/TextEdit -psn_0_729266
+S 501 2431 102 1067868 43492 0.0 iCal /Applications/iCal.app/Contents/MacOS/iCal -psn_0_803012
+S 501 2531 102 1250108 68792 2.4 Skype /Applications/Skype.app/Contents/MacOS/Skype -psn_0_823497
+Ss 92 3143 1 602432 828 0.0 launchd /sbin/launchd
+S 501 3491 102 1048620 31256 0.0 TextEdit /Applications/TextEdit.app/Contents/MacOS/TextEdit -psn_0_962795
+S 501 3536 102 1073340 30524 0.0 Preview /Applications/Preview.app/Contents/MacOS/Preview -psn_0_983280
+S 501 4045 102 1041544 29168 0.0 PasswordWallet /Applications/PasswordWallet.app/Contents/MacOS/PasswordWallet -psn_0_1138966
+S 501 4892 114 1064948 43488 0.0 DashboardClient /System/Library/CoreServices/Dock.app/Contents/Resources/DashboardClient.app/Contents/MacOS/DashboardClient
+S 501 6806 102 1163836 67356 0.0 Colloquy /Applications/Colloquy.app/Contents/MacOS/Colloquy -psn_0_2220574
+U 501 6969 102 1156804 58764 0.0 Adium /Applications/Adium.app/Contents/MacOS/Adium -psn_0_2294320
+S 501 7530 102 671612 17440 0.0 helpdatad /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/Resources/helpdatad
+Ss -2 38255 1 602432 952 0.0 launchd /sbin/launchd
+S 501 40569 102 1160664 49484 0.0 Dictionary /Applications/Dictionary.app/Contents/MacOS/Dictionary -psn_0_4387887
+SNs 501 42683 1 744096 21084 0.0 mdworker /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker MDSImporterWorker com.apple.Spotlight.ImporterWorker.501
+S 501 62225 102 711004 18040 0.0 SyncServer /System/Library/Frameworks/SyncServices.framework/Versions/Current/Resources/SyncServer.app/Contents/MacOS/SyncServer
+SNs -2 62284 1 671812 10880 0.0 mdworker /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker MDSImporterWorker com.apple.Spotlight.ImporterWorker.-2
+Ss 0 62285 1 617056 5472 0.0 cupsd /usr/sbin/cupsd -l
+S 502 62287 217 632360 10044 0.0 PubSubAgent /System/Library/Frameworks/PubSub.framework/Versions/A/Resources/PubSubAgent.app/Contents/MacOS/PubSubAgent
+SNs 502 62288 1 668876 10440 0.0 mdworker /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker MDSImporterWorker com.apple.Spotlight.ImporterWorker.502
+S 501 62296 102 643688 11980 2.2 PubSubAgent /System/Library/Frameworks/PubSub.framework/Versions/A/Resources/PubSubAgent.app/Contents/MacOS/PubSubAgent
+Ss 0 4558 175 630816 6960 0.0 login login -pf tonvoon
+S 501 4559 4558 603600 1736 0.0 bash -bash
+R+ 0 62297 4559 602388 852 0.0 ps /bin/ps -axwo stat
+Ss 0 7301 175 630816 6960 0.0 login login -pf tonvoon
+S 501 7302 7301 603600 1584 0.0 bash -bash
+S+ 501 41381 7302 615408 4196 0.0 ssh ssh dev.net.altinity
diff --git a/plugins/tests/var/ps-axwo.debian b/plugins/tests/var/ps-axwo.debian
new file mode 100644
index 0000000..5889e9a
--- /dev/null
+++ b/plugins/tests/var/ps-axwo.debian
@@ -0,0 +1,219 @@
+STAT UID PID PPID VSZ RSS %CPU ELAPSED COMMAND COMMAND
+Ss 0 1 0 167244 7144 0.1 26-03:07:26 systemd /lib/systemd/systemd --system --deserialize 17
+S 0 2 0 0 0 0.0 26-03:07:26 kthreadd [kthreadd]
+I< 0 3 2 0 0 0.0 26-03:07:26 rcu_gp [rcu_gp]
+I< 0 4 2 0 0 0.0 26-03:07:26 rcu_par_gp [rcu_par_gp]
+I< 0 6 2 0 0 0.0 26-03:07:26 kworker/0:0H-ev [kworker/0:0H-events_highpri]
+I< 0 9 2 0 0 0.0 26-03:07:26 mm_percpu_wq [mm_percpu_wq]
+S 0 10 2 0 0 0.0 26-03:07:26 rcu_tasks_rude_ [rcu_tasks_rude_]
+S 0 11 2 0 0 0.0 26-03:07:26 rcu_tasks_trace [rcu_tasks_trace]
+S 0 12 2 0 0 0.0 26-03:07:26 ksoftirqd/0 [ksoftirqd/0]
+I 0 13 2 0 0 0.0 26-03:07:26 rcu_sched [rcu_sched]
+S 0 14 2 0 0 0.0 26-03:07:26 migration/0 [migration/0]
+S 0 15 2 0 0 0.0 26-03:07:26 cpuhp/0 [cpuhp/0]
+S 0 16 2 0 0 0.0 26-03:07:26 cpuhp/1 [cpuhp/1]
+S 0 17 2 0 0 0.0 26-03:07:26 migration/1 [migration/1]
+S 0 18 2 0 0 0.0 26-03:07:26 ksoftirqd/1 [ksoftirqd/1]
+I< 0 20 2 0 0 0.0 26-03:07:26 kworker/1:0H-ev [kworker/1:0H-events_highpri]
+S 0 21 2 0 0 0.0 26-03:07:26 cpuhp/2 [cpuhp/2]
+S 0 22 2 0 0 0.0 26-03:07:26 migration/2 [migration/2]
+S 0 23 2 0 0 0.0 26-03:07:26 ksoftirqd/2 [ksoftirqd/2]
+I< 0 25 2 0 0 0.0 26-03:07:26 kworker/2:0H-ev [kworker/2:0H-events_highpri]
+S 0 26 2 0 0 0.0 26-03:07:26 cpuhp/3 [cpuhp/3]
+S 0 27 2 0 0 0.0 26-03:07:26 migration/3 [migration/3]
+S 0 28 2 0 0 0.0 26-03:07:26 ksoftirqd/3 [ksoftirqd/3]
+I< 0 30 2 0 0 0.0 26-03:07:26 kworker/3:0H-ev [kworker/3:0H-events_highpri]
+S 0 35 2 0 0 0.0 26-03:07:26 kdevtmpfs [kdevtmpfs]
+I< 0 36 2 0 0 0.0 26-03:07:26 netns [netns]
+S 0 37 2 0 0 0.0 26-03:07:26 kauditd [kauditd]
+S 0 38 2 0 0 0.0 26-03:07:26 khungtaskd [khungtaskd]
+S 0 39 2 0 0 0.0 26-03:07:26 oom_reaper [oom_reaper]
+I< 0 40 2 0 0 0.0 26-03:07:26 writeback [writeback]
+S 0 41 2 0 0 0.0 26-03:07:26 kcompactd0 [kcompactd0]
+SN 0 42 2 0 0 0.0 26-03:07:26 ksmd [ksmd]
+SN 0 43 2 0 0 0.0 26-03:07:26 khugepaged [khugepaged]
+I< 0 62 2 0 0 0.0 26-03:07:26 kintegrityd [kintegrityd]
+I< 0 63 2 0 0 0.0 26-03:07:26 kblockd [kblockd]
+I< 0 64 2 0 0 0.0 26-03:07:26 blkcg_punt_bio [blkcg_punt_bio]
+I< 0 65 2 0 0 0.0 26-03:07:26 edac-poller [edac-poller]
+I< 0 66 2 0 0 0.0 26-03:07:26 devfreq_wq [devfreq_wq]
+I< 0 67 2 0 0 0.0 26-03:07:26 kworker/2:1H-ev [kworker/2:1H-events_highpri]
+S 0 70 2 0 0 0.3 26-03:07:25 kswapd0 [kswapd0]
+I< 0 71 2 0 0 0.0 26-03:07:25 kthrotld [kthrotld]
+I< 0 72 2 0 0 0.0 26-03:07:25 acpi_thermal_pm [acpi_thermal_pm]
+I< 0 74 2 0 0 0.0 26-03:07:25 ipv6_addrconf [ipv6_addrconf]
+I< 0 80 2 0 0 0.0 26-03:07:25 kworker/3:1H-ev [kworker/3:1H-events_highpri]
+I< 0 84 2 0 0 0.0 26-03:07:25 kstrp [kstrp]
+I< 0 87 2 0 0 0.0 26-03:07:25 zswap-shrink [zswap-shrink]
+I< 0 110 2 0 0 0.0 26-03:07:25 kworker/0:1H-ev [kworker/0:1H-events_highpri]
+I< 0 141 2 0 0 0.0 26-03:07:25 ata_sff [ata_sff]
+S 0 143 2 0 0 0.0 26-03:07:25 scsi_eh_0 [scsi_eh_0]
+I< 0 144 2 0 0 0.0 26-03:07:25 scsi_tmf_0 [scsi_tmf_0]
+S 0 145 2 0 0 0.0 26-03:07:25 scsi_eh_1 [scsi_eh_1]
+I< 0 146 2 0 0 0.0 26-03:07:25 scsi_tmf_1 [scsi_tmf_1]
+S 0 147 2 0 0 0.0 26-03:07:25 scsi_eh_2 [scsi_eh_2]
+I< 0 148 2 0 0 0.0 26-03:07:25 scsi_tmf_2 [scsi_tmf_2]
+S 0 149 2 0 0 0.0 26-03:07:25 scsi_eh_3 [scsi_eh_3]
+I< 0 150 2 0 0 0.0 26-03:07:25 scsi_tmf_3 [scsi_tmf_3]
+S 0 151 2 0 0 0.0 26-03:07:25 scsi_eh_4 [scsi_eh_4]
+I< 0 152 2 0 0 0.0 26-03:07:25 scsi_tmf_4 [scsi_tmf_4]
+S 0 153 2 0 0 0.0 26-03:07:25 scsi_eh_5 [scsi_eh_5]
+I< 0 154 2 0 0 0.0 26-03:07:25 scsi_tmf_5 [scsi_tmf_5]
+S 0 158 2 0 0 0.0 26-03:07:25 card0-crtc0 [card0-crtc0]
+S 0 159 2 0 0 0.0 26-03:07:25 card0-crtc1 [card0-crtc1]
+S 0 160 2 0 0 0.0 26-03:07:25 card0-crtc2 [card0-crtc2]
+I< 0 162 2 0 0 0.0 26-03:07:25 kworker/1:1H-ev [kworker/1:1H-events_highpri]
+S 0 163 2 0 0 0.0 26-03:07:25 scsi_eh_6 [scsi_eh_6]
+I< 0 164 2 0 0 0.0 26-03:07:25 scsi_tmf_6 [scsi_tmf_6]
+S 0 165 2 0 0 0.0 26-03:07:25 usb-storage [usb-storage]
+I< 0 167 2 0 0 0.0 26-03:07:25 uas [uas]
+I< 0 176 2 0 0 0.0 26-03:07:25 kdmflush [kdmflush]
+I< 0 177 2 0 0 0.0 26-03:07:25 kdmflush [kdmflush]
+S 0 202 2 0 0 0.0 26-03:07:24 scsi_eh_7 [scsi_eh_7]
+I< 0 203 2 0 0 0.0 26-03:07:24 scsi_tmf_7 [scsi_tmf_7]
+S 0 204 2 0 0 0.0 26-03:07:24 usb-storage [usb-storage]
+I< 0 232 2 0 0 0.0 26-03:07:23 btrfs-worker [btrfs-worker]
+I< 0 233 2 0 0 0.0 26-03:07:23 btrfs-worker-hi [btrfs-worker-hi]
+I< 0 234 2 0 0 0.0 26-03:07:23 btrfs-delalloc [btrfs-delalloc]
+I< 0 235 2 0 0 0.0 26-03:07:23 btrfs-flush_del [btrfs-flush_del]
+I< 0 236 2 0 0 0.0 26-03:07:23 btrfs-cache [btrfs-cache]
+I< 0 237 2 0 0 0.0 26-03:07:23 btrfs-fixup [btrfs-fixup]
+I< 0 238 2 0 0 0.0 26-03:07:23 btrfs-endio [btrfs-endio]
+I< 0 239 2 0 0 0.0 26-03:07:23 btrfs-endio-met [btrfs-endio-met]
+I< 0 240 2 0 0 0.0 26-03:07:23 btrfs-endio-met [btrfs-endio-met]
+I< 0 241 2 0 0 0.0 26-03:07:23 btrfs-endio-rai [btrfs-endio-rai]
+I< 0 242 2 0 0 0.0 26-03:07:23 btrfs-rmw [btrfs-rmw]
+I< 0 243 2 0 0 0.0 26-03:07:23 btrfs-endio-wri [btrfs-endio-wri]
+I< 0 244 2 0 0 0.0 26-03:07:23 btrfs-freespace [btrfs-freespace]
+I< 0 245 2 0 0 0.0 26-03:07:23 btrfs-delayed-m [btrfs-delayed-m]
+I< 0 246 2 0 0 0.0 26-03:07:23 btrfs-readahead [btrfs-readahead]
+I< 0 247 2 0 0 0.0 26-03:07:23 btrfs-qgroup-re [btrfs-qgroup-re]
+S 0 248 2 0 0 0.0 26-03:07:23 btrfs-cleaner [btrfs-cleaner]
+S 0 249 2 0 0 0.2 26-03:07:23 btrfs-transacti [btrfs-transacti]
+I< 0 317 2 0 0 0.0 26-03:07:22 rpciod [rpciod]
+I< 0 322 2 0 0 0.0 26-03:07:22 xprtiod [xprtiod]
+S 0 381 2 0 0 0.0 26-03:07:22 irq/133-mei_me [irq/133-mei_me]
+S 0 422 2 0 0 0.0 26-03:07:22 watchdogd [watchdogd]
+I< 0 523 2 0 0 0.0 26-03:07:22 led_workqueue [led_workqueue]
+I< 0 583 2 0 0 0.0 26-03:07:22 cryptd [cryptd]
+I< 0 590 2 0 0 0.0 26-03:07:22 ext4-rsv-conver [ext4-rsv-conver]
+Ss 104 693 1 12324 4292 0.5 26-03:07:21 dbus-daemon /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
+Ss 0 731 1 575120 1368 0.0 26-03:07:21 systemd-logind /lib/systemd/systemd-logind
+Ssl 0 1111 1 121248 732 0.0 26-03:07:18 unattended-upgr /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
+S 0 1141 2 0 0 0.0 26-03:07:18 lockd [lockd]
+I< 0 1459 2 0 0 0.0 26-03:07:16 nfsiod [nfsiod]
+S 0 1621 2 0 0 0.0 26-03:07:15 NFSv4 callback [NFSv4 callback]
+Ssl 0 1771 1 1548340 676 0.0 26-03:07:13 libvirtd /usr/sbin/libvirtd
+I< 0 24315 2 0 0 0.0 26-02:49:02 cifsiod [cifsiod]
+I< 0 24316 2 0 0 0.0 26-02:49:02 smb3decryptd [smb3decryptd]
+I< 0 24317 2 0 0 0.0 26-02:49:02 cifsfileinfoput [cifsfileinfoput]
+I< 0 24318 2 0 0 0.0 26-02:49:02 cifsoplockd [cifsoplockd]
+I< 0 24319 2 0 0 0.0 26-02:49:02 cifs-dfscache [cifs-dfscache]
+S 0 24322 2 0 0 0.0 26-02:49:02 cifsd [cifsd]
+I< 0 24413 2 0 0 0.0 26-02:48:57 btrfs-worker [btrfs-worker]
+I< 0 24414 2 0 0 0.0 26-02:48:57 btrfs-worker-hi [btrfs-worker-hi]
+I< 0 24415 2 0 0 0.0 26-02:48:57 btrfs-delalloc [btrfs-delalloc]
+I< 0 24416 2 0 0 0.0 26-02:48:57 btrfs-flush_del [btrfs-flush_del]
+I< 0 24418 2 0 0 0.0 26-02:48:57 btrfs-cache [btrfs-cache]
+I< 0 24419 2 0 0 0.0 26-02:48:57 btrfs-fixup [btrfs-fixup]
+I< 0 24420 2 0 0 0.0 26-02:48:57 btrfs-endio [btrfs-endio]
+I< 0 24421 2 0 0 0.0 26-02:48:57 btrfs-endio-met [btrfs-endio-met]
+I< 0 24422 2 0 0 0.0 26-02:48:57 btrfs-endio-met [btrfs-endio-met]
+I< 0 24423 2 0 0 0.0 26-02:48:57 btrfs-endio-rai [btrfs-endio-rai]
+I< 0 24424 2 0 0 0.0 26-02:48:57 btrfs-rmw [btrfs-rmw]
+I< 0 24425 2 0 0 0.0 26-02:48:57 btrfs-endio-wri [btrfs-endio-wri]
+I< 0 24426 2 0 0 0.0 26-02:48:57 btrfs-freespace [btrfs-freespace]
+I< 0 24427 2 0 0 0.0 26-02:48:57 btrfs-delayed-m [btrfs-delayed-m]
+I< 0 24428 2 0 0 0.0 26-02:48:57 btrfs-readahead [btrfs-readahead]
+I< 0 24429 2 0 0 0.0 26-02:48:57 btrfs-qgroup-re [btrfs-qgroup-re]
+S 0 24450 2 0 0 0.0 26-02:48:53 btrfs-cleaner [btrfs-cleaner]
+S 0 24451 2 0 0 0.0 26-02:48:53 btrfs-transacti [btrfs-transacti]
+I< 0 747708 2 0 0 0.0 16-21:06:20 xfsalloc [xfsalloc]
+I< 0 747709 2 0 0 0.0 16-21:06:20 xfs_mru_cache [xfs_mru_cache]
+S 0 747713 2 0 0 0.0 16-21:06:20 jfsIO [jfsIO]
+S 0 747714 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
+S 0 747715 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
+S 0 747716 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
+S 0 747717 2 0 0 0.0 16-21:06:20 jfsCommit [jfsCommit]
+S 0 747718 2 0 0 0.0 16-21:06:20 jfsSync [jfsSync]
+Ss 0 1071687 1 105976 28304 0.0 3-03:12:31 systemd-journal /lib/systemd/systemd-journald
+Ss 0 1934146 1 25672 4704 0.0 11:19:31 cupsd /usr/sbin/cupsd -l
+Ssl 0 1934148 1 182868 8540 0.0 11:19:31 cups-browsed /usr/sbin/cups-browsed
+S 13 1934155 3392655 5752 88 0.0 11:19:31 pinger (pinger)
+S< 33 1934166 3393034 57996 5460 0.0 11:19:31 apache2 /usr/sbin/apache2 -k start
+S< 33 1934167 3393034 216944 13892 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
+S< 33 1934168 3393034 216944 13756 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
+S< 33 1934169 3393034 216936 13732 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
+S< 33 1934170 3393034 216944 13888 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
+S< 33 1934172 3393034 216944 15388 0.0 11:19:30 apache2 /usr/sbin/apache2 -k start
+S< 33 1934701 3393034 216936 13736 0.0 11:19:29 apache2 /usr/sbin/apache2 -k start
+S< 33 1935056 3393034 216920 13724 0.0 11:19:28 apache2 /usr/sbin/apache2 -k start
+S 7 1936834 1934146 16652 832 0.0 11:18:12 dbus /usr/lib/cups/notifier/dbus dbus://
+S< 33 1955909 3393034 216928 13792 0.0 11:00:25 apache2 /usr/sbin/apache2 -k start
+I< 0 2531464 2 0 0 0.0 06:35:47 kworker/u9:0-i9 [kworker/u9:0-i915_flip]
+I 0 2570506 2 0 0 0.0 06:27:41 kworker/1:0-cgr [kworker/1:0-cgroup_destroy]
+I 0 2596195 2 0 0 0.0 06:21:52 kworker/1:1-eve [kworker/1:1-events]
+I 0 2785341 2 0 0 0.0 03:34:16 kworker/u8:8-bt [kworker/u8:8-btrfs-endio-write]
+I 0 2785520 2 0 0 0.0 03:33:50 kworker/3:0-eve [kworker/3:0-events]
+I 0 2798669 2 0 0 0.0 03:21:09 kworker/u8:5-bt [kworker/u8:5-btrfs-endio-write]
+Ss 0 2803015 1 5616 3108 0.0 03:17:54 cron /usr/sbin/cron -f
+I 0 2845483 2 0 0 0.0 02:38:11 kworker/0:3-eve [kworker/0:3-events]
+I 0 2939490 2 0 0 0.1 01:10:32 kworker/0:0-eve [kworker/0:0-events]
+I 0 2939754 2 0 0 0.0 01:10:26 kworker/u8:1-i9 [kworker/u8:1-i915]
+I 0 2942040 2 0 0 0.0 01:08:02 kworker/u8:7-bt [kworker/u8:7-btrfs-endio-meta]
+S 117 2954268 3392551 40044 5772 0.0 56:37 pickup pickup -l -t unix -u -c
+I 0 2965195 2 0 0 0.0 46:00 kworker/u8:0-bt [kworker/u8:0-btrfs-worker]
+I 0 2977972 2 0 0 0.0 33:54 kworker/u8:2-bt [kworker/u8:2-btrfs-endio-write]
+I 0 2985488 2 0 0 0.0 27:02 kworker/u8:3-bl [kworker/u8:3-blkcg_punt_bio]
+I 0 2987519 2 0 0 1.0 25:15 kworker/2:1-eve [kworker/2:1-events]
+I 0 2987601 2 0 0 0.0 25:03 kworker/u8:9-i9 [kworker/u8:9-i915]
+I< 0 2995218 2 0 0 0.0 18:41 kworker/u9:2-xp [kworker/u9:2-xprtiod]
+I 0 2997170 2 0 0 0.0 16:41 kworker/3:1-rcu [kworker/3:1-rcu_gp]
+I 0 3001264 2 0 0 0.0 13:01 kworker/u8:4-bt [kworker/u8:4-btrfs-endio-write]
+I 0 3004697 2 0 0 0.7 09:41 kworker/2:0-eve [kworker/2:0-events]
+I 0 3010619 2 0 0 1.0 04:29 kworker/2:2-eve [kworker/2:2-events]
+I 0 3014612 2 0 0 0.0 00:41 kworker/3:2-eve [kworker/3:2-events]
+S 0 3015082 2803015 6716 3028 0.0 00:30 cron /usr/sbin/CRON -f
+I 0 3015382 2 0 0 0.0 00:00 kworker/u8:6-bt [kworker/u8:6-btrfs-endio-meta]
+Ss 1 3392068 1 5592 504 0.0 15-02:34:39 atd /usr/sbin/atd -f
+Ssl 0 3392072 1 235796 1740 0.0 15-02:34:39 accounts-daemon /usr/libexec/accounts-daemon
+Ssl 106 3392076 1 315708 6128 0.0 15-02:34:39 colord /usr/libexec/colord
+Ss 0 3392083 1 8120 720 0.0 15-02:34:39 haveged /usr/sbin/haveged --Foreground --verbose=1
+Ss 0 3392090 1 5168 132 0.0 15-02:34:39 blkmapd /usr/sbin/blkmapd
+SNsl 111 3392094 1 155648 440 0.0 15-02:34:39 rtkit-daemon /usr/libexec/rtkit-daemon
+Ssl 0 3392097 1 290168 1352 0.0 15-02:34:39 packagekitd /usr/libexec/packagekitd
+Ss 128 3392100 1 7960 448 0.0 15-02:34:39 rpcbind /sbin/rpcbind -f -w
+Ss 0 3392114 1 13432 616 0.0 15-02:34:39 systemd-machine /lib/systemd/systemd-machined
+Ss 0 3392118 1 13316 848 0.0 15-02:34:39 sshd sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
+Ssl 0 3392124 1 244072 2456 0.0 15-02:34:39 upowerd /usr/libexec/upowerd
+Ssl 0 3392138 1 1634748 10684 0.0 15-02:34:39 containerd /usr/bin/containerd
+Ssl 0 3392139 1 222768 1784 0.0 15-02:34:39 rsyslogd /usr/sbin/rsyslogd -n -iNONE
+Ss 13 3392140 1 3344 152 0.0 15-02:34:39 polipo /usr/bin/polipo -c /etc/polipo/config pidFile=/var/run/polipo/polipo.pid daemonise=true
+Ssl 119 3392156 1 76472 1688 0.0 15-02:34:39 ntpd /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 119:126
+Ss 120 3392168 1 4656 276 0.0 15-02:34:39 rpc.statd /sbin/rpc.statd --no-notify
+Ss 0 3392171 1 5072 432 0.0 15-02:34:39 rpc.mountd /usr/sbin/rpc.mountd --manage-gids
+Ss 0 3392176 1 5008 288 0.0 15-02:34:39 rpc.idmapd /usr/sbin/rpc.idmapd
+Ss 105 3392184 1 15544 6816 3.5 15-02:34:39 avahi-daemon avahi-daemon: running [tsui.local]
+Ss 0 3392186 1 25288 3860 0.0 15-02:34:39 systemd-udevd /lib/systemd/systemd-udevd
+S 105 3392190 3392184 8788 52 0.0 15-02:34:39 avahi-daemon avahi-daemon: chroot helper
+Ssl 0 3392197 1 396120 4188 0.0 15-02:34:39 udisksd /usr/libexec/udisks2/udisksd
+Ssl 0 3392214 1 237504 6632 0.0 15-02:34:39 polkitd /usr/libexec/polkitd --no-debug
+Ss 0 3392284 1 9684 560 0.0 15-02:34:38 xinetd /usr/sbin/xinetd -pidfile /run/xinetd.pid -stayalive -inetd_compat -inetd_ipv6
+Ssl 0 3392285 1 314840 1352 0.0 15-02:34:38 ModemManager /usr/sbin/ModemManager
+Ss 0 3392317 1 2352 140 0.0 15-02:34:38 acpid /usr/sbin/acpid
+S 0 3392400 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392401 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392402 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392403 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392404 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392405 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392407 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+S 0 3392410 2 0 0 0.0 15-02:34:38 nfsd [nfsd]
+Ss 0 3392551 1 40092 1304 0.0 15-02:34:37 master /usr/lib/postfix/sbin/master -w
+S 117 3392553 3392551 40156 568 0.0 15-02:34:37 qmgr qmgr -l -t unix -u
+Ss 0 3392650 1 63652 4 0.0 15-02:34:36 squid /usr/sbin/squid --foreground -sYC
+Ssl 116 3392652 1 1675196 93848 0.0 15-02:34:36 mariadbd /usr/sbin/mariadbd
+S 13 3392655 3392650 81776 21232 0.0 15-02:34:36 squid (squid-1) --kid squid-1 --foreground -sYC
+S 13 3392657 3392655 5572 68 0.0 15-02:34:36 log_file_daemon (logfile-daemon) /var/log/squid/access.log
+S<s 0 3393034 1 216648 7560 0.0 15-02:34:34 apache2 /usr/sbin/apache2 -k start
+Ss 33 3393037 1 3432 180 0.0 15-02:34:34 htcacheclean /usr/bin/htcacheclean -d 120 -p /var/cache/apache2/mod_cache_disk -l 300M -n
diff --git a/plugins/tests/var/root b/plugins/tests/var/root
new file mode 100644
index 0000000..9339e13
--- /dev/null
+++ b/plugins/tests/var/root
@@ -0,0 +1 @@
+Root
diff --git a/plugins/urlize.c b/plugins/urlize.c
new file mode 100644
index 0000000..6fda72d
--- /dev/null
+++ b/plugins/urlize.c
@@ -0,0 +1,198 @@
+/*****************************************************************************
+*
+* Monitoring urlize plugin
+*
+* License: GPL
+* Copyright (c) 2000-2007 Monitoring Plugins Development Team
+*
+* Description:
+*
+* This file contains the urlize plugin
+*
+* This plugin wraps the text output of another command (plugin) in HTML <A>
+* tags. This plugin returns the status of the invoked plugin.
+*
+*
+* 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+const char *progname = "urlize";
+const char *copyright = "2000-2006";
+const char *email = "devel@monitoring-plugins.org";
+
+#include "common.h"
+#include "utils.h"
+#include "popen.h"
+
+#define PERF_CHARACTER "|"
+#define NEWLINE_CHARACTER '\n'
+
+void print_help (void);
+void print_usage (void);
+
+int
+main (int argc, char **argv)
+{
+ int found = 0, result = STATE_UNKNOWN;
+ char *url = NULL;
+ char *cmd;
+ char *buf;
+ char *nstr;
+ char tstr[MAX_INPUT_BUFFER];
+
+ int c;
+ int option = 0;
+ static struct option longopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"url", required_argument, 0, 'u'},
+ {0, 0, 0, 0}
+ };
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ /* Need at least 2 args */
+ if (argc < 3) {
+ print_help();
+ exit (STATE_UNKNOWN);
+ }
+
+ while (1) {
+ c = getopt_long (argc, argv, "+hVu:", longopts, &option);
+
+ if (c == -1 || c == EOF)
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ print_help ();
+ exit (EXIT_SUCCESS);
+ break;
+ case 'V': /* version */
+ print_revision (progname, NP_VERSION);
+ exit (EXIT_SUCCESS);
+ break;
+ case 'u':
+ url = strdup (argv[optind]);
+ break;
+ case '?':
+ default:
+ usage5 ();
+ }
+ }
+
+ if (url == NULL)
+ url = strdup (argv[optind++]);
+
+ cmd = strdup (argv[optind++]);
+ for (c = optind; c < argc; c++) {
+ xasprintf (&cmd, "%s %s", cmd, argv[c]);
+ }
+
+ child_process = spopen (cmd);
+ if (child_process == NULL) {
+ printf (_("Could not open pipe: %s\n"), cmd);
+ exit (STATE_UNKNOWN);
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL) {
+ printf (_("Could not open stderr for %s\n"), cmd);
+ }
+
+ bzero(tstr, sizeof(tstr));
+ buf = malloc(MAX_INPUT_BUFFER);
+ printf ("<A href=\"%s\">", argv[1]);
+ while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) {
+ found++;
+ /* Collect the string in temp str so we can tokenize */
+ strcat(tstr, buf);
+ }
+
+ if (!found)
+ die (STATE_UNKNOWN,
+ _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"),
+ argv[0], cmd);
+
+
+ /* chop the newline character */
+ if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL)
+ *nstr = '\0';
+
+ /* tokenize the string for Perfdata if there is some */
+ nstr = strtok(tstr, PERF_CHARACTER);
+ printf ("%s", nstr);
+ printf ("</A>");
+ nstr = strtok(NULL, PERF_CHARACTER);
+ if (nstr != NULL)
+ printf (" | %s", nstr);
+
+ /* close the pipe */
+ result = spclose (child_process);
+
+ /* WARNING if output found on stderr */
+ if (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr))
+ result = max_state (result, STATE_WARNING);
+
+ /* close stderr */
+ (void) fclose (child_stderr);
+
+ return result;
+}
+
+
+
+void
+print_help (void)
+{
+ print_revision (progname, NP_VERSION);
+
+ printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
+ printf (COPYRIGHT, copyright, email);
+
+ printf ("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
+ printf ("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
+ printf ("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin."));
+
+ printf ("\n\n");
+
+ print_usage ();
+
+ printf (UT_HELP_VRSN);
+
+ printf ("\n");
+ printf ("%s\n", _("Examples:"));
+ printf ("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected"));
+ printf ("%s\n\n", _("data to the plugin. For example, in:"));
+ printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'"));
+ printf (" %s\n", _("the shell will remove the single quotes and urlize will see:"));
+ printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words"));
+ printf (" %s\n\n", _("You probably want:"));
+ printf (" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\""));
+
+ printf (UT_SUPPORT);
+}
+
+
+
+void
+print_usage (void)
+{
+ printf ("%s\n", _("Usage:"));
+ printf ("%s <url> <plugin> <arg1> ... <argN>\n", progname);
+}
diff --git a/plugins/utils.c b/plugins/utils.c
new file mode 100644
index 0000000..71c0bdd
--- /dev/null
+++ b/plugins/utils.c
@@ -0,0 +1,806 @@
+/*****************************************************************************
+*
+* Library of useful functions for plugins
+*
+* License: GPL
+* Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
+* Copyright (c) 2002-2007 Monitoring Plugins 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 3 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 <http://www.gnu.org/licenses/>.
+*
+*
+*****************************************************************************/
+
+#include "common.h"
+#include "utils.h"
+#include "utils_base.h"
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+extern void print_usage (void);
+extern const char *progname;
+
+#define STRLEN 64
+#define TXTBLK 128
+
+time_t start_time, end_time;
+
+/* **************************************************************************
+ * max_state(STATE_x, STATE_y)
+ * compares STATE_x to STATE_y and returns result based on the following
+ * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
+ *
+ * Note that numerically the above does not hold
+ ****************************************************************************/
+
+int
+max_state (int a, int b)
+{
+ if (a == STATE_CRITICAL || b == STATE_CRITICAL)
+ return STATE_CRITICAL;
+ else if (a == STATE_WARNING || b == STATE_WARNING)
+ return STATE_WARNING;
+ else if (a == STATE_OK || b == STATE_OK)
+ return STATE_OK;
+ else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
+ return STATE_UNKNOWN;
+ else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
+ return STATE_DEPENDENT;
+ else
+ return max (a, b);
+}
+
+/* **************************************************************************
+ * max_state_alt(STATE_x, STATE_y)
+ * compares STATE_x to STATE_y and returns result based on the following
+ * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
+ *
+ * The main difference between max_state_alt and max_state it that it doesn't
+ * allow setting a default to UNKNOWN. It will instead prioritixe any valid
+ * non-OK state.
+ ****************************************************************************/
+
+int
+max_state_alt (int a, int b)
+{
+ if (a == STATE_CRITICAL || b == STATE_CRITICAL)
+ return STATE_CRITICAL;
+ else if (a == STATE_WARNING || b == STATE_WARNING)
+ return STATE_WARNING;
+ else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
+ return STATE_UNKNOWN;
+ else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
+ return STATE_DEPENDENT;
+ else if (a == STATE_OK || b == STATE_OK)
+ return STATE_OK;
+ else
+ return max (a, b);
+}
+
+void usage (const char *msg)
+{
+ printf ("%s\n", msg);
+ print_usage ();
+ exit (STATE_UNKNOWN);
+}
+
+void usage_va (const char *fmt, ...)
+{
+ va_list ap;
+ printf("%s: ", progname);
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+ exit (STATE_UNKNOWN);
+}
+
+void usage2(const char *msg, const char *arg)
+{
+ printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" );
+ print_usage ();
+ exit (STATE_UNKNOWN);
+}
+
+void
+usage3 (const char *msg, int arg)
+{
+ printf ("%s: %s - %c\n", progname, msg, arg);
+ print_usage();
+ exit (STATE_UNKNOWN);
+}
+
+void
+usage4 (const char *msg)
+{
+ printf ("%s: %s\n", progname, msg);
+ print_usage();
+ exit (STATE_UNKNOWN);
+}
+
+void
+usage5 (void)
+{
+ print_usage();
+ exit (STATE_UNKNOWN);
+}
+
+void
+print_revision (const char *command_name, const char *revision)
+{
+ printf ("%s v%s (%s %s)\n",
+ command_name, revision, PACKAGE, VERSION);
+}
+
+int
+is_numeric (char *number)
+{
+ char tmp[1];
+ float x;
+
+ if (!number)
+ return FALSE;
+ else if (sscanf (number, "%f%c", &x, tmp) == 1)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_positive (char *number)
+{
+ if (is_numeric (number) && atof (number) > 0.0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_negative (char *number)
+{
+ if (is_numeric (number) && atof (number) < 0.0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_nonnegative (char *number)
+{
+ if (is_numeric (number) && atof (number) >= 0.0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_percentage (char *number)
+{
+ int x;
+ if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_integer (char *number)
+{
+ long int n;
+
+ if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
+ return FALSE;
+
+ n = strtol (number, NULL, 10);
+
+ if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_intpos (char *number)
+{
+ if (is_integer (number) && atoi (number) > 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_intneg (char *number)
+{
+ if (is_integer (number) && atoi (number) < 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_intnonneg (char *number)
+{
+ if (is_integer (number) && atoi (number) >= 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*
+ * Checks whether the number in the string _number_ can be put inside a int64_t
+ * On success the number will be written to the _target_ address, if _target_ is not set
+ * to NULL.
+ */
+int is_int64(char *number, int64_t *target) {
+ errno = 0;
+ uint64_t tmp = strtoll(number, NULL, 10);
+ if (errno != 0) {
+ return 0;
+ }
+ if (tmp < INT64_MIN || tmp > INT64_MAX) {
+ return 0;
+ }
+ if (target != NULL) {
+ *target = tmp;
+ }
+ return 1;
+}
+
+/*
+ * Checks whether the number in the string _number_ can be put inside a uint64_t
+ * On success the number will be written to the _target_ address, if _target_ is not set
+ * to NULL.
+ */
+int is_uint64(char *number, uint64_t *target) {
+ errno = 0;
+ uint64_t tmp = strtoll(number, NULL, 10);
+ if (errno != 0) {
+ return 0;
+ }
+ if (tmp < 0 || tmp > UINT64_MAX) {
+ return 0;
+ }
+ if (target != NULL) {
+ *target = tmp;
+ }
+ return 1;
+}
+
+int
+is_intpercent (char *number)
+{
+ int i;
+ if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int
+is_option (char *str)
+{
+ if (!str)
+ return FALSE;
+ else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+#ifdef NEED_GETTIMEOFDAY
+int
+gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+ tv->tv_usec = 0;
+ tv->tv_sec = (long) time ((time_t) 0);
+}
+#endif
+
+
+
+double
+delta_time (struct timeval tv)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+ return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
+}
+
+
+
+long
+deltime (struct timeval tv)
+{
+ struct timeval now;
+ gettimeofday (&now, NULL);
+ return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
+}
+
+
+
+
+void
+strip (char *buffer)
+{
+ size_t x;
+ int i;
+
+ for (x = strlen (buffer); x >= 1; x--) {
+ i = x - 1;
+ if (buffer[i] == ' ' ||
+ buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
+ buffer[i] = '\0';
+ else
+ break;
+ }
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * Copies one string to another. Any previously existing data in
+ * the destination string is lost.
+ *
+ * Example:
+ *
+ * char *str=NULL;
+ * str = strscpy("This is a line of text with no trailing newline");
+ *
+ *****************************************************************************/
+
+char *
+strscpy (char *dest, const char *src)
+{
+ if (src == NULL)
+ return NULL;
+
+ xasprintf (&dest, "%s", src);
+
+ return dest;
+}
+
+
+
+/******************************************************************************
+ *
+ * Returns a pointer to the next line of a multiline string buffer
+ *
+ * Given a pointer string, find the text following the next sequence
+ * of \r and \n characters. This has the effect of skipping blank
+ * lines as well
+ *
+ * Example:
+ *
+ * Given text as follows:
+ *
+ * ==============================
+ * This
+ * is
+ * a
+ *
+ * multiline string buffer
+ * ==============================
+ *
+ * int i=0;
+ * char *str=NULL;
+ * char *ptr=NULL;
+ * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
+ * ptr = str;
+ * while (ptr) {
+ * printf("%d %s",i++,firstword(ptr));
+ * ptr = strnl(ptr);
+ * }
+ *
+ * Produces the following:
+ *
+ * 1 This
+ * 2 is
+ * 3 a
+ * 4 multiline
+ *
+ * NOTE: The 'firstword()' function is conceptual only and does not
+ * exist in this package.
+ *
+ * NOTE: Although the second 'ptr' variable is not strictly needed in
+ * this example, it is good practice with these utilities. Once
+ * the * pointer is advance in this manner, it may no longer be
+ * handled with * realloc(). So at the end of the code fragment
+ * above, * strscpy(str,"foo") work perfectly fine, but
+ * strscpy(ptr,"foo") will * cause the the program to crash with
+ * a segmentation fault.
+ *
+ *****************************************************************************/
+
+char *
+strnl (char *str)
+{
+ size_t len;
+ if (str == NULL)
+ return NULL;
+ str = strpbrk (str, "\r\n");
+ if (str == NULL)
+ return NULL;
+ len = strspn (str, "\r\n");
+ if (str[len] == '\0')
+ return NULL;
+ str += len;
+ if (strlen (str) == 0)
+ return NULL;
+ return str;
+}
+
+
+/******************************************************************************
+ *
+ * Like strscpy, except only the portion of the source string up to
+ * the provided delimiter is copied.
+ *
+ * Example:
+ *
+ * str = strpcpy(str,"This is a line of text with no trailing newline","x");
+ * printf("%s\n",str);
+ *
+ * Produces:
+ *
+ *This is a line of te
+ *
+ *****************************************************************************/
+
+char *
+strpcpy (char *dest, const char *src, const char *str)
+{
+ size_t len;
+
+ if (src)
+ len = strcspn (src, str);
+ else
+ return NULL;
+
+ if (dest == NULL || strlen (dest) < len)
+ dest = realloc (dest, len + 1);
+ if (dest == NULL)
+ die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
+
+ strncpy (dest, src, len);
+ dest[len] = '\0';
+
+ return dest;
+}
+
+
+
+/******************************************************************************
+ *
+ * Like strscat, except only the portion of the source string up to
+ * the provided delimiter is copied.
+ *
+ * str = strpcpy(str,"This is a line of text with no trailing newline","x");
+ * str = strpcat(str,"This is a line of text with no trailing newline","x");
+ * printf("%s\n",str);
+ *
+ *This is a line of texThis is a line of tex
+ *
+ *****************************************************************************/
+
+char *
+strpcat (char *dest, const char *src, const char *str)
+{
+ size_t len, l2;
+
+ if (dest)
+ len = strlen (dest);
+ else
+ len = 0;
+
+ if (src) {
+ l2 = strcspn (src, str);
+ }
+ else {
+ return dest;
+ }
+
+ dest = realloc (dest, len + l2 + 1);
+ if (dest == NULL)
+ die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
+
+ strncpy (dest + len, src, l2);
+ dest[len + l2] = '\0';
+
+ return dest;
+}
+
+
+/******************************************************************************
+ *
+ * asprintf, but die on failure
+ *
+ ******************************************************************************/
+
+int
+xvasprintf (char **strp, const char *fmt, va_list ap)
+{
+ int result = vasprintf (strp, fmt, ap);
+ if (result == -1 || *strp == NULL)
+ die (STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
+ return result;
+}
+
+int
+xasprintf (char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+ va_start (ap, fmt);
+ result = xvasprintf (strp, fmt, ap);
+ va_end (ap);
+ return result;
+}
+
+/******************************************************************************
+ *
+ * Print perfdata in a standard format
+ *
+ ******************************************************************************/
+
+char *perfdata (const char *label,
+ long int val,
+ const char *uom,
+ int warnp,
+ long int warn,
+ int critp,
+ long int crit,
+ int minp,
+ long int minv,
+ int maxp,
+ long int maxv)
+{
+ char *data = NULL;
+
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=%ld%s;", label, val, uom);
+ else
+ xasprintf (&data, "%s=%ld%s;", label, val, uom);
+
+ if (warnp)
+ xasprintf (&data, "%s%ld;", data, warn);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (critp)
+ xasprintf (&data, "%s%ld;", data, crit);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%ld;", data, minv);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (maxp)
+ xasprintf (&data, "%s%ld", data, maxv);
+
+ return data;
+}
+
+
+char *perfdata_uint64 (const char *label,
+ uint64_t val,
+ const char *uom,
+ int warnp, /* Warning present */
+ uint64_t warn,
+ int critp, /* Critical present */
+ uint64_t crit,
+ int minp, /* Minimum present */
+ uint64_t minv,
+ int maxp, /* Maximum present */
+ uint64_t maxv)
+{
+ char *data = NULL;
+
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
+ else
+ xasprintf (&data, "%s=%" PRIu64 "%s;", label, val, uom);
+
+ if (warnp)
+ xasprintf (&data, "%s%" PRIu64 ";", data, warn);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (critp)
+ xasprintf (&data, "%s%" PRIu64 ";", data, crit);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%" PRIu64 ";", data, minv);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (maxp)
+ xasprintf (&data, "%s%" PRIu64, data, maxv);
+
+ return data;
+}
+
+
+char *perfdata_int64 (const char *label,
+ int64_t val,
+ const char *uom,
+ int warnp, /* Warning present */
+ int64_t warn,
+ int critp, /* Critical present */
+ int64_t crit,
+ int minp, /* Minimum present */
+ int64_t minv,
+ int maxp, /* Maximum present */
+ int64_t maxv)
+{
+ char *data = NULL;
+
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=%" PRId64 "%s;", label, val, uom);
+ else
+ xasprintf (&data, "%s=%" PRId64 "%s;", label, val, uom);
+
+ if (warnp)
+ xasprintf (&data, "%s%" PRId64 ";", data, warn);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (critp)
+ xasprintf (&data, "%s%" PRId64 ";", data, crit);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%" PRId64 ";", data, minv);
+ else
+ xasprintf (&data, "%s;", data);
+
+ if (maxp)
+ xasprintf (&data, "%s%" PRId64, data, maxv);
+
+ return data;
+}
+
+
+char *fperfdata (const char *label,
+ double val,
+ const char *uom,
+ int warnp,
+ double warn,
+ int critp,
+ double crit,
+ int minp,
+ double minv,
+ int maxp,
+ double maxv)
+{
+ char *data = NULL;
+
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=", label);
+ else
+ xasprintf (&data, "%s=", label);
+
+ xasprintf (&data, "%s%f", data, val);
+ xasprintf (&data, "%s%s;", data, uom);
+
+ if (warnp)
+ xasprintf (&data, "%s%f", data, warn);
+
+ xasprintf (&data, "%s;", data);
+
+ if (critp)
+ xasprintf (&data, "%s%f", data, crit);
+
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%f", data, minv);
+
+ if (maxp) {
+ xasprintf (&data, "%s;", data);
+ xasprintf (&data, "%s%f", data, maxv);
+ }
+
+ return data;
+}
+
+char *sperfdata (const char *label,
+ double val,
+ const char *uom,
+ char *warn,
+ char *crit,
+ int minp,
+ double minv,
+ int maxp,
+ double maxv)
+{
+ char *data = NULL;
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=", label);
+ else
+ xasprintf (&data, "%s=", label);
+
+ xasprintf (&data, "%s%f", data, val);
+ xasprintf (&data, "%s%s;", data, uom);
+
+ if (warn!=NULL)
+ xasprintf (&data, "%s%s", data, warn);
+
+ xasprintf (&data, "%s;", data);
+
+ if (crit!=NULL)
+ xasprintf (&data, "%s%s", data, crit);
+
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%f", data, minv);
+
+ if (maxp) {
+ xasprintf (&data, "%s;", data);
+ xasprintf (&data, "%s%f", data, maxv);
+ }
+
+ return data;
+}
+
+char *sperfdata_int (const char *label,
+ int val,
+ const char *uom,
+ char *warn,
+ char *crit,
+ int minp,
+ int minv,
+ int maxp,
+ int maxv)
+{
+ char *data = NULL;
+ if (strpbrk (label, "'= "))
+ xasprintf (&data, "'%s'=", label);
+ else
+ xasprintf (&data, "%s=", label);
+
+ xasprintf (&data, "%s%d", data, val);
+ xasprintf (&data, "%s%s;", data, uom);
+
+ if (warn!=NULL)
+ xasprintf (&data, "%s%s", data, warn);
+
+ xasprintf (&data, "%s;", data);
+
+ if (crit!=NULL)
+ xasprintf (&data, "%s%s", data, crit);
+
+ xasprintf (&data, "%s;", data);
+
+ if (minp)
+ xasprintf (&data, "%s%d", data, minv);
+
+ if (maxp) {
+ xasprintf (&data, "%s;", data);
+ xasprintf (&data, "%s%d", data, maxv);
+ }
+
+ return data;
+}
diff --git a/plugins/utils.h b/plugins/utils.h
new file mode 100644
index 0000000..cb979ce
--- /dev/null
+++ b/plugins/utils.h
@@ -0,0 +1,198 @@
+#ifndef NP_UTILS_H
+#define NP_UTILS_H
+/* Header file for Monitoring Plugins utils.c */
+
+/* This file should be included in all plugins */
+
+/* The purpose of this package is to provide safer alternatives to C
+functions that might otherwise be vulnerable to hacking. This
+currently includes a standard suite of validation routines to be sure
+that an string argument actually converts to its intended type and a
+suite of string handling routine that do their own memory management
+in order to resist overflow attacks. In addition, a few functions are
+provided to standardize version and error reporting across the entire
+suite of plugins. */
+
+/* now some functions etc are being defined in ../lib/utils_base.c */
+#include "utils_base.h"
+
+
+#ifdef NP_EXTRA_OPTS
+/* Include extra-opts functions if compiled in */
+#include "extra_opts.h"
+#else
+/* else, fake np_extra_opts */
+#define np_extra_opts(acptr,av,pr) av
+#endif
+
+/* Standardize version information, termination */
+
+void support (void);
+void print_revision (const char *, const char *);
+
+extern time_t start_time, end_time;
+
+/* Test input types */
+
+int is_integer (char *);
+int is_intpos (char *);
+int is_intneg (char *);
+int is_intnonneg (char *);
+int is_intpercent (char *);
+int is_uint64(char *number, uint64_t *target);
+int is_int64(char *number, int64_t *target);
+
+int is_numeric (char *);
+int is_positive (char *);
+int is_negative (char *);
+int is_nonnegative (char *);
+int is_percentage (char *);
+
+int is_option (char *);
+
+/* Generalized timer that will do milliseconds if available */
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* microseconds */
+};
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+int gettimeofday(struct timeval *, struct timezone *);
+#endif
+
+double delta_time (struct timeval tv);
+long deltime (struct timeval tv);
+
+/* Handle strings safely */
+
+void strip (char *);
+char *strscpy (char *, const char *);
+char *strnl (char *);
+char *strpcpy (char *, const char *, const char *);
+char *strpcat (char *, const char *, const char *);
+int xvasprintf (char **strp, const char *fmt, va_list ap);
+int xasprintf (char **strp, const char *fmt, ...);
+
+int max_state (int a, int b);
+int max_state_alt (int a, int b);
+
+void usage (const char *) __attribute__((noreturn));
+void usage2(const char *, const char *) __attribute__((noreturn));
+void usage3(const char *, int) __attribute__((noreturn));
+void usage4(const char *) __attribute__((noreturn));
+void usage5(void) __attribute__((noreturn));
+void usage_va(const char *fmt, ...) __attribute__((noreturn));
+
+#define max(a,b) (((a)>(b))?(a):(b))
+#define min(a,b) (((a)<(b))?(a):(b))
+
+char *perfdata (const char *, long int, const char *, int, long int,
+ int, long int, int, long int, int, long int);
+
+char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t,
+ int, uint64_t, int, uint64_t, int, uint64_t);
+
+char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t,
+ int, int64_t, int, int64_t, int, int64_t);
+
+char *fperfdata (const char *, double, const char *, int, double,
+ int, double, int, double, int, double);
+
+char *sperfdata (const char *, double, const char *, char *, char *,
+ int, double, int, double);
+
+char *sperfdata_int (const char *, int, const char *, char *, char *,
+ int, int, int, int);
+
+/* The idea here is that, although not every plugin will use all of these,
+ most will or should. Therefore, for consistency, these very common
+ options should have only these meanings throughout the overall suite */
+
+#define STD_LONG_OPTS \
+{"version",no_argument,0,'V'},\
+{"verbose",no_argument,0,'v'},\
+{"help",no_argument,0,'h'},\
+{"timeout",required_argument,0,'t'},\
+{"critical",required_argument,0,'c'},\
+{"warning",required_argument,0,'w'},\
+{"hostname",required_argument,0,'H'}
+
+#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\
+\t<%s>\n\n"
+
+#define UT_HLP_VRS _("\
+ %s (-h | --help) for detailed help\n\
+ %s (-V | --version) for version information\n")
+
+#define UT_HELP_VRSN _("\
+\nOptions:\n\
+ -h, --help\n\
+ Print detailed help screen\n\
+ -V, --version\n\
+ Print version information\n")
+
+#define UT_HOST_PORT _("\
+ -H, --hostname=ADDRESS\n\
+ Host name, IP Address, or unix socket (must be an absolute path)\n\
+ -%c, --port=INTEGER\n\
+ Port number (default: %s)\n")
+
+#define UT_IPv46 _("\
+ -4, --use-ipv4\n\
+ Use IPv4 connection\n\
+ -6, --use-ipv6\n\
+ Use IPv6 connection\n")
+
+#define UT_VERBOSE _("\
+ -v, --verbose\n\
+ Show details for command-line debugging (output may be truncated by\n\
+ the monitoring system)\n")
+
+#define UT_WARN_CRIT _("\
+ -w, --warning=DOUBLE\n\
+ Response time to result in warning status (seconds)\n\
+ -c, --critical=DOUBLE\n\
+ Response time to result in critical status (seconds)\n")
+
+#define UT_WARN_CRIT_RANGE _("\
+ -w, --warning=RANGE\n\
+ Warning range (format: start:end). Alert if outside this range\n\
+ -c, --critical=RANGE\n\
+ Critical range\n")
+
+#define UT_CONN_TIMEOUT _("\
+ -t, --timeout=INTEGER\n\
+ Seconds before connection times out (default: %d)\n")
+
+#define UT_PLUG_TIMEOUT _("\
+ -t, --timeout=INTEGER\n\
+ Seconds before plugin times out (default: %d)\n")
+
+#ifdef NP_EXTRA_OPTS
+#define UT_EXTRA_OPTS _("\
+ --extra-opts=[section][@file]\n\
+ Read options from an ini file. See\n\
+ https://www.monitoring-plugins.org/doc/extra-opts.html\n\
+ for usage and examples.\n")
+#else
+#define UT_EXTRA_OPTS " \b"
+#endif
+
+#define UT_THRESHOLDS_NOTES _("\
+ See:\n\
+ https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
+ for THRESHOLD format and examples.\n")
+
+#define UT_SUPPORT _("\n\
+Send email to help@monitoring-plugins.org if you have questions regarding\n\
+use of this software. To submit patches or suggest improvements, send email\n\
+to devel@monitoring-plugins.org\n\n")
+
+#define UT_NOWARRANTY _("\n\
+The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
+copies of the plugins under the terms of the GNU General Public License.\n\
+For more information about these matters, see the file named COPYING.\n")
+
+#endif /* NP_UTILS_H */