diff options
Diffstat (limited to 'plugins')
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='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + 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 (¤t_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 (¤t_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 (¤t_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(¤t_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 */ |