summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.github/mock.sh2
-rw-r--r--.gitignore7
-rw-r--r--configure.ac106
-rw-r--r--plugins/Makefile.am21
-rw-r--r--plugins/check_swap.c786
-rw-r--r--plugins/check_swap.d/check_swap.h43
-rw-r--r--plugins/check_swap.d/swap.c469
-rw-r--r--plugins/common.h10
-rw-r--r--plugins/t/check_swap.t6
-rw-r--r--plugins/tests/test_check_swap.c23
-rwxr-xr-xplugins/tests/test_check_swap.t6
-rw-r--r--plugins/tests/var/proc_meminfo55
12 files changed, 926 insertions, 608 deletions
diff --git a/.github/mock.sh b/.github/mock.sh
index ea4f7f3d..8f84756c 100755
--- a/.github/mock.sh
+++ b/.github/mock.sh
@@ -59,7 +59,7 @@ mkdir -p "${SRCRPM_DIR}" "${RPM_DIR}"
59dnf -y --setopt="tsflags=nodocs" install rpmdevtools && \ 59dnf -y --setopt="tsflags=nodocs" install rpmdevtools && \
60 spectool -g -C ${SOURCE_DIR} ${SPEC_FILE} && \ 60 spectool -g -C ${SOURCE_DIR} ${SPEC_FILE} && \
61 mock --init && \ 61 mock --init && \
62 { mock --no-clean --spec ${SPEC_FILE} --sources=${SOURCE_DIR} --result=${SRCRPM_DIR} --build || \ 62 { mock --no-clean --spec ${SPEC_FILE} --sources=${SOURCE_DIR} --result=${SRCRPM_DIR} --buildsrpm || \
63 { cat ${SRCRPM_DIR}/{root,build}.log; exit 1; } } && \ 63 { cat ${SRCRPM_DIR}/{root,build}.log; exit 1; } } && \
64 { mock --no-clean --sources=${SOURCE_DIR} --result=${RPM_DIR} --rebuild "${SRCRPM_DIR}"/${SRC_RPM} || \ 64 { mock --no-clean --sources=${SOURCE_DIR} --result=${RPM_DIR} --rebuild "${SRCRPM_DIR}"/${SRC_RPM} || \
65 { cat ${RPM_DIR}/{root,build}.log; exit 1; } } 65 { cat ${RPM_DIR}/{root,build}.log; exit 1; } }
diff --git a/.gitignore b/.gitignore
index 6f903d61..0b5028ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@ NP-VERSION-FILE
58/gl/charset.alias 58/gl/charset.alias
59/gl/configmake.h 59/gl/configmake.h
60/gl/errno.h 60/gl/errno.h
61/gl/error.h
61/gl/fcntl.h 62/gl/fcntl.h
62/gl/float.h 63/gl/float.h
63/gl/getopt.h 64/gl/getopt.h
@@ -221,7 +222,13 @@ NP-VERSION-FILE
221/plugins/tests/Makefile.in 222/plugins/tests/Makefile.in
222/plugins/tests/test_utils 223/plugins/tests/test_utils
223/plugins/tests/test_disk 224/plugins/tests/test_disk
225/plugins/tests/test_check_swap
224/plugins/tests/.deps 226/plugins/tests/.deps
227/plugins/tests/.dirstamp
228
229# /plugins/check_swap.d
230/plugins/check_swap.d/.deps
231/plugins/check_swap.d/.dirstamp
225 232
226# /plugins-root/ 233# /plugins-root/
227/plugins-root/.deps 234/plugins-root/.deps
diff --git a/configure.ac b/configure.ac
index 8594238f..ef3d26e2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
1dnl Process this file with autoconf to produce a configure script. 1dnl Process this file with autoconf to produce a configure script.
2AC_PREREQ(2.64) 2AC_PREREQ([2.64])
3AC_INIT(monitoring-plugins,2.4git) 3AC_INIT([monitoring-plugins],[2.4git])
4AC_CONFIG_SRCDIR(NPTest.pm) 4AC_CONFIG_SRCDIR(NPTest.pm)
5AC_CONFIG_FILES([gl/Makefile]) 5AC_CONFIG_FILES([gl/Makefile])
6AC_CONFIG_AUX_DIR(build-aux) 6AC_CONFIG_AUX_DIR(build-aux)
7AM_INIT_AUTOMAKE([1.8.3]) 7AM_INIT_AUTOMAKE([1.8.3 subdir-objects])
8AM_SILENT_RULES([yes]) 8AM_SILENT_RULES([yes])
9AM_MAINTAINER_MODE([enable]) 9AM_MAINTAINER_MODE([enable])
10AC_CONFIG_HEADERS([config.h]) 10AC_CONFIG_HEADERS([config.h])
@@ -43,14 +43,14 @@ AC_SUBST(INSTALL)
43AC_PROG_CC 43AC_PROG_CC
44gl_EARLY 44gl_EARLY
45AC_PROG_GCC_TRADITIONAL 45AC_PROG_GCC_TRADITIONAL
46AC_PROG_LIBTOOL 46LT_INIT
47 47
48AM_PROG_CC_C_O 48AM_PROG_CC_C_O
49 49
50AC_FUNC_ERROR_AT_LINE 50AC_FUNC_ERROR_AT_LINE
51AC_SYS_LARGEFILE 51AC_SYS_LARGEFILE
52 52
53ifdef([AC_FUNC_STRTOD],[AC_FUNC_STRTOD],[AM_FUNC_STRTOD]) 53ifdef([AC_FUNC_STRTOD],[AC_FUNC_STRTOD],[AC_FUNC_STRTOD])
54 54
55PLUGIN_TEST=`echo $srcdir/plugins/t/*.t|sed -e 's,\.*/plugins/,,g'` 55PLUGIN_TEST=`echo $srcdir/plugins/t/*.t|sed -e 's,\.*/plugins/,,g'`
56AC_SUBST(PLUGIN_TEST)dnl 56AC_SUBST(PLUGIN_TEST)dnl
@@ -125,8 +125,7 @@ AC_SUBST(PERL, $with_perl)
125 125
126dnl openssl/gnutls 126dnl openssl/gnutls
127AC_ARG_WITH(openssl, 127AC_ARG_WITH(openssl,
128 AC_HELP_STRING([--with-openssl=DIR], 128 AS_HELP_STRING([--with-openssl=DIR],[path to openssl installation]),)
129 [path to openssl installation]),)
130 129
131AC_ARG_WITH(gnutls, 130AC_ARG_WITH(gnutls,
132 ACX_HELP_STRING([--with-gnutls=PATH], 131 ACX_HELP_STRING([--with-gnutls=PATH],
@@ -167,8 +166,7 @@ AC_SUBST(MATHLIBS)
167 166
168dnl Check if we buils local libtap 167dnl Check if we buils local libtap
169AC_ARG_ENABLE(libtap, 168AC_ARG_ENABLE(libtap,
170 AC_HELP_STRING([--enable-libtap], 169 AS_HELP_STRING([--enable-libtap],[Enable built-in libtap for unit-testing (default: autodetect system library).]),
171 [Enable built-in libtap for unit-testing (default: autodetect system library).]),
172 [enable_libtap=$enableval], 170 [enable_libtap=$enableval],
173 [enable_libtap=no]) 171 [enable_libtap=no])
174AM_CONDITIONAL([USE_LIBTAP_LOCAL],[test "$enable_libtap" = "yes"]) 172AM_CONDITIONAL([USE_LIBTAP_LOCAL],[test "$enable_libtap" = "yes"])
@@ -185,12 +183,14 @@ fi
185if test "$enable_libtap" = "yes" ; then 183if test "$enable_libtap" = "yes" ; then
186 EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64" 184 EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64"
187 AC_SUBST(EXTRA_TEST) 185 AC_SUBST(EXTRA_TEST)
186
187 EXTRA_PLUGIN_TESTS="tests/test_check_swap"
188 AC_SUBST(EXTRA_PLUGIN_TESTS)
188fi 189fi
189 190
190dnl INI Parsing 191dnl INI Parsing
191AC_ARG_ENABLE(extra-opts, 192AC_ARG_ENABLE(extra-opts,
192 AC_HELP_STRING([--enable-extra-opts], 193 AS_HELP_STRING([--enable-extra-opts],[Enables parsing of plugins ini config files for extra options (default: no)]),
193 [Enables parsing of plugins ini config files for extra options (default: no)]),
194 [enable_extra_opts=$enableval], 194 [enable_extra_opts=$enableval],
195 [enable_extra_opts=yes]) 195 [enable_extra_opts=yes])
196AM_CONDITIONAL([USE_PARSE_INI],[test "$enable_extra_opts" = "yes"]) 196AM_CONDITIONAL([USE_PARSE_INI],[test "$enable_extra_opts" = "yes"])
@@ -464,20 +464,16 @@ AC_ARG_WITH([ipv6],
464dnl Check for AF_INET6 support - unistd.h required for Darwin 464dnl Check for AF_INET6 support - unistd.h required for Darwin
465if test "$with_ipv6" != "no"; then 465if test "$with_ipv6" != "no"; then
466 AC_CACHE_CHECK([for IPv6 support], np_cv_sys_ipv6, [ 466 AC_CACHE_CHECK([for IPv6 support], np_cv_sys_ipv6, [
467 AC_TRY_COMPILE( 467 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#ifdef HAVE_UNISTD_H
468 [#ifdef HAVE_UNISTD_H
469 #include <unistd.h> 468 #include <unistd.h>
470 #endif 469 #endif
471 #include <netinet/in.h> 470 #include <netinet/in.h>
472 #include <sys/socket.h>], 471 #include <sys/socket.h>]], [[struct sockaddr_in6 sin6;
473 [struct sockaddr_in6 sin6;
474 void *p; 472 void *p;
475 473
476 sin6.sin6_family = AF_INET6; 474 sin6.sin6_family = AF_INET6;
477 sin6.sin6_port = 587; 475 sin6.sin6_port = 587;
478 p = &sin6.sin6_addr;], 476 p = &sin6.sin6_addr;]])],[np_cv_sys_ipv6=yes],[np_cv_sys_ipv6=no])
479 [np_cv_sys_ipv6=yes],
480 [np_cv_sys_ipv6=no])
481 ]) 477 ])
482 if test "$np_cv_sys_ipv6" = "no" -a "$with_ipv6" != "check"; then 478 if test "$np_cv_sys_ipv6" = "no" -a "$with_ipv6" != "check"; then
483 AC_MSG_FAILURE([--with-ipv6 was given, but test for IPv6 support failed]) 479 AC_MSG_FAILURE([--with-ipv6 was given, but test for IPv6 support failed])
@@ -611,10 +607,10 @@ dnl
611dnl Checks for header files. 607dnl Checks for header files.
612dnl 608dnl
613 609
614AC_HEADER_TIME
615AC_HEADER_SYS_WAIT 610AC_HEADER_SYS_WAIT
616AC_CHECK_HEADERS(signal.h syslog.h uio.h errno.h sys/time.h sys/socket.h sys/un.h sys/poll.h) 611AC_CHECK_HEADERS(signal.h syslog.h uio.h errno.h sys/time.h sys/socket.h sys/un.h sys/poll.h)
617AC_CHECK_HEADERS(features.h stdarg.h sys/unistd.h ctype.h) 612AC_CHECK_HEADERS(features.h stdarg.h sys/unistd.h ctype.h)
613AC_CHECK_HEADERS_ONCE([sys/time.h])
618 614
619dnl Checks for typedefs, structures, and compiler characteristics. 615dnl Checks for typedefs, structures, and compiler characteristics.
620AC_C_CONST 616AC_C_CONST
@@ -623,36 +619,27 @@ AC_TYPE_PID_T
623AC_TYPE_SIZE_T 619AC_TYPE_SIZE_T
624 620
625AC_CACHE_CHECK([for va_copy],ac_cv_HAVE_VA_COPY,[ 621AC_CACHE_CHECK([for va_copy],ac_cv_HAVE_VA_COPY,[
626AC_TRY_LINK([#include <stdarg.h> 622AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
627va_list ap1,ap2;], [va_copy(ap1,ap2);], 623va_list ap1,ap2;]], [[va_copy(ap1,ap2);]])],[ac_cv_HAVE_VA_COPY=yes],[ac_cv_HAVE_VA_COPY=no])])
628ac_cv_HAVE_VA_COPY=yes,
629ac_cv_HAVE_VA_COPY=no)])
630if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then 624if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then
631 AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available]) 625 AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
632else 626else
633 AC_CACHE_CHECK([for __va_copy],ac_cv_HAVE___VA_COPY,[ 627 AC_CACHE_CHECK([for __va_copy],ac_cv_HAVE___VA_COPY,[
634 AC_TRY_LINK([#include <stdarg.h> 628 AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
635 va_list ap1,ap2;], [__va_copy(ap1,ap2);], 629 va_list ap1,ap2;]], [[__va_copy(ap1,ap2);]])],[ac_cv_HAVE___VA_COPY=yes],[ac_cv_HAVE___VA_COPY=no])])
636 ac_cv_HAVE___VA_COPY=yes,
637 ac_cv_HAVE___VA_COPY=no)])
638 if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then 630 if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then
639 AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available]) 631 AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
640 fi 632 fi
641fi 633fi
642 634
643AC_TRY_COMPILE([#include <sys/time.h>], 635AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>]], [[struct timeval *tv;
644 [struct timeval *tv; 636 struct timezone *tz;]])],[AC_DEFINE(HAVE_STRUCT_TIMEVAL,1,Define if we have a timeval structure)
645 struct timezone *tz;], 637 FOUND_STRUCT_TIMEVAL="yes"],[])
646 AC_DEFINE(HAVE_STRUCT_TIMEVAL,1,[Define if we have a timeval structure])
647 FOUND_STRUCT_TIMEVAL="yes")
648 638
649if test x"$FOUND_STRUCT_TIMEVAL" = x"yes"; then 639if test x"$FOUND_STRUCT_TIMEVAL" = x"yes"; then
650 AC_TRY_COMPILE([#include <sys/time.h>], 640 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>]], [[struct timeval *tv;
651 [struct timeval *tv;
652 struct timezone *tz; 641 struct timezone *tz;
653 gettimeofday(tv, tz);], 642 gettimeofday(tv, tz);]])],[AC_DEFINE(HAVE_GETTIMEOFDAY,1,Define if gettimeofday is found)],[AC_DEFINE(NEED_GETTIMEOFDAY,1,Define if gettimeofday is needed)])
654 AC_DEFINE(HAVE_GETTIMEOFDAY,1,[Define if gettimeofday is found]),
655 AC_DEFINE(NEED_GETTIMEOFDAY,1,[Define if gettimeofday is needed]))
656fi 643fi
657 644
658dnl Checks for library functions. 645dnl Checks for library functions.
@@ -660,14 +647,11 @@ AC_CHECK_FUNCS(memmove select socket strdup strstr strtol strtoul floor)
660AC_CHECK_FUNCS(poll) 647AC_CHECK_FUNCS(poll)
661 648
662AC_MSG_CHECKING(return type of socket size) 649AC_MSG_CHECKING(return type of socket size)
663AC_TRY_COMPILE([#include <stdlib.h> 650AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stdlib.h>
664 #include <sys/types.h> 651 #include <sys/types.h>
665 #include <sys/socket.h>], 652 #include <sys/socket.h>]], [[int a = send(1, (const void *) buffer, (size_t *) 0, (int *) 0);]])],[ac_cv_socket_size_type="size_t"
666 [int a = send(1, (const void *) buffer, (size_t *) 0, (int *) 0);], 653 AC_MSG_RESULT(size_t)],[ac_cv_socket_size_type="int"
667 ac_cv_socket_size_type=["size_t"] 654 AC_MSG_RESULT(int)])
668 AC_MSG_RESULT(size_t),
669 ac_cv_socket_size_type=["int"]
670 AC_MSG_RESULT(int))
671 655
672AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $ac_cv_socket_size_type , 656AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $ac_cv_socket_size_type ,
673 [Define type of socket size]) 657 [Define type of socket size])
@@ -1430,20 +1414,14 @@ if test -n "$ac_cv_nslookup_command"; then
1430fi 1414fi
1431 1415
1432AC_MSG_CHECKING([for number of online cpus]) 1416AC_MSG_CHECKING([for number of online cpus])
1433AC_TRY_COMPILE([#include <unistd.h>], 1417AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]], [[sysconf(_SC_NPROCESSORS_ONLN) > 0;]])],[AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_ONLN,1,Define if sysconf returns number of online cpus)
1434 [sysconf(_SC_NPROCESSORS_ONLN) > 0;], 1418 AC_MSG_RESULT(sysconf(_SC_NPROCESSORS_ONLN))],[AC_MSG_RESULT(cannot calculate)
1435 AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_ONLN,1,[Define if sysconf returns number of online cpus]) 1419 ])
1436 AC_MSG_RESULT([sysconf(_SC_NPROCESSORS_ONLN)]),
1437 AC_MSG_RESULT([cannot calculate])
1438 )
1439 1420
1440AC_MSG_CHECKING([for number of available cpus]) 1421AC_MSG_CHECKING([for number of available cpus])
1441AC_TRY_COMPILE([#include <unistd.h>], 1422AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]], [[sysconf(_SC_NPROCESSORS_CONF) > 0;]])],[AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_CONF,1,Define if sysconf returns number of available cpus)
1442 [sysconf(_SC_NPROCESSORS_CONF) > 0;], 1423 AC_MSG_RESULT(sysconf(_SC_NPROCESSORS_CONF))],[AC_MSG_RESULT(cannot calculate)
1443 AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_CONF,1,[Define if sysconf returns number of available cpus]) 1424 ])
1444 AC_MSG_RESULT([sysconf(_SC_NPROCESSORS_CONF)]),
1445 AC_MSG_RESULT([cannot calculate])
1446 )
1447 1425
1448AC_PATH_PROG(PATH_TO_UPTIME,uptime) 1426AC_PATH_PROG(PATH_TO_UPTIME,uptime)
1449AC_ARG_WITH(uptime_command, 1427AC_ARG_WITH(uptime_command,
@@ -1850,8 +1828,8 @@ AC_SUBST(EXTRAS_ROOT)
1850AC_SUBST(EXTRA_NETOBJS) 1828AC_SUBST(EXTRA_NETOBJS)
1851AC_SUBST(DEPLIBS) 1829AC_SUBST(DEPLIBS)
1852 1830
1853AM_GNU_GETTEXT([external], [need-ngettext]) 1831dnl AM_GNU_GETTEXT([external], [need-ngettext])
1854AM_GNU_GETTEXT_VERSION(0.15) 1832dnl AM_GNU_GETTEXT_VERSION(0.15)
1855 1833
1856dnl Check for Redhat spopen problem 1834dnl Check for Redhat spopen problem
1857dnl Weird problem where ECHILD is returned from a wait call in error 1835dnl Weird problem where ECHILD is returned from a wait call in error
@@ -1861,8 +1839,7 @@ dnl We patch plugins/popen.c
1861dnl Need to add smp because uname different on those 1839dnl Need to add smp because uname different on those
1862dnl Can force patch to be applied with --enable-redhat-pthread-workaround 1840dnl Can force patch to be applied with --enable-redhat-pthread-workaround
1863AC_ARG_ENABLE(redhat-pthread-workaround, 1841AC_ARG_ENABLE(redhat-pthread-workaround,
1864 AC_HELP_STRING([--enable-redhat-pthread-workaround], 1842 AS_HELP_STRING([--enable-redhat-pthread-workaround],[force Redhat patch to be applied (default: test system)]),
1865 [force Redhat patch to be applied (default: test system)]),
1866 [ac_cv_enable_redhat_pthread_workaround=$enableval], 1843 [ac_cv_enable_redhat_pthread_workaround=$enableval],
1867 [ac_cv_enable_redhat_pthread_workaround=test]) 1844 [ac_cv_enable_redhat_pthread_workaround=test])
1868if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then 1845if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then
@@ -1883,8 +1860,7 @@ fi
1883 1860
1884dnl Perl modules 1861dnl Perl modules
1885AC_ARG_ENABLE(perl-modules, 1862AC_ARG_ENABLE(perl-modules,
1886 AC_HELP_STRING([--enable-perl-modules], 1863 AS_HELP_STRING([--enable-perl-modules],[Enables installation of Monitoring::Plugin and its dependencies (default: no)]),
1887 [Enables installation of Monitoring::Plugin and its dependencies (default: no)]),
1888 [enable_perl_modules=$enableval], 1864 [enable_perl_modules=$enableval],
1889 [enable_perl_modules=no]) 1865 [enable_perl_modules=no])
1890if test "$enable_perl_modules" = "yes" ; then 1866if test "$enable_perl_modules" = "yes" ; then
@@ -1911,8 +1887,7 @@ if test "$ac_cv_uname_s" = 'SunOS' -a \( "x$ac_cv_prog_ac_ct_AR" = "x" -o "$ac_c
1911 AC_MSG_ERROR(No ar found for Solaris - is /usr/ccs/bin in PATH?) 1887 AC_MSG_ERROR(No ar found for Solaris - is /usr/ccs/bin in PATH?)
1912fi 1888fi
1913 1889
1914AC_OUTPUT( 1890AC_CONFIG_FILES([Makefile
1915 Makefile
1916 tap/Makefile 1891 tap/Makefile
1917 lib/Makefile 1892 lib/Makefile
1918 plugins/Makefile 1893 plugins/Makefile
@@ -1924,7 +1899,8 @@ AC_OUTPUT(
1924 perlmods/Makefile 1899 perlmods/Makefile
1925 test.pl 1900 test.pl
1926 pkg/solaris/pkginfo 1901 pkg/solaris/pkginfo
1927) 1902])
1903AC_OUTPUT
1928 1904
1929 1905
1930dnl the ones below that are commented out need to be cleaned up 1906dnl the ones below that are commented out need to be cleaned up
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 49086b7a..d43c1971 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -38,19 +38,27 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 39 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl 41 check_procs check_mysql_query check_apt check_dbi check_curl \
42 \
43 tests/test_check_swap
42 44
43SUBDIRS = picohttpparser 45SUBDIRS = picohttpparser
44 46
45EXTRA_DIST = t tests 47np_test_scripts = tests/test_check_swap.t
48
49EXTRA_DIST = t tests $(np_test_scripts) check_swap.d
46 50
47PLUGINHDRS = common.h 51PLUGINHDRS = common.h
48 52
49noinst_LIBRARIES = libnpcommon.a 53noinst_LIBRARIES = libnpcommon.a
54noinst_PROGRAMS = @EXTRA_PLUGIN_TESTS@
55# These two lines support "make check", but we use "make test"
56check_PROGRAMS = @EXTRA_PLUGIN_TESTS@
50 57
51libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ 58libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
52 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h 59 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
53 60
61
54BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO) 62BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
55NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) 63NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
56NETLIBS = $(NETOBJS) $(SOCKETLIBS) 64NETLIBS = $(NETOBJS) $(SOCKETLIBS)
@@ -58,7 +66,10 @@ SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
58 66
59TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir) 67TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
60 68
61TESTS = @PLUGIN_TEST@ 69tap_ldflags = -L$(top_srcdir)/tap
70
71TESTS = @PLUGIN_TEST@ @EXTRA_PLUGIN_TESTS@
72
62 73
63test: 74test:
64 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl 75 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
@@ -107,6 +118,7 @@ check_real_LDADD = $(NETLIBS)
107check_snmp_LDADD = $(BASEOBJS) 118check_snmp_LDADD = $(BASEOBJS)
108check_smtp_LDADD = $(SSLOBJS) 119check_smtp_LDADD = $(SSLOBJS)
109check_ssh_LDADD = $(NETLIBS) 120check_ssh_LDADD = $(NETLIBS)
121check_swap_SOURCES = check_swap.c check_swap.d/swap.c
110check_swap_LDADD = $(MATHLIBS) $(BASEOBJS) 122check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
111check_tcp_LDADD = $(SSLOBJS) 123check_tcp_LDADD = $(SSLOBJS)
112check_time_LDADD = $(NETLIBS) 124check_time_LDADD = $(NETLIBS)
@@ -122,6 +134,9 @@ if !HAVE_UTMPX
122check_users_LDADD += popen.o 134check_users_LDADD += popen.o
123endif 135endif
124 136
137tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
138tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
139
125############################################################################## 140##############################################################################
126# secondary dependencies 141# secondary dependencies
127 142
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index e7ee785d..bc90a90b 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -1,607 +1,337 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_swap plugin 3 * Monitoring check_swap plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 6 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
7* Copyright (c) 2000-2024 Monitoring Plugins Development Team 7 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_swap plugin 11 * This file contains the check_swap plugin
12* 12 *
13* 13 *
14* This program is free software: you can redistribute it and/or modify 14 * This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16 * the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17 * (at your option) any later version.
18* 18 *
19* This program is distributed in the hope that it will be useful, 19 * This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22 * GNU General Public License for more details.
23* 23 *
24* You should have received a copy of the GNU General Public License 24 * You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26 *
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29
30const char *progname = "check_swap";
31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org";
33 29
34#include "common.h" 30#include "common.h"
35#include "popen.h"
36#include "utils.h"
37
38#ifdef HAVE_DECL_SWAPCTL 31#ifdef HAVE_DECL_SWAPCTL
39# ifdef HAVE_SYS_PARAM_H 32# ifdef HAVE_SYS_PARAM_H
40# include <sys/param.h> 33# include <sys/param.h>
41# endif 34# endif
42# ifdef HAVE_SYS_SWAP_H 35# ifdef HAVE_SYS_SWAP_H
43# include <sys/swap.h> 36# include <sys/swap.h>
44# endif 37# endif
45# ifdef HAVE_SYS_STAT_H 38# ifdef HAVE_SYS_STAT_H
46# include <sys/stat.h> 39# include <sys/stat.h>
47# endif 40# endif
48#endif 41#endif
49 42
50#ifndef SWAP_CONVERSION 43#include <stdint.h>
51# define SWAP_CONVERSION 1 44#include "./check_swap.d/check_swap.h"
52#endif 45#include "./utils.h"
53 46
54typedef struct { 47typedef struct {
55 bool is_percentage; 48 int errorcode;
56 uint64_t value; 49 swap_config config;
57} threshold; 50} swap_config_wrapper;
58
59int check_swap (float free_swap_mb, float total_swap_mb);
60int process_arguments (int argc, char **argv);
61int validate_arguments (void);
62void print_usage (void);
63void print_help (void);
64
65threshold warn;
66threshold crit;
67int verbose;
68bool allswaps = false;
69int no_swap_state = STATE_CRITICAL;
70
71int
72main (int argc, char **argv)
73{
74 unsigned int percent_used, percent;
75 uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
76 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
77 uint64_t tmp_KB = 0;
78 int result = STATE_UNKNOWN;
79 char input_buffer[MAX_INPUT_BUFFER];
80#ifdef HAVE_PROC_MEMINFO
81 FILE *fp;
82#else
83 int conv_factor = SWAP_CONVERSION;
84# ifdef HAVE_SWAP
85 char *temp_buffer;
86 char *swap_command;
87 char *swap_format;
88# else
89# ifdef HAVE_DECL_SWAPCTL
90 int i=0, nswaps=0, swapctl_res=0;
91# ifdef CHECK_SWAP_SWAPCTL_SVR4
92 swaptbl_t *tbl=NULL;
93 swapent_t *ent=NULL;
94# else
95# ifdef CHECK_SWAP_SWAPCTL_BSD
96 struct swapent *ent;
97# endif /* CHECK_SWAP_SWAPCTL_BSD */
98# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
99# endif /* HAVE_DECL_SWAPCTL */
100# endif
101#endif
102 char str[32];
103 char *status;
104 51
105 setlocale (LC_ALL, ""); 52static swap_config_wrapper process_arguments(int argc, char **argv);
106 bindtextdomain (PACKAGE, LOCALEDIR); 53void print_usage(void);
107 textdomain (PACKAGE); 54static void print_help(swap_config /*config*/);
108 55
109 status = strdup (""); 56int verbose;
110 57
111 /* Parse extra opts if any */ 58#define HUNDRED_PERCENT 100
112 argv=np_extra_opts (&argc, argv, progname);
113 59
114 if (process_arguments (argc, argv) == ERROR) 60#define BYTES_TO_KiB(number) (number / 1024)
115 usage4 (_("Could not parse arguments")); 61#define BYTES_TO_MiB(number) (BYTES_TO_KiB(number) / 1024)
116 62
117#ifdef HAVE_PROC_MEMINFO 63const char *progname = "check_swap";
118 if (verbose >= 3) { 64const char *copyright = "2000-2024";
119 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO); 65const char *email = "devel@monitoring-plugins.org";
120 }
121 fp = fopen (PROC_MEMINFO, "r");
122 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
123 /*
124 * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
125 * On which kind of system this format exists, I can not say, but I wanted to
126 * document this for people who are not adapt with sscanf anymore, like me
127 */
128 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
129 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
130 dskused_mb = dskused_mb / (1024 * 1024);
131 dskfree_mb = dskfree_mb / (1024 * 1024);
132 total_swap_mb += dsktotal_mb;
133 used_swap_mb += dskused_mb;
134 free_swap_mb += dskfree_mb;
135 if (allswaps) {
136 if (dsktotal_mb == 0)
137 percent=100.0;
138 else
139 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
140 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
141 if (verbose)
142 xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
143 }
144 }
145 66
146 /* 67int main(int argc, char **argv) {
147 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123" 68 setlocale(LC_ALL, "");
148 * This format exists at least on Debian Linux with a 5.* kernel 69 bindtextdomain(PACKAGE, LOCALEDIR);
149 */ 70 textdomain(PACKAGE);
150 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
151 if (verbose >= 3) {
152 printf("Got %s with %lu\n", str, tmp_KB);
153 }
154 /* I think this part is always in Kb, so convert to mb */
155 if (strcmp ("Total", str) == 0) {
156 dsktotal_mb = tmp_KB / 1024;
157 }
158 else if (strcmp ("Free", str) == 0) {
159 dskfree_mb = dskfree_mb + tmp_KB / 1024;
160 }
161 else if (strcmp ("Cached", str) == 0) {
162 dskfree_mb = dskfree_mb + tmp_KB / 1024;
163 }
164 }
165 }
166 fclose(fp);
167 dskused_mb = dsktotal_mb - dskfree_mb;
168 total_swap_mb = dsktotal_mb;
169 used_swap_mb = dskused_mb;
170 free_swap_mb = dskfree_mb;
171#else
172# ifdef HAVE_SWAP
173 xasprintf(&swap_command, "%s", SWAP_COMMAND);
174 xasprintf(&swap_format, "%s", SWAP_FORMAT);
175
176/* These override the command used if a summary (and thus ! allswaps) is required */
177/* The summary flag returns more accurate information about swap usage on these OSes */
178# ifdef _AIX
179 if (!allswaps) {
180 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
181 xasprintf(&swap_format, "%s", "%lu%*s %lu");
182 conv_factor = 1;
183 }
184# endif
185 71
186 if (verbose >= 2) 72 char *status = strdup("");
187 printf (_("Command: %s\n"), swap_command);
188 if (verbose >= 3)
189 printf (_("Format: %s\n"), swap_format);
190 73
191 child_process = spopen (swap_command); 74 /* Parse extra opts if any */
192 if (child_process == NULL) { 75 argv = np_extra_opts(&argc, argv, progname);
193 printf (_("Could not open pipe: %s\n"), swap_command);
194 return STATE_UNKNOWN;
195 }
196 76
197 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 77 swap_config_wrapper tmp = process_arguments(argc, argv);
198 if (child_stderr == NULL)
199 printf (_("Could not open stderr for %s\n"), swap_command);
200
201 sprintf (str, "%s", "");
202 /* read 1st line */
203 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
204 if (strcmp (swap_format, "") == 0) {
205 temp_buffer = strtok (input_buffer, " \n");
206 while (temp_buffer) {
207 if (strstr (temp_buffer, "blocks"))
208 sprintf (str, "%s %s", str, "%lu");
209 else if (strstr (temp_buffer, "dskfree"))
210 sprintf (str, "%s %s", str, "%lu");
211 else
212 sprintf (str, "%s %s", str, "%*s");
213 temp_buffer = strtok (NULL, " \n");
214 }
215 }
216 78
217/* If different swap command is used for summary switch, need to read format differently */ 79 if (tmp.errorcode != OK) {
218# ifdef _AIX 80 usage4(_("Could not parse arguments"));
219 if (!allswaps) {
220 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
221 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
222 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
223 used_swap_mb = total_swap_mb - free_swap_mb;
224 if (verbose >= 3)
225 printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
226 } else {
227# endif
228 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
229 sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
230
231 dsktotal_mb = dsktotal_mb / conv_factor;
232 /* AIX lists percent used, so this converts to dskfree in MBs */
233# ifdef _AIX
234 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
235# else
236 dskfree_mb = dskfree_mb / conv_factor;
237# endif
238 if (verbose >= 3)
239 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
240
241 dskused_mb = dsktotal_mb - dskfree_mb;
242 total_swap_mb += dsktotal_mb;
243 used_swap_mb += dskused_mb;
244 free_swap_mb += dskfree_mb;
245 if (allswaps) {
246 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
247 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
248 if (verbose)
249 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
250 }
251 }
252# ifdef _AIX
253 } 81 }
254# endif
255
256 /* If we get anything on STDERR, at least set warning */
257 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
258 result = max_state (result, STATE_WARNING);
259 82
260 /* close stderr */ 83 swap_config config = tmp.config;
261 (void) fclose (child_stderr);
262 84
263 /* close the pipe */ 85 swap_result data = get_swap_data(config);
264 if (spclose (child_process))
265 result = max_state (result, STATE_WARNING);
266# else
267# ifdef CHECK_SWAP_SWAPCTL_SVR4
268 86
269 /* get the number of active swap devices */ 87 if (data.errorcode != STATE_OK) {
270 if((nswaps=swapctl(SC_GETNSWP, NULL))== -1) 88 puts("SWAP UNKNOWN - Failed to retrieve Swap usage");
271 die(STATE_UNKNOWN, _("Error getting swap devices\n") ); 89 exit(STATE_UNKNOWN);
272
273 if(nswaps == 0)
274 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
275
276 if(verbose >= 3)
277 printf("Found %d swap device(s)\n", nswaps);
278
279 /* initialize swap table + entries */
280 tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
281
282 if(tbl==NULL)
283 die(STATE_UNKNOWN, _("malloc() failed!\n"));
284
285 memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
286 tbl->swt_n=nswaps;
287 for(i=0;i<nswaps;i++){
288 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
289 die(STATE_UNKNOWN, _("malloc() failed!\n"));
290 } 90 }
291 91
292 /* and now, tally 'em up */ 92 double percent_used;
293 swapctl_res=swapctl(SC_LIST, tbl); 93 /* if total_swap_mb == 0, let's not divide by 0 */
294 if(swapctl_res < 0){ 94 if (data.metrics.total != 0) {
295 perror(_("swapctl failed: ")); 95 percent_used = HUNDRED_PERCENT * ((double)data.metrics.used) / ((double)data.metrics.total);
296 die(STATE_UNKNOWN, _("Error in swapctl call\n")); 96 } else {
97 printf(_("SWAP %s - Swap is either disabled, not present, or of zero "
98 "size."),
99 state_text(data.statusCode));
100 exit(config.no_swap_state);
297 } 101 }
298 102
299 for(i=0;i<nswaps;i++){ 103 if (verbose) {
300 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION; 104 printf("Computed usage percentage: %g\n", percent_used);
301 dskfree_mb = (float) tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
302 dskused_mb = ( dsktotal_mb - dskfree_mb );
303
304 if (verbose >= 3)
305 printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
306
307 if(allswaps && dsktotal_mb > 0){
308 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
309 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
310 if (verbose) {
311 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
312 }
313 }
314
315 total_swap_mb += dsktotal_mb;
316 free_swap_mb += dskfree_mb;
317 used_swap_mb += dskused_mb;
318 } 105 }
319 106
320 /* and clean up after ourselves */ 107 uint64_t warn_print = config.warn.value;
321 for(i=0;i<nswaps;i++){ 108 if (config.warn.is_percentage) {
322 free(tbl->swt_ent[i].ste_path); 109 warn_print = config.warn.value * (data.metrics.total / HUNDRED_PERCENT);
323 } 110 }
324 free(tbl);
325# else
326# ifdef CHECK_SWAP_SWAPCTL_BSD
327
328 /* get the number of active swap devices */
329 nswaps=swapctl(SWAP_NSWAP, NULL, 0);
330
331 /* initialize swap table + entries */
332 ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
333 111
334 /* and now, tally 'em up */ 112 uint64_t crit_print = config.crit.value;
335 swapctl_res=swapctl(SWAP_STATS, ent, nswaps); 113 if (config.crit.is_percentage) {
336 if(swapctl_res < 0){ 114 crit_print = config.crit.value * (data.metrics.total / HUNDRED_PERCENT);
337 perror(_("swapctl failed: "));
338 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
339 } 115 }
340 116
341 for(i=0;i<nswaps;i++){ 117 char *perfdata = perfdata_uint64("swap", data.metrics.free, "B", config.warn_is_set, warn_print, config.crit_is_set, crit_print, true,
342 dsktotal_mb = (float) ent[i].se_nblks / conv_factor; 118 0, true, data.metrics.total);
343 dskused_mb = (float) ent[i].se_inuse / conv_factor;
344 dskfree_mb = ( dsktotal_mb - dskused_mb );
345 119
346 if(allswaps && dsktotal_mb > 0){ 120 if (config.warn_is_set) {
347 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb)); 121 if (verbose > 1) {
348 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb)); 122 printf("Warn threshold value: %" PRIu64 "\n", config.warn.value);
349 if (verbose) {
350 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
351 }
352 } 123 }
353 124
354 total_swap_mb += dsktotal_mb; 125 if ((config.warn.is_percentage && (percent_used >= (double)(HUNDRED_PERCENT - config.warn.value))) ||
355 free_swap_mb += dskfree_mb; 126 config.warn.value >= data.metrics.free) {
356 used_swap_mb += dskused_mb; 127 data.statusCode = max_state(data.statusCode, STATE_WARNING);
128 }
357 } 129 }
358 130
359 /* and clean up after ourselves */ 131 if (config.crit_is_set) {
360 free(ent); 132 if (verbose > 1) {
361 133 printf("Crit threshold value: %" PRIu64 "\n", config.crit.value);
362# endif /* CHECK_SWAP_SWAPCTL_BSD */ 134 }
363# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
364# endif /* HAVE_SWAP */
365#endif /* HAVE_PROC_MEMINFO */
366 135
367 /* if total_swap_mb == 0, let's not divide by 0 */ 136 if ((config.crit.is_percentage && (percent_used >= (double)(HUNDRED_PERCENT - config.crit.value))) ||
368 if(total_swap_mb) { 137 config.crit.value >= data.metrics.free) {
369 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb); 138 data.statusCode = max_state(data.statusCode, STATE_CRITICAL);
370 } else { 139 }
371 percent_used = 100;
372 status = "- Swap is either disabled, not present, or of zero size. ";
373 } 140 }
374 141
375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb)); 142 printf(_("SWAP %s - %g%% free (%lluMiB out of %lluMiB) %s|%s\n"), state_text(data.statusCode), (HUNDRED_PERCENT - percent_used),
376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"), 143 BYTES_TO_MiB(data.metrics.free), BYTES_TO_MiB(data.metrics.total), status, perfdata);
377 state_text (result),
378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
379
380 uint64_t warn_print = warn.value;
381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100);
382 uint64_t crit_print = crit.value;
383 if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
384 144
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B", 145 exit(data.statusCode);
386 true, warn_print,
387 true, crit_print,
388 true, 0,
389 true, (long) total_swap_mb * 1024 * 1024));
390
391 return result;
392} 146}
393 147
148int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
149 if (total_swap_mb == 0) {
150 return config.no_swap_state;
151 }
394 152
395int 153 uint64_t free_swap = (uint64_t)(free_swap_mb * (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */
396check_swap(float free_swap_mb, float total_swap_mb)
397{
398
399 if (!total_swap_mb) return no_swap_state;
400 154
401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */ 155 if (!config.crit.is_percentage && config.crit.value >= free_swap) {
402 uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100; 156 return STATE_CRITICAL;
157 }
158 if (!config.warn.is_percentage && config.warn.value >= free_swap) {
159 return STATE_WARNING;
160 }
403 161
404 if (warn.value || crit.value) { /* Thresholds defined */ 162 uint64_t usage_percentage = (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT;
405 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
406 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
407 163
408 if (crit.is_percentage && 164 if (config.crit.is_percentage && config.crit.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) {
409 crit.value != 0 && 165 return STATE_CRITICAL;
410 usage_percentage >= (100 - crit.value)) 166 }
411 {
412 return STATE_CRITICAL;
413 }
414 167
415 if (warn.is_percentage && 168 if (config.warn.is_percentage && config.warn.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) {
416 warn.value != 0 && 169 return STATE_WARNING;
417 usage_percentage >= (100 - warn.value)) 170 }
418 {
419 return STATE_WARNING;
420 }
421 171
422 return STATE_OK; 172 return STATE_OK;
423 } else { /* Without thresholds */
424 return STATE_OK;
425 }
426} 173}
427 174
175/* process command-line arguments */
176swap_config_wrapper process_arguments(int argc, char **argv) {
177 swap_config_wrapper conf_wrapper = {.errorcode = OK};
178 conf_wrapper.config = swap_config_init();
428 179
180 static struct option longopts[] = {{"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'},
181 {"allswaps", no_argument, 0, 'a'}, {"no-swap", required_argument, 0, 'n'},
182 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
183 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
429 184
430/* process command-line arguments */ 185 while (true) {
431int 186 int option = 0;
432process_arguments (int argc, char **argv) 187 int option_char = getopt_long(argc, argv, "+?Vvhac:w:n:", longopts, &option);
433{ 188
434 int c = 0; /* option character */ 189 if (option_char == -1 || option_char == EOF) {
435
436 int option = 0;
437 static struct option longopts[] = {
438 {"warning", required_argument, 0, 'w'},
439 {"critical", required_argument, 0, 'c'},
440 {"allswaps", no_argument, 0, 'a'},
441 {"no-swap", required_argument, 0, 'n'},
442 {"verbose", no_argument, 0, 'v'},
443 {"version", no_argument, 0, 'V'},
444 {"help", no_argument, 0, 'h'},
445 {0, 0, 0, 0}
446 };
447
448 while (1) {
449 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option);
450
451 if (c == -1 || c == EOF)
452 break; 190 break;
191 }
453 192
454 switch (c) { 193 switch (option_char) {
455 case 'w': /* warning size threshold */ 194 case 'w': /* warning size threshold */
456 { 195 {
457 /* 196 /*
458 * We expect either a positive integer value without a unit, which means 197 * We expect either a positive integer value without a unit, which
459 * the unit is Bytes or a positive integer value and a percentage sign (%), 198 * means the unit is Bytes or a positive integer value and a
460 * which means the value must be with 0 and 100 and is relative to the total swap 199 * percentage sign (%), which means the value must be with 0 and 100
461 */ 200 * and is relative to the total swap
462 size_t length; 201 */
463 length = strlen(optarg); 202 size_t length;
464 203 length = strlen(optarg);
465 if (optarg[length - 1] == '%') { 204 conf_wrapper.config.warn_is_set = true;
466 /* It's percentage */ 205
467 warn.is_percentage = true; 206 if (optarg[length - 1] == '%') {
468 optarg[length - 1] = '\0'; 207 /* It's percentage */
469 if (is_uint64(optarg, &warn.value)) { 208 conf_wrapper.config.warn.is_percentage = true;
470 if (warn.value > 100) { 209 optarg[length - 1] = '\0';
471 usage4 (_("Warning threshold percentage must be <= 100!")); 210 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
472 } 211 if (conf_wrapper.config.warn.value > HUNDRED_PERCENT) {
473 } 212 usage4(_("Warning threshold percentage must be <= 100!"));
474 break;
475 } else {
476 /* It's Bytes */
477 warn.is_percentage = false;
478 if (is_uint64(optarg, &warn.value)) {
479 break;
480 } else {
481 usage4 (_("Warning threshold be positive integer or percentage!"));
482 } 213 }
483 } 214 }
215 break;
216 } /* It's Bytes */
217 conf_wrapper.config.warn.is_percentage = false;
218 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
219 break;
484 } 220 }
221 usage4(_("Warning threshold be positive integer or "
222 "percentage!"));
223 }
485 case 'c': /* critical size threshold */ 224 case 'c': /* critical size threshold */
486 { 225 {
487 /* 226 /*
488 * We expect either a positive integer value without a unit, which means 227 * We expect either a positive integer value without a unit, which
489 * the unit is Bytes or a positive integer value and a percentage sign (%), 228 * means the unit is Bytes or a positive integer value and a
490 * which means the value must be with 0 and 100 and is relative to the total swap 229 * percentage sign (%), which means the value must be with 0 and 100
491 */ 230 * and is relative to the total swap
492 size_t length; 231 */
493 length = strlen(optarg); 232 size_t length;
494 233 length = strlen(optarg);
495 if (optarg[length - 1] == '%') { 234 conf_wrapper.config.crit_is_set = true;
496 /* It's percentage */ 235
497 crit.is_percentage = true; 236 if (optarg[length - 1] == '%') {
498 optarg[length - 1] = '\0'; 237 /* It's percentage */
499 if (is_uint64(optarg, &crit.value)) { 238 conf_wrapper.config.crit.is_percentage = true;
500 if (crit.value> 100) { 239 optarg[length - 1] = '\0';
501 usage4 (_("Critical threshold percentage must be <= 100!")); 240 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
502 } 241 if (conf_wrapper.config.crit.value > HUNDRED_PERCENT) {
503 } 242 usage4(_("Critical threshold percentage must be <= 100!"));
504 break;
505 } else {
506 /* It's Bytes */
507 crit.is_percentage = false;
508 if (is_uint64(optarg, &crit.value)) {
509 break;
510 } else {
511 usage4 (_("Critical threshold be positive integer or percentage!"));
512 } 243 }
513 } 244 }
514 } 245 break;
515 case 'a': /* all swap */ 246 } /* It's Bytes */
516 allswaps = true; 247 conf_wrapper.config.crit.is_percentage = false;
248 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
249 break;
250 }
251 usage4(_("Critical threshold be positive integer or "
252 "percentage!"));
253 }
254 case 'a': /* all swap */
255 conf_wrapper.config.allswaps = true;
517 break; 256 break;
518 case 'n': 257 case 'n':
519 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) { 258 if ((conf_wrapper.config.no_swap_state = mp_translate_state(optarg)) == ERROR) {
520 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 259 usage4(_("no-swap result must be a valid state name (OK, "
260 "WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
521 } 261 }
522 break; 262 break;
523 case 'v': /* verbose */ 263 case 'v': /* verbose */
524 verbose++; 264 verbose++;
525 break; 265 break;
526 case 'V': /* version */ 266 case 'V': /* version */
527 print_revision (progname, NP_VERSION); 267 print_revision(progname, NP_VERSION);
528 exit (STATE_UNKNOWN); 268 exit(STATE_UNKNOWN);
529 case 'h': /* help */ 269 case 'h': /* help */
530 print_help (); 270 print_help(conf_wrapper.config);
531 exit (STATE_UNKNOWN); 271 exit(STATE_UNKNOWN);
532 case '?': /* error */ 272 case '?': /* error */
533 usage5 (); 273 usage5();
534 } 274 }
535 } 275 }
536 276
537 c = optind; 277 if ((conf_wrapper.config.warn.is_percentage == conf_wrapper.config.crit.is_percentage) &&
538 if (c == argc) 278 (conf_wrapper.config.warn.value < conf_wrapper.config.crit.value)) {
539 return validate_arguments (); 279 /* This is NOT triggered if warn and crit are different units, e.g warn
540 280 * is percentage and crit is absolute. We cannot determine the condition
541 return validate_arguments (); 281 * at this point since we dont know the value of total swap yet
542}
543
544
545
546int
547validate_arguments (void)
548{
549 if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
550 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
551 * and crit is absolute. We cannot determine the condition at this point since we
552 * dont know the value of total swap yet
553 */ 282 */
554 usage4(_("Warning should be more than critical")); 283 usage4(_("Warning should be more than critical"));
555 } 284 }
556 return OK;
557}
558 285
559 286 return conf_wrapper;
560
561void
562print_help (void)
563{
564 print_revision (progname, NP_VERSION);
565
566 printf (_(COPYRIGHT), copyright, email);
567
568 printf ("%s\n", _("Check swap space on local machine."));
569
570 printf ("\n\n");
571
572 print_usage ();
573
574 printf (UT_HELP_VRSN);
575 printf (UT_EXTRA_OPTS);
576
577 printf (" %s\n", "-w, --warning=INTEGER");
578 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
579 printf (" %s\n", "-w, --warning=PERCENT%");
580 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
581 printf (" %s\n", "-c, --critical=INTEGER");
582 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
583 printf (" %s\n", "-c, --critical=PERCENT%");
584 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
585 printf (" %s\n", "-a, --allswaps");
586 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
587 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
588 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
589 printf (UT_VERBOSE);
590
591 printf ("\n");
592 printf ("%s\n", _("Notes:"));
593 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
594 printf (" %s\n", _("Without thresholds, the plugin shows free swap space and performance data, but always returns OK."));
595 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
596
597 printf (UT_SUPPORT);
598} 287}
599 288
289void print_help(swap_config config) {
290 print_revision(progname, NP_VERSION);
291
292 printf(_(COPYRIGHT), copyright, email);
293
294 printf("%s\n", _("Check swap space on local machine."));
295
296 printf("\n\n");
297
298 print_usage();
299
300 printf(UT_HELP_VRSN);
301 printf(UT_EXTRA_OPTS);
302
303 printf(" %s\n", "-w, --warning=INTEGER");
304 printf(" %s\n", _("Exit with WARNING status if less than INTEGER bytes "
305 "of swap space are free"));
306 printf(" %s\n", "-w, --warning=PERCENT%");
307 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of "
308 "swap space is free"));
309 printf(" %s\n", "-c, --critical=INTEGER");
310 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes "
311 "of swap space are free"));
312 printf(" %s\n", "-c, --critical=PERCENT%");
313 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of "
314 "swap space is free"));
315 printf(" %s\n", "-a, --allswaps");
316 printf(" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
317 printf(" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
318 printf(" %s %s\n",
319 _("Resulting state when there is no swap regardless of thresholds. "
320 "Default:"),
321 state_text(config.no_swap_state));
322 printf(UT_VERBOSE);
323
324 printf("\n");
325 printf("%s\n", _("Notes:"));
326 printf(" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, "
327 "they are all checked."));
328 printf(" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
329
330 printf(UT_SUPPORT);
331}
600 332
601void 333void print_usage(void) {
602print_usage (void) 334 printf("%s\n", _("Usage:"));
603{ 335 printf(" %s [-av] -w <percent_free>%% -c <percent_free>%%\n", progname);
604 printf ("%s\n", _("Usage:")); 336 printf(" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
605 printf (" %s [-av] [-w <percent_free>%%] [-c <percent_free>%%]\n",progname);
606 printf (" [-w <bytes_free>] [-c <bytes_free>] [-n <state>]\n");
607} 337}
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
new file mode 100644
index 00000000..99039b21
--- /dev/null
+++ b/plugins/check_swap.d/check_swap.h
@@ -0,0 +1,43 @@
1#pragma once
2
3#include "../common.h"
4
5#ifndef SWAP_CONVERSION
6# define SWAP_CONVERSION 1
7#endif
8
9typedef struct {
10 bool is_percentage;
11 uint64_t value;
12} check_swap_threshold;
13
14typedef struct {
15 unsigned long long free; // Free swap in Bytes!
16 unsigned long long used; // Used swap in Bytes!
17 unsigned long long total; // Total swap size, you guessed it, in Bytes!
18} swap_metrics;
19
20typedef struct {
21 int errorcode;
22 int statusCode;
23 swap_metrics metrics;
24} swap_result;
25
26typedef struct {
27 bool allswaps;
28 int no_swap_state;
29 bool warn_is_set;
30 check_swap_threshold warn;
31 bool crit_is_set;
32 check_swap_threshold crit;
33 bool on_aix;
34 int conversion_factor;
35} swap_config;
36
37swap_config swap_config_init(void);
38
39swap_result get_swap_data(swap_config config);
40swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]);
41swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]);
42swap_result getSwapFromSwapctl_BSD(swap_config config);
43swap_result getSwapFromSwap_SRV4(swap_config config);
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
new file mode 100644
index 00000000..2fe4544f
--- /dev/null
+++ b/plugins/check_swap.d/swap.c
@@ -0,0 +1,469 @@
1#include "./check_swap.d/check_swap.h"
2#include "../popen.h"
3#include "../utils.h"
4#include "common.h"
5
6extern int verbose;
7
8swap_config swap_config_init(void) {
9 swap_config tmp = {0};
10 tmp.allswaps = false;
11 tmp.no_swap_state = STATE_CRITICAL;
12 tmp.conversion_factor = SWAP_CONVERSION;
13
14 tmp.warn_is_set = false;
15 tmp.crit_is_set = false;
16
17#ifdef _AIX
18 tmp.on_aix = true;
19#else
20 tmp.on_aix = false;
21#endif
22
23 return tmp;
24}
25
26swap_result get_swap_data(swap_config config) {
27#ifdef HAVE_PROC_MEMINFO
28 if (verbose >= 3) {
29 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
30 }
31
32 return getSwapFromProcMeminfo(PROC_MEMINFO);
33#else // HAVE_PROC_MEMINFO
34# ifdef HAVE_SWAP
35 if (verbose >= 3) {
36 printf("Using swap command %s with format: %s\n", SWAP_COMMAND, SWAP_FORMAT);
37 }
38
39 /* These override the command used if a summary (and thus ! allswaps) is
40 * required
41 * The summary flag returns more accurate information about swap usage on these
42 * OSes */
43 if (config.on_aix && !config.allswaps) {
44
45 config.conversion_factor = 1;
46
47 return getSwapFromSwapCommand(config, "/usr/sbin/lsps -s", "%lu%*s %lu");
48 } else {
49 return getSwapFromSwapCommand(config, SWAP_COMMAND, SWAP_FORMAT);
50 }
51# else // HAVE_SWAP
52# ifdef CHECK_SWAP_SWAPCTL_SVR4
53 return getSwapFromSwapctl_SRV4();
54# else // CHECK_SWAP_SWAPCTL_SVR4
55# ifdef CHECK_SWAP_SWAPCTL_BSD
56 return getSwapFromSwapctl_BSD();
57# else // CHECK_SWAP_SWAPCTL_BSD
58# error No way found to retrieve swap
59# endif /* CHECK_SWAP_SWAPCTL_BSD */
60# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
61# endif /* HAVE_SWAP */
62#endif /* HAVE_PROC_MEMINFO */
63}
64
65swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
66 FILE *meminfo_file_ptr;
67 meminfo_file_ptr = fopen(proc_meminfo, "r");
68
69 swap_result result = {0};
70 result.errorcode = STATE_UNKNOWN;
71
72 if (meminfo_file_ptr == NULL) {
73 // failed to open meminfo file
74 // errno should contain an error
75 result.errorcode = STATE_UNKNOWN;
76 return result;
77 }
78
79 uint64_t swap_total = 0;
80 uint64_t swap_used = 0;
81 uint64_t swap_free = 0;
82
83 bool found_total = false;
84 bool found_used = false;
85 bool found_free = false;
86
87 char input_buffer[MAX_INPUT_BUFFER];
88 char str[32];
89
90 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
91 uint64_t tmp_KB = 0;
92
93 /*
94 * The following sscanf call looks for a line looking like: "Swap: 123
95 * 123 123" On which kind of system this format exists, I can not say,
96 * but I wanted to document this for people who are not adapt with
97 * sscanf anymore, like me
98 * Also the units used here are unclear and probably wrong
99 */
100 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) {
101
102 result.metrics.total += swap_total;
103 result.metrics.used += swap_used;
104 result.metrics.free += swap_free;
105
106 found_total = true;
107 found_free = true;
108 found_used = true;
109
110 // Set error
111 result.errorcode = STATE_OK;
112
113 /*
114 * The following sscanf call looks for lines looking like:
115 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
116 * on Debian Linux with a 5.* kernel
117 */
118 } else {
119 int sscanf_result = sscanf(input_buffer,
120 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
121 "%*[k]%*[B]",
122 str, &tmp_KB);
123
124 if (sscanf_result == 2) {
125
126 if (verbose >= 3) {
127 printf("Got %s with %lu\n", str, tmp_KB);
128 }
129
130 /* I think this part is always in Kb, so convert to bytes */
131 if (strcmp("Total", str) == 0) {
132 swap_total = tmp_KB * 1000;
133 found_total = true;
134 } else if (strcmp("Free", str) == 0) {
135 swap_free = swap_free + tmp_KB * 1000;
136 found_free = true;
137 found_used = true; // No explicit used metric available
138 } else if (strcmp("Cached", str) == 0) {
139 swap_free = swap_free + tmp_KB * 1000;
140 found_free = true;
141 found_used = true; // No explicit used metric available
142 }
143
144 result.errorcode = STATE_OK;
145 }
146 }
147 }
148
149 fclose(meminfo_file_ptr);
150
151 result.metrics.total = swap_total;
152 result.metrics.used = swap_total - swap_free;
153 result.metrics.free = swap_free;
154
155 if (!found_free || !found_total || !found_used) {
156 result.errorcode = STATE_UNKNOWN;
157 }
158
159 return result;
160}
161
162swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]) {
163 swap_result result = {0};
164
165 char *temp_buffer;
166
167 if (verbose >= 2) {
168 printf(_("Command: %s\n"), swap_command);
169 }
170 if (verbose >= 3) {
171 printf(_("Format: %s\n"), swap_format);
172 }
173
174 child_process = spopen(swap_command);
175 if (child_process == NULL) {
176 printf(_("Could not open pipe: %s\n"), swap_command);
177 swap_result tmp = {
178 .errorcode = STATE_UNKNOWN,
179 };
180 return tmp;
181 }
182
183 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
184 if (child_stderr == NULL) {
185 printf(_("Could not open stderr for %s\n"), swap_command);
186 }
187
188 char str[32] = {0};
189 char input_buffer[MAX_INPUT_BUFFER];
190
191 /* read 1st line */
192 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);
193 if (strcmp(swap_format, "") == 0) {
194 temp_buffer = strtok(input_buffer, " \n");
195 while (temp_buffer) {
196 if (strstr(temp_buffer, "blocks")) {
197 sprintf(str, "%s %s", str, "%lu");
198 } else if (strstr(temp_buffer, "dskfree")) {
199 sprintf(str, "%s %s", str, "%lu");
200 } else {
201 sprintf(str, "%s %s", str, "%*s");
202 }
203 temp_buffer = strtok(NULL, " \n");
204 }
205 }
206
207 double total_swap_mb = 0;
208 double free_swap_mb = 0;
209 double used_swap_mb = 0;
210 double dsktotal_mb = 0;
211 double dskused_mb = 0;
212 double dskfree_mb = 0;
213
214 /*
215 * If different swap command is used for summary switch, need to read format
216 * differently
217 */
218 if (config.on_aix && !config.allswaps) {
219 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
220 sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
221 free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100;
222 used_swap_mb = total_swap_mb - free_swap_mb;
223
224 if (verbose >= 3) {
225 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
226 }
227 } else {
228 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
229 sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
230
231 dsktotal_mb = dsktotal_mb / config.conversion_factor;
232 /* AIX lists percent used, so this converts to dskfree in MBs */
233
234 if (config.on_aix) {
235 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
236 } else {
237 dskfree_mb = dskfree_mb / config.conversion_factor;
238 }
239
240 if (verbose >= 3) {
241 printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
242 }
243
244 dskused_mb = dsktotal_mb - dskfree_mb;
245 total_swap_mb += dsktotal_mb;
246 used_swap_mb += dskused_mb;
247 free_swap_mb += dskfree_mb;
248 }
249 }
250
251 result.metrics.free = free_swap_mb * 1024 * 1024;
252 result.metrics.used = used_swap_mb * 1024 * 1024;
253 result.metrics.total = free_swap_mb * 1024 * 1024;
254
255 /* If we get anything on STDERR, at least set warning */
256 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
257 result.statusCode = max_state(result.statusCode, STATE_WARNING);
258 // TODO Set error here
259 }
260
261 /* close stderr */
262 (void)fclose(child_stderr);
263
264 /* close the pipe */
265 if (spclose(child_process)) {
266 result.statusCode = max_state(result.statusCode, STATE_WARNING);
267 // TODO set error here
268 }
269
270 return result;
271}
272
273#ifndef CHECK_SWAP_SWAPCTL_BSD
274# define CHECK_SWAP_SWAPCTL_BSD
275
276// Stub functionality for BSD stuff, so the compiler always sees the following BSD code
277
278# define SWAP_NSWAP 0
279# define SWAP_STATS 1
280
281int bsd_swapctl(int cmd, const void *arg, int misc) {
282 (void)cmd;
283 (void)arg;
284 (void)misc;
285 return 512;
286}
287
288struct swapent {
289 dev_t se_dev; /* device id */
290 int se_flags; /* entry flags */
291 int se_nblks; /* total blocks */
292 int se_inuse; /* blocks in use */
293 int se_priority; /* priority */
294 char se_path[PATH_MAX]; /* path to entry */
295};
296
297#else
298# define bsd_swapctl swapctl
299#endif
300
301swap_result getSwapFromSwapctl_BSD(swap_config config) {
302 /* get the number of active swap devices */
303 int nswaps = bsd_swapctl(SWAP_NSWAP, NULL, 0);
304
305 /* initialize swap table + entries */
306 struct swapent *ent = (struct swapent *)malloc(sizeof(struct swapent) * (unsigned long)nswaps);
307
308 /* and now, tally 'em up */
309 int swapctl_res = bsd_swapctl(SWAP_STATS, ent, nswaps);
310 if (swapctl_res < 0) {
311 perror(_("swapctl failed: "));
312 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
313 }
314
315 double dsktotal_mb = 0.0;
316 double dskfree_mb = 0.0;
317 double dskused_mb = 0.0;
318 unsigned long long total_swap_mb = 0;
319 unsigned long long free_swap_mb = 0;
320 unsigned long long used_swap_mb = 0;
321
322 for (int i = 0; i < nswaps; i++) {
323 dsktotal_mb = (float)ent[i].se_nblks / (float)config.conversion_factor;
324 dskused_mb = (float)ent[i].se_inuse / (float)config.conversion_factor;
325 dskfree_mb = (dsktotal_mb - dskused_mb);
326
327 if (config.allswaps && dsktotal_mb > 0) {
328 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
329
330 if (verbose) {
331 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
332 }
333 }
334
335 total_swap_mb += (unsigned long long)dsktotal_mb;
336 free_swap_mb += (unsigned long long)dskfree_mb;
337 used_swap_mb += (unsigned long long)dskused_mb;
338 }
339
340 /* and clean up after ourselves */
341 free(ent);
342
343 swap_result result = {0};
344
345 result.statusCode = OK;
346 result.errorcode = OK;
347
348 result.metrics.total = total_swap_mb * 1024 * 1024;
349 result.metrics.free = free_swap_mb * 1024 * 1024;
350 result.metrics.used = used_swap_mb * 1024 * 1024;
351
352 return result;
353}
354
355#ifndef CHECK_SWAP_SWAPCTL_SVR4
356int srv4_swapctl(int cmd, void *arg) {
357 (void)cmd;
358 (void)arg;
359 return 512;
360}
361
362typedef struct srv4_swapent {
363 char *ste_path; /* name of the swap file */
364 off_t ste_start; /* starting block for swapping */
365 off_t ste_length; /* length of swap area */
366 long ste_pages; /* number of pages for swapping */
367 long ste_free; /* number of ste_pages free */
368 long ste_flags; /* ST_INDEL bit set if swap file */
369 /* is now being deleted */
370} swapent_t;
371
372typedef struct swaptbl {
373 int swt_n; /* number of swapents following */
374 struct srv4_swapent swt_ent[]; /* array of swt_n swapents */
375} swaptbl_t;
376
377# define SC_LIST 2
378# define SC_GETNSWP 3
379
380# ifndef MAXPATHLEN
381# define MAXPATHLEN 2048
382# endif
383
384#else
385# define srv4_swapctl swapctl
386#endif
387
388swap_result getSwapFromSwap_SRV4(swap_config config) {
389 int nswaps = 0;
390
391 /* get the number of active swap devices */
392 if ((nswaps = srv4_swapctl(SC_GETNSWP, NULL)) == -1) {
393 die(STATE_UNKNOWN, _("Error getting swap devices\n"));
394 }
395
396 if (nswaps == 0) {
397 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
398 }
399
400 if (verbose >= 3) {
401 printf("Found %d swap device(s)\n", nswaps);
402 }
403
404 /* initialize swap table + entries */
405 swaptbl_t *tbl = (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
406
407 if (tbl == NULL) {
408 die(STATE_UNKNOWN, _("malloc() failed!\n"));
409 }
410
411 memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
412 tbl->swt_n = nswaps;
413
414 for (int i = 0; i < nswaps; i++) {
415 if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) {
416 die(STATE_UNKNOWN, _("malloc() failed!\n"));
417 }
418 }
419
420 /* and now, tally 'em up */
421 int swapctl_res = srv4_swapctl(SC_LIST, tbl);
422 if (swapctl_res < 0) {
423 perror(_("swapctl failed: "));
424 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
425 }
426
427 double dsktotal_mb = 0.0;
428 double dskfree_mb = 0.0;
429 double dskused_mb = 0.0;
430 unsigned long long total_swap_mb = 0;
431 unsigned long long free_swap_mb = 0;
432 unsigned long long used_swap_mb = 0;
433
434 for (int i = 0; i < nswaps; i++) {
435 dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
436 dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
437 dskused_mb = (dsktotal_mb - dskfree_mb);
438
439 if (verbose >= 3) {
440 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
441 }
442
443 if (config.allswaps && dsktotal_mb > 0) {
444 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
445
446 if (verbose) {
447 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
448 }
449 }
450
451 total_swap_mb += (unsigned long long)dsktotal_mb;
452 free_swap_mb += (unsigned long long)dskfree_mb;
453 used_swap_mb += (unsigned long long)dskused_mb;
454 }
455
456 /* and clean up after ourselves */
457 for (int i = 0; i < nswaps; i++) {
458 free(tbl->swt_ent[i].ste_path);
459 }
460 free(tbl);
461
462 swap_result result = {0};
463 result.errorcode = OK;
464 result.metrics.total = total_swap_mb * 1024 * 1024;
465 result.metrics.free = free_swap_mb * 1024 * 1024;
466 result.metrics.used = used_swap_mb * 1024 * 1024;
467
468 return result;
469}
diff --git a/plugins/common.h b/plugins/common.h
index 833479ce..b7a7d59b 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -90,16 +90,10 @@
90# define GET_NUMBER_OF_CPUS() -1 90# define GET_NUMBER_OF_CPUS() -1
91#endif 91#endif
92 92
93#ifdef TIME_WITH_SYS_TIME 93#ifdef HAVE_SYS_TIME_H
94# include <sys/time.h> 94# include <sys/time.h>
95# include <time.h>
96#else
97# ifdef HAVE_SYS_TIME_H
98# include <sys/time.h>
99# else
100# include <time.h>
101# endif
102#endif 95#endif
96#include <time.h>
103 97
104#ifdef HAVE_SYS_TYPES_H 98#ifdef HAVE_SYS_TYPES_H
105#include <sys/types.h> 99#include <sys/types.h>
diff --git a/plugins/t/check_swap.t b/plugins/t/check_swap.t
index 18780386..eaa81083 100644
--- a/plugins/t/check_swap.t
+++ b/plugins/t/check_swap.t
@@ -8,9 +8,9 @@ use strict;
8use Test::More tests => 14; 8use Test::More tests => 14;
9use NPTest; 9use NPTest;
10 10
11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/'; 11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/'; 12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/'; 13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
14 14
15my $result; 15my $result;
16 16
diff --git a/plugins/tests/test_check_swap.c b/plugins/tests/test_check_swap.c
new file mode 100644
index 00000000..b85fb4ad
--- /dev/null
+++ b/plugins/tests/test_check_swap.c
@@ -0,0 +1,23 @@
1
2#include "../check_swap.d/check_swap.h"
3#include "../../tap/tap.h"
4
5int verbose = 0;
6
7void print_usage(void) {}
8void print_help(swap_config config) {
9 (void) config;
10}
11
12const char *progname = "test_check_swap";
13
14int main(void) {
15 swap_result test_data = getSwapFromProcMeminfo("./var/proc_meminfo");
16
17 plan_tests(4);
18
19 ok(test_data.errorcode == 0, "Test whether we manage to retrieve swap data");
20 ok(test_data.metrics.total == 34233905152, "Is the total Swap correct");
21 ok(test_data.metrics.free == 34233905152, "Is the free Swap correct");
22 ok(test_data.metrics.used == 0, "Is the used Swap correct");
23}
diff --git a/plugins/tests/test_check_swap.t b/plugins/tests/test_check_swap.t
new file mode 100755
index 00000000..826fae01
--- /dev/null
+++ b/plugins/tests/test_check_swap.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_swap") {
4 plan skip_all => "./test_check_swap not compiled - please enable libtap library to test";
5}
6exec "./test_check_swap";
diff --git a/plugins/tests/var/proc_meminfo b/plugins/tests/var/proc_meminfo
new file mode 100644
index 00000000..6c5a618d
--- /dev/null
+++ b/plugins/tests/var/proc_meminfo
@@ -0,0 +1,55 @@
1MemTotal: 32767776 kB
2MemFree: 1693508 kB
3MemAvailable: 23807480 kB
4Buffers: 438456 kB
5Cached: 19124976 kB
6SwapCached: 0 kB
7Active: 7860680 kB
8Inactive: 18886776 kB
9Active(anon): 6108756 kB
10Inactive(anon): 1364500 kB
11Active(file): 1751924 kB
12Inactive(file): 17522276 kB
13Unevictable: 8548 kB
14Mlocked: 8548 kB
15SwapTotal: 33431548 kB
16SwapFree: 33431548 kB
17Zswap: 0 kB
18Zswapped: 0 kB
19Dirty: 784 kB
20Writeback: 0 kB
21AnonPages: 7139968 kB
22Mapped: 1094916 kB
23Shmem: 284160 kB
24KReclaimable: 3303788 kB
25Slab: 3801908 kB
26SReclaimable: 3303788 kB
27SUnreclaim: 498120 kB
28KernelStack: 32992 kB
29PageTables: 68160 kB
30SecPageTables: 0 kB
31NFS_Unstable: 0 kB
32Bounce: 0 kB
33WritebackTmp: 0 kB
34CommitLimit: 49815436 kB
35Committed_AS: 16888536 kB
36VmallocTotal: 34359738367 kB
37VmallocUsed: 91200 kB
38VmallocChunk: 0 kB
39Percpu: 41472 kB
40HardwareCorrupted: 0 kB
41AnonHugePages: 1708032 kB
42ShmemHugePages: 0 kB
43ShmemPmdMapped: 0 kB
44FileHugePages: 0 kB
45FilePmdMapped: 0 kB
46Unaccepted: 0 kB
47HugePages_Total: 0
48HugePages_Free: 0
49HugePages_Rsvd: 0
50HugePages_Surp: 0
51Hugepagesize: 2048 kB
52Hugetlb: 0 kB
53DirectMap4k: 860468 kB
54DirectMap2M: 20023296 kB
55DirectMap1G: 12582912 kB