Hello community,

here is the log from the commit of package sbd for openSUSE:Factory checked in 
at 2019-11-06 13:56:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sbd (Old)
 and      /work/SRC/openSUSE:Factory/.sbd.new.2990 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "sbd"

Wed Nov  6 13:56:40 2019 rev:32 rq:745168 version:1.4.0+20191029.695f9ca

Changes:
--------
--- /work/SRC/openSUSE:Factory/sbd/sbd.changes  2019-10-30 14:44:28.845969360 
+0100
+++ /work/SRC/openSUSE:Factory/.sbd.new.2990/sbd.changes        2019-11-06 
13:56:45.640199024 +0100
@@ -1,0 +2,23 @@
+Wed Oct 30 16:16:31 UTC 2019 - Yan Gao <[email protected]>
+
+- Update to version 1.4.0+20191029.695f9ca:
+- tests: add regression-tests using preload-library
+- tests: added preload-library for reboot interception
+
+-------------------------------------------------------------------
+Wed Oct 30 16:14:40 UTC 2019 - Yan Gao <[email protected]>
+
+- Update to version 1.4.0+20191028.3f01a1d:
+- spec: add devel package
+
+-------------------------------------------------------------------
+Wed Oct 30 14:30:59 UTC 2019 - Yan Gao <[email protected]>
+
+- Update to version 1.4.0+20191028.d937f9d:
+- sbd-inquisitor: use crashdump timeout
+- Build: switch back to serial test-harness
+- Doc: mention crashdump message in usage note
+- defaults: make 15s timeout default for s390 consistently
+- cmdline: just use SBD_DEVICE if no devs from cmdline
+
+-------------------------------------------------------------------

Old:
----
  sbd-1.4.0+20190919.2758632.tar.xz

New:
----
  sbd-1.4.0+20191029.695f9ca.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ sbd.spec ++++++
--- /var/tmp/diff_new_pack.tkjQut/_old  2019-11-06 13:56:46.884200333 +0100
+++ /var/tmp/diff_new_pack.tkjQut/_new  2019-11-06 13:56:46.888200337 +0100
@@ -23,7 +23,7 @@
 %endif
 
 Name:           sbd
-Version:        1.4.0+20190919.2758632
+Version:        1.4.0+20191029.695f9ca
 Release:        0
 Summary:        Storage-based death
 License:        GPL-2.0-or-later
@@ -52,17 +52,33 @@
 %description
 This package contains the storage-based death functionality.
 
+%package devel
+Summary:        Storage-based death environment for regression tests
+Group:          Productivity/Clustering/HA
+Requires:       %{name} = %{version}-%{release}
+
+%description devel
+This package provides an environment + testscripts for
+regression-testing sbd.
+
 %prep
 %autosetup -n %{name}-%{version} -p1
 
+%ifarch s390x s390
+sed -i src/sbd.sysconfig -e "s/Default: 5/Default: 15/"
+sed -i src/sbd.sysconfig -e "s/SBD_WATCHDOG_TIMEOUT=5/SBD_WATCHDOG_TIMEOUT=15/"
+%endif
+
 %build
-autoreconf -fvi
+./autogen.sh
+
 %configure
 make %{?_smp_mflags}
 
 %install
 %make_install LIBDIR=%{_libdir}
 install -D -m 0755 src/sbd.sh %{buildroot}%{_datadir}/sbd/sbd.sh
+install -D -m 0755 tests/regressions.sh 
%{buildroot}%{_datadir}/sbd/regressions.sh
 install -D -m 0644 src/sbd.service %{buildroot}/%{_unitdir}/sbd.service
 install -D -m 0644 src/sbd_remote.service 
%{buildroot}/%{_unitdir}/sbd_remote.service
 ln -s service %{buildroot}%{_sbindir}/rcsbd
@@ -70,6 +86,10 @@
 mkdir -p %{buildroot}%{_fillupdir}
 install -m 0644 src/sbd.sysconfig %{buildroot}%{_fillupdir}/sysconfig.sbd
 
+# Don't package static libs
+find %{buildroot} -type f -name "*.a" -delete -print
+find %{buildroot} -type f -name "*.la" -delete -print
+
 %post
 %service_add_post sbd.service sbd_remote.service
 
@@ -86,6 +106,9 @@
 %postun
 %service_del_postun -n sbd.service sbd_remote.service
 
+%post devel -p /sbin/ldconfig
+%postun devel -p /sbin/ldconfig
+
 %files
 %defattr(-,root,root)
 %{_libdir}/stonith/
@@ -93,10 +116,18 @@
 %{_sbindir}/rcsbd
 %{_sbindir}/rcsbd_remote
 %{_datadir}/sbd
+%exclude %{_datadir}/sbd/regressions.sh
 %{_mandir}/man8/sbd*
 %{_unitdir}/sbd.service
 %{_unitdir}/sbd_remote.service
 %{_fillupdir}/sysconfig.sbd
 %doc COPYING
 
+%files devel
+%defattr(-,root,root)
+%dir %{_datadir}/sbd
+%{_datadir}/sbd/regressions.sh
+%{_libdir}/libsbdtestbed*
+%doc COPYING
+
 %changelog

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.tkjQut/_old  2019-11-06 13:56:46.928200379 +0100
+++ /var/tmp/diff_new_pack.tkjQut/_new  2019-11-06 13:56:46.928200379 +0100
@@ -1,6 +1,6 @@
 <servicedata>
   <service name="tar_scm">
     <param name="url">https://github.com/ClusterLabs/sbd.git</param>
-    <param 
name="changesrevision">275863252c88b89ed6181c6bf44640b95458448b</param>
+    <param 
name="changesrevision">c4dc05841157dd42496d3643617c31383410e51f</param>
   </service>
 </servicedata>
\ No newline at end of file

++++++ sbd-1.4.0+20190919.2758632.tar.xz -> sbd-1.4.0+20191029.695f9ca.tar.xz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/.travis.yml 
new/sbd-1.4.0+20191029.695f9ca/.travis.yml
--- old/sbd-1.4.0+20190919.2758632/.travis.yml  2019-09-19 17:40:55.000000000 
+0200
+++ new/sbd-1.4.0+20191029.695f9ca/.travis.yml  2019-10-29 23:38:48.000000000 
+0100
@@ -40,7 +40,7 @@
   - docker run --privileged -v ${PWD}:/rpms 
${BUILD_OS_TYPE}:${BUILD_OS_DIST}${BUILD_OS_VERSION} /bin/bash -c "dnf install 
-y mock dnf-utils && if test $OS_VERSION = rawhide; then sed -i 
/etc/mock/${OS_MOCK}-${OS_VERSION}-${OS_ARCH}.cfg -e s/gpgcheck.*/gpgcheck=0/g; 
fi && mock --no-clean -r ${OS_MOCK}-${OS_VERSION}-${OS_ARCH} --resultdir=/rpms 
--disable-plugin=yum_cache --disable-plugin=selinux --no-bootstrap-chroot 
--old-chroot /rpms/sbd*.src.rpm"
   - ls ${PWD}/${PACKAGE}*.${OS_ARCH}.rpm
   - docker pull ${OS_TYPE}:${OS_DIST}${OS_VERSION}
-  - docker run --privileged -v ${PWD}:/rpms -v ${PWD}/tests:/tests 
${OS_TYPE}:${OS_DIST}${OS_VERSION} /bin/bash -c "if test $OS_VERSION = rawhide; 
then yum update -y --nogpgcheck; fi && yum install -y device-mapper 
/rpms/${PACKAGE}*.${OS_ARCH}.rpm && /tests/regressions.sh && touch 
/rpms/regressions.sh.SUCCESS"
+  - docker run --privileged -v ${PWD}:/rpms ${OS_TYPE}:${OS_DIST}${OS_VERSION} 
/bin/bash -c "if test $OS_VERSION = rawhide; then yum update -y --nogpgcheck; 
fi && yum install -y device-mapper /rpms/${PACKAGE}*.${OS_ARCH}.rpm && 
/usr/share/sbd/regressions.sh && touch /rpms/regressions.sh.SUCCESS"
   - ls ${PWD}/regressions.sh.SUCCESS
 
 addons:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/Makefile.am 
new/sbd-1.4.0+20191029.695f9ca/Makefile.am
--- old/sbd-1.4.0+20190919.2758632/Makefile.am  2019-09-19 17:40:55.000000000 
+0200
+++ new/sbd-1.4.0+20191029.695f9ca/Makefile.am  2019-10-29 23:38:48.000000000 
+0100
@@ -1,4 +1,4 @@
-SUBDIRS = src agent man
+SUBDIRS = src agent man tests
 
 # .gz because github doesn't support .xz yet :-(
 # this is modified
@@ -28,6 +28,9 @@
 
 TESTS           = tests/regressions.sh
 export SBD_BINARY := src/sbd
+export SBD_PRELOAD := tests/.libs/libsbdtestbed.so
+export SBD_USE_DM := no
+
 EXTRA_DIST      = sbd.spec tests/regressions.sh
 
 export:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/autogen.sh 
new/sbd-1.4.0+20191029.695f9ca/autogen.sh
--- old/sbd-1.4.0+20190919.2758632/autogen.sh   2019-09-19 17:40:55.000000000 
+0200
+++ new/sbd-1.4.0+20191029.695f9ca/autogen.sh   2019-10-29 23:38:48.000000000 
+0100
@@ -1,4 +1,10 @@
 #!/bin/sh
 
+am_ver=`automake --version | sed -n 1p`
+case $am_ver in
+    *\ 1.11*|*\ 1.12*) echo 'm4_define([TESTS_OPTION], [])';;
+    *) echo 'm4_define([TESTS_OPTION], [serial-tests])';;
+esac > tests-opt.m4
+cat tests-opt.m4
 # Run this to generate all the initial makefiles, etc.
 autoreconf -i -v && echo Now run ./configure and make
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/configure.ac 
new/sbd-1.4.0+20191029.695f9ca/configure.ac
--- old/sbd-1.4.0+20190919.2758632/configure.ac 2019-09-19 17:40:55.000000000 
+0200
+++ new/sbd-1.4.0+20191029.695f9ca/configure.ac 2019-10-29 23:38:48.000000000 
+0100
@@ -22,15 +22,16 @@
 AC_INIT([sbd], 
        [1.4.0],
        [[email protected]])
+m4_include([tests-opt.m4])
 AC_CANONICAL_HOST
 AC_CONFIG_AUX_DIR(.)
 AC_CONFIG_HEADERS(config.h)
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([no])])
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE(1.11.1 foreign TESTS_OPTION)
 AM_PROG_CC_C_O
 
 PKG_CHECK_MODULES(glib, [glib-2.0])
-dnl PKG_CHECK_MODULES(libcoroipcc, [libcoroipcc])
+PKG_CHECK_MODULES(libxml, [libxml-2.0])
 
 PKG_CHECK_MODULES(cmap, [libcmap], HAVE_cmap=1, HAVE_cmap=0)
 PKG_CHECK_MODULES(votequorum, [libvotequorum], HAVE_votequorum=1, 
HAVE_votequorum=0)
@@ -40,9 +41,12 @@
 
 dnl pacemaker <= 1.1.8
 PKG_CHECK_MODULES(pcmk, [pcmk, pcmk-cib], HAVE_pcmk=1, HAVE_pcmk=0)
+
 PKG_CHECK_MODULES(libqb, [libqb])
 
-CPPFLAGS="$CPPFLAGS -Werror"
+CPPFLAGS="$CPPFLAGS -Werror $glib_CFLAGS $libxml_CFLAGS"
+LIBS="$LIBS $glib_LIBS $libxml_LIBS"
+
 if test $HAVE_pacemaker = 0 -a $HAVE_pcmk = 0; then
     AC_MSG_ERROR(No package 'pacemaker' found)
 elif test $HAVE_pacemaker = 1; then
@@ -61,11 +65,12 @@
     fi
 fi
 
-PKG_CHECK_MODULES(libxml, [libxml-2.0])
-CPPFLAGS="$CPPFLAGS $libxml_CFLAGS $libqb_CFLAGS $pacemaker_CFLAGS 
$pcmk_CFLAGS"
-LIBS="$LIBS $libxml_LIBS $libqb_LIBS $pacemaker_LIBS $pcmk_LIBS"
+CPPFLAGS="$CPPFLAGS $libqb_CFLAGS $pacemaker_CFLAGS $pcmk_CFLAGS"
+LIBS="$LIBS $libqb_LIBS $pacemaker_LIBS $pcmk_LIBS"
 
 dnl     checks for libraries
+AC_CHECK_LIB(c, dlopen)                         dnl if dlopen is in libc...
+AC_CHECK_LIB(dl, dlopen)                        dnl -ldl (for Linux)
 AC_CHECK_LIB(aio, io_setup, , missing="yes")
 AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set, , missing="yes")
 AC_CHECK_LIB(cib, cib_new, , missing="yes")
@@ -127,6 +132,18 @@
     [ CONFIGDIR="$withval" ]
 )
 
+#
+# Where is dlopen?
+#
+if test "$ac_cv_lib_c_dlopen" = yes; then
+    LIBADD_DL=""
+elif test "$ac_cv_lib_dl_dlopen" = yes; then
+    LIBADD_DL=-ldl
+else
+    LIBADD_DL=${lt_cv_dlopen_libs}
+fi
+
+
 dnl **********************************************************************
 dnl Check for various argv[] replacing functions on various OSs
 dnl
@@ -240,6 +257,8 @@
 eval infodir="`eval echo ${infodir}`"
 eval mandir="`eval echo ${mandir}`"
 
+AC_SUBST(LIBADD_DL)        dnl extra flags for dynamic linking libraries
+
 if test x"${CONFIGDIR}" = x""; then
     CONFIGDIR="${sysconfdir}/sysconfig"
 fi
@@ -248,6 +267,8 @@
 dnl The Makefiles and shell scripts we output
 AC_CONFIG_FILES([Makefile src/Makefile agent/Makefile man/Makefile agent/sbd 
src/sbd.service src/sbd_remote.service src/sbd.sh])
 
+AC_CONFIG_SUBDIRS([tests])
+
 dnl Now process the entire list of files added by previous 
 dnl  calls to AC_CONFIG_FILES()
 AC_OUTPUT()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/man/sbd.8.pod 
new/sbd-1.4.0+20191029.695f9ca/man/sbd.8.pod
--- old/sbd-1.4.0+20190919.2758632/man/sbd.8.pod        2019-09-19 
17:40:55.000000000 +0200
+++ new/sbd-1.4.0+20191029.695f9ca/man/sbd.8.pod        2019-10-29 
23:38:48.000000000 +0100
@@ -331,7 +331,7 @@
 setting before triggering the dump. Otherwise, the watchdog might trigger and
 prevent a successful crashdump from ever being written.
 
-Defaults to 240 seconds. Set to zero to disable.
+Set to zero (= default) to disable.
 
 =item B<-r> I<N>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/sbd.spec 
new/sbd-1.4.0+20191029.695f9ca/sbd.spec
--- old/sbd-1.4.0+20190919.2758632/sbd.spec     2019-09-19 17:40:55.000000000 
+0200
+++ new/sbd-1.4.0+20191029.695f9ca/sbd.spec     2019-10-29 23:38:48.000000000 
+0100
@@ -35,7 +35,7 @@
 BuildRequires:  libuuid-devel
 BuildRequires:  glib2-devel
 BuildRequires:  libaio-devel
-BuildRequires:  corosynclib-devel
+BuildRequires:  corosync-devel
 %if 0%{?suse_version}
 BuildRequires:  libpacemaker-devel
 %else
@@ -60,14 +60,27 @@
 
 This package contains the storage-based death functionality.
 
+%package tests
+Summary:        Storage-based death environment for regression tests
+License:        GPLv2+
+Group:          System Environment/Daemons
+
+%description tests
+This package provides an environment + testscripts for
+regression-testing sbd.
+
 %prep
 ###########################################################
 # %setup -n sbd-%{version} -q
 %setup -q -n %{name}-%{commit}
+%ifarch s390x s390
+sed -i src/sbd.sysconfig -e "s/Default: 5/Default: 15/"
+sed -i src/sbd.sysconfig -e "s/SBD_WATCHDOG_TIMEOUT=5/SBD_WATCHDOG_TIMEOUT=15/"
+%endif
 ###########################################################
 
 %build
-autoreconf -i
+./autogen.sh
 export CFLAGS="$RPM_OPT_FLAGS -Wall -Werror"
 %configure
 make %{?_smp_mflags}
@@ -80,6 +93,7 @@
 rm -rf ${RPM_BUILD_ROOT}%{_libdir}/stonith
 
 install -D -m 0755 src/sbd.sh $RPM_BUILD_ROOT/usr/share/sbd/sbd.sh
+install -D -m 0755 tests/regressions.sh 
$RPM_BUILD_ROOT/usr/share/sbd/regressions.sh
 %if %{defined _unitdir}
 install -D -m 0644 src/sbd.service $RPM_BUILD_ROOT/%{_unitdir}/sbd.service
 install -D -m 0644 src/sbd_remote.service 
$RPM_BUILD_ROOT/%{_unitdir}/sbd_remote.service
@@ -88,6 +102,10 @@
 mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
 install -m 644 src/sbd.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/sbd
 
+# Don't package static libs
+find %{buildroot} -name '*.a' -type f -print0 | xargs -0 rm -f
+find %{buildroot} -name '*.la' -type f -print0 | xargs -0 rm -f
+
 %clean
 rm -rf %{buildroot}
 
@@ -111,6 +129,7 @@
 %config(noreplace) %{_sysconfdir}/sysconfig/sbd
 %{_sbindir}/sbd
 %{_datadir}/sbd
+%exclude %{_datadir}/sbd/regressions.sh
 %doc %{_mandir}/man8/sbd*
 %if %{defined _unitdir}
 %{_unitdir}/sbd.service
@@ -118,6 +137,12 @@
 %endif
 %doc COPYING
 
+%files tests
+%defattr(-,root,root)
+%dir %{_datadir}/sbd
+%{_datadir}/sbd/regressions.sh
+%{_libdir}/libsbdtestbed*
+
 %changelog
 * Mon Jan 14 2019 <[email protected]> - 1.4.0-0.1.2d595fdd.git
 - updated travis-CI (ppc64le-build, fedora29, remove need for
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/src/Makefile.am 
new/sbd-1.4.0+20191029.695f9ca/src/Makefile.am
--- old/sbd-1.4.0+20190919.2758632/src/Makefile.am      2019-09-19 
17:40:55.000000000 +0200
+++ new/sbd-1.4.0+20191029.695f9ca/src/Makefile.am      2019-10-29 
23:38:48.000000000 +0100
@@ -11,5 +11,3 @@
 sbd_SOURCES += sbd-md.c
 endif
 
-sbd_LDADD = $(glib_LIBS) $(libcoroipcc_LIBS)
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/src/sbd-common.c 
new/sbd-1.4.0+20191029.695f9ca/src/sbd-common.c
--- old/sbd-1.4.0+20190919.2758632/src/sbd-common.c     2019-09-19 
17:40:55.000000000 +0200
+++ new/sbd-1.4.0+20191029.695f9ca/src/sbd-common.c     2019-10-29 
23:38:48.000000000 +0100
@@ -47,7 +47,7 @@
 
 int    watchdog_use            = 1;
 int    watchdog_set_timeout    = 1;
-unsigned long  timeout_watchdog_crashdump = 240;
+unsigned long  timeout_watchdog_crashdump = 0;
 int    skip_rt                 = 0;
 int    debug                   = 0;
 int    debug_mode              = 0;
@@ -89,7 +89,8 @@
 "-4 <N>                Set msgwait timeout to N seconds (optional, create 
only)\n"
 "-5 <N>                Warn if loop latency exceeds threshold (optional, watch 
only)\n"
 "                      (default is 3, set to 0 to disable)\n"
-"-C <N>                Watchdog timeout to set before crashdumping (def: 240s, 
optional)\n"
+"-C <N>                Watchdog timeout to set before crashdumping\n"
+"                      (def: 0s = disable gracefully, optional)\n"
 "-I <N>                Async IO read timeout (defaults to 3 * loop timeout, 
optional)\n"
 "-s <N>                Timeout to wait for devices to become available (def: 
120s)\n"
 "-t <N>                Dampening delay before faulty servants are restarted 
(optional)\n"
@@ -107,7 +108,7 @@
 "dump          Dump meta-data header from device.\n"
 "allocate <node>\n"
 "              Allocate a slot for node (optional)\n"
-"message <node> (test|reset|off|clear|exit)\n"
+"message <node> (test|reset|off|crashdump|clear|exit)\n"
 "              Writes the specified message to node's slot.\n"
 #endif
 "watch         Loop forever, monitoring own slot\n"
@@ -930,10 +931,17 @@
         sync();
     }
 
-    if(kind == 'c') {
-        watchdog_close(true);
+    if (kind == 'c') {
+        if (timeout_watchdog_crashdump) {
+            if (timeout_watchdog != timeout_watchdog_crashdump) {
+                timeout_watchdog = timeout_watchdog_crashdump;
+                watchdog_init_interval();
+            }
+            watchdog_close(false);
+        } else {
+            watchdog_close(true);
+        }
         sysrq_trigger(kind);
-
     } else {
         watchdog_close(false);
         sysrq_trigger(kind);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/src/sbd-inquisitor.c 
new/sbd-1.4.0+20191029.695f9ca/src/sbd-inquisitor.c
--- old/sbd-1.4.0+20190919.2758632/src/sbd-inquisitor.c 2019-09-19 
17:40:55.000000000 +0200
+++ new/sbd-1.4.0+20191029.695f9ca/src/sbd-inquisitor.c 2019-10-29 
23:38:48.000000000 +0100
@@ -886,22 +886,6 @@
 
        sbd_get_uname();
 
-        value = getenv("SBD_DEVICE");
-        if(value) {
-#if SUPPORT_SHARED_DISK
-            int devices = parse_device_line(value);
-            if(devices < 1) {
-                fprintf(stderr, "Invalid device line: %s\n", value);
-                exit_status = -2;
-                goto out;
-            }
-#else
-            fprintf(stderr, "Shared disk functionality not supported\n");
-            exit_status = -2;
-            goto out;
-#endif
-        }
-
         value = getenv("SBD_PACEMAKER");
         if(value) {
             check_pcmk = crm_is_true(value);
@@ -1112,6 +1096,28 @@
                }
        }
 
+    if (disk_count == 0) {
+        /* if we already have disks from commandline
+           then it is probably undesirable to add those
+           from environment (general rule cmdline has precedence)
+         */
+        value = getenv("SBD_DEVICE");
+        if ((value) && strlen(value)) {
+#if SUPPORT_SHARED_DISK
+            int devices = parse_device_line(value);
+            if(devices < 1) {
+                fprintf(stderr, "Invalid device line: %s\n", value);
+                exit_status = -2;
+                goto out;
+            }
+#else
+            fprintf(stderr, "Shared disk functionality not supported\n");
+            exit_status = -2;
+            goto out;
+#endif
+        }
+       }
+
        if (watchdogdev == NULL || strcmp(watchdogdev, "/dev/null") == 0) {
             watchdog_use = 0;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/tests/Makefile.am 
new/sbd-1.4.0+20191029.695f9ca/tests/Makefile.am
--- old/sbd-1.4.0+20190919.2758632/tests/Makefile.am    1970-01-01 
01:00:00.000000000 +0100
+++ new/sbd-1.4.0+20191029.695f9ca/tests/Makefile.am    2019-10-29 
23:38:48.000000000 +0100
@@ -0,0 +1,4 @@
+lib_LTLIBRARIES = libsbdtestbed.la
+libsbdtestbed_la_SOURCES = sbd-testbed.c
+libsbdtestbed_la_LDFLAGS =
+libsbdtestbed_la_LIBADD        = @LIBADD_DL@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/tests/configure.ac 
new/sbd-1.4.0+20191029.695f9ca/tests/configure.ac
--- old/sbd-1.4.0+20190919.2758632/tests/configure.ac   1970-01-01 
01:00:00.000000000 +0100
+++ new/sbd-1.4.0+20191029.695f9ca/tests/configure.ac   2019-10-29 
23:38:48.000000000 +0100
@@ -0,0 +1,183 @@
+dnl
+dnl autoconf for Agents
+dnl
+dnl License: GNU General Public License (GPL)
+
+dnl ===============================================
+dnl Bootstrap
+dnl ===============================================
+AC_PREREQ(2.63)
+
+dnl Suggested structure:
+dnl     information on the package
+dnl     checks for programs
+dnl     checks for libraries
+dnl     checks for header files
+dnl     checks for types
+dnl     checks for structures
+dnl     checks for compiler characteristics
+dnl     checks for library functions
+dnl     checks for system services
+
+AC_INIT([sbd],
+       [1.4.0],
+       [[email protected]])
+m4_include([../tests-opt.m4])
+AC_CANONICAL_HOST
+AC_CONFIG_AUX_DIR(.)
+AC_CONFIG_HEADERS(config.h)
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([no])])
+AM_INIT_AUTOMAKE(1.11.1 foreign TESTS_OPTION)
+LT_INIT([dlopen],[disable-static])
+AM_PROG_CC_C_O
+
+PKG_CHECK_MODULES(glib, [glib-2.0])
+
+CPPFLAGS="$CPPFLAGS -Werror $glib_CFLAGS"
+LIBS="$LIBS $glib_LIBS"
+
+dnl     checks for libraries
+AC_CHECK_LIB(c, dlopen)                         dnl if dlopen is in libc...
+AC_CHECK_LIB(dl, dlopen)                        dnl -ldl (for Linux)
+
+
+CONFIGDIR=""
+AC_ARG_WITH(configdir,
+    [  --with-configdir=DIR
+       Directory for SBD configuration file [${CONFIGDIR}]],
+    [ CONFIGDIR="$withval" ]
+)
+
+#
+# Where is dlopen?
+#
+if test "$ac_cv_lib_c_dlopen" = yes; then
+    LIBADD_DL=""
+elif test "$ac_cv_lib_dl_dlopen" = yes; then
+    LIBADD_DL=-ldl
+else
+    LIBADD_DL=${lt_cv_dlopen_libs}
+fi
+
+
+dnl **********************************************************************
+dnl Check for various argv[] replacing functions on various OSs
+dnl
+dnl Borrowed from Proftpd
+dnl Proftpd is Licenced under the terms of the GNU General Public Licence
+dnl and is available from http://www.proftpd.org/
+dnl
+
+AC_CHECK_FUNCS(setproctitle)
+AC_CHECK_HEADERS(libutil.h)
+AC_CHECK_LIB(util, setproctitle,
+        [AC_DEFINE(HAVE_SETPROCTITLE,1,[ ])
+                ac_cv_func_setproctitle="yes" ; LIBS="$LIBS -lutil"])
+
+if test "$ac_cv_func_setproctitle" = "yes"; then
+  pf_argv_set="PF_ARGV_NONE"
+fi
+
+if test "$pf_argv_set" = ""; then
+  AC_CHECK_HEADERS(sys/pstat.h)
+  if test "$ac_cv_header_pstat_h" = "yes"; then
+    AC_CHECK_FUNCS(pstat)
+
+    if test "$ac_cv_func_pstat" = "yes"; then
+        pf_argv_set="PF_ARGV_PSTAT"
+    else
+        pf_argv_set="PF_ARGV_WRITEABLE"
+    fi
+  fi
+
+  if test "$pf_argv_set" = ""; then
+    AC_EGREP_HEADER([#define.*PS_STRINGS.*],sys/exec.h,
+                        have_psstrings="yes",have_psstrings="no")
+    if test "$have_psstrings" = "yes"; then
+        pf_argv_set="PF_ARGV_PSSTRINGS"
+    fi
+  fi
+
+  if test "$pf_argv_set" = ""; then
+    AC_CACHE_CHECK(whether __progname and __progname_full are available,
+                    pf_cv_var_progname,
+                    AC_TRY_LINK([extern char *__progname, *__progname_full;],
+                        [__progname = "foo"; __progname_full = "foo bar";],
+                        pf_cv_var_progname="yes", pf_cv_var_progname="no"))
+
+    if test "$pf_cv_var_progname" = "yes"; then
+        AC_DEFINE(HAVE___PROGNAME,1,[ ])
+    fi
+
+    AC_CACHE_CHECK(which argv replacement method to use,
+                    pf_cv_argv_type,
+                    AC_EGREP_CPP(yes,[
+#if defined(__GNU_HURD__)
+  yes
+#endif
+  ],pf_cv_argv_type="new", pf_cv_argv_type="writeable"))
+
+    if test "$pf_cv_argv_type" = "new"; then
+        pf_argv_set="PF_ARGV_NEW"
+    fi
+
+    if test "$pf_argv_set" = ""; then
+        pf_argv_set="PF_ARGV_WRITEABLE"
+    fi
+  fi
+fi
+AC_DEFINE_UNQUOTED(PF_ARGV_TYPE, $pf_argv_set,
+        mechanism to pretty-print ps output: setproctitle-equivalent)
+
+dnl End of tests borrowed from Proftpd
+
+AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
+case $prefix in
+  NONE)
+       prefix=/usr
+       dnl Fix default variables - "prefix" variable if not specified
+       if test "$localstatedir" = "\${prefix}/var"; then
+               localstatedir="/var"
+       fi
+       if test "$sysconfdir" = "\${prefix}/etc"; then
+               sysconfdir="/etc"
+       fi
+       ;;
+esac
+
+AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
+case $exec_prefix in
+  dnl For consistency with Heartbeat, map NONE->$prefix
+  NONE)          exec_prefix=$prefix;;
+  prefix) exec_prefix=$prefix;;
+esac
+
+dnl Expand autoconf variables so that we dont end up with '${prefix}'
+dnl in #defines and python scripts
+dnl NOTE: Autoconf deliberately leaves them unexpanded to allow
+dnl    make exec_prefix=/foo install
+dnl No longer being able to do this seems like no great loss to me...
+
+eval prefix="`eval echo ${prefix}`"
+eval exec_prefix="`eval echo ${exec_prefix}`"
+eval bindir="`eval echo ${bindir}`"
+eval sbindir="`eval echo ${sbindir}`"
+eval libexecdir="`eval echo ${libexecdir}`"
+eval datadir="`eval echo ${datadir}`"
+eval sysconfdir="`eval echo ${sysconfdir}`"
+eval sharedstatedir="`eval echo ${sharedstatedir}`"
+eval localstatedir="`eval echo ${localstatedir}`"
+eval libdir="`eval echo ${libdir}`"
+eval includedir="`eval echo ${includedir}`"
+eval oldincludedir="`eval echo ${oldincludedir}`"
+eval infodir="`eval echo ${infodir}`"
+eval mandir="`eval echo ${mandir}`"
+
+AC_SUBST(LIBADD_DL)        dnl extra flags for dynamic linking libraries
+
+dnl The Makefiles and shell scripts we output
+AC_CONFIG_FILES([Makefile])
+
+dnl Now process the entire list of files added by previous
+dnl  calls to AC_CONFIG_FILES()
+AC_OUTPUT()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/tests/regressions.sh 
new/sbd-1.4.0+20191029.695f9ca/tests/regressions.sh
--- old/sbd-1.4.0+20190919.2758632/tests/regressions.sh 2019-09-19 
17:40:55.000000000 +0200
+++ new/sbd-1.4.0+20191029.695f9ca/tests/regressions.sh 2019-10-29 
23:38:48.000000000 +0100
@@ -28,41 +28,78 @@
 # - Can the unit/service file be tested? or at least the wrapper?
 
 : ${SBD_BINARY:="/usr/sbin/sbd"}
+: ${SBD_PRELOAD="libsbdtestbed.so"}
+: ${SBD_USE_DM:="yes"}
 
 sbd() {
-       ${SBD_BINARY} $*
+       LD_PRELOAD=${SBD_PRELOAD} SBD_WATCHDOG_TIMEOUT=5 
SBD_DEVICE="${SBD_DEVICE}" SBD_PRELOAD_LOG=${SBD_PRELOAD_LOG} 
SBD_WATCHDOG_DEV=/dev/watchdog setsid ${SBD_BINARY} -p ${SBD_PIDFILE} $*
+}
+
+sbd_wipe_disk() {
+       dd if=/dev/zero of=$1 count=2048 2>/dev/null
 }
 
 sbd_setup() {
        trap sbd_teardown EXIT
        for N in $(seq 3) ; do
                F[$N]=$(mktemp /tmp/sbd.device.$N.XXXXXX)
-               R[$N]=$(echo ${F[$N]}|cut -f4 -d.)
-               dd if=/dev/zero of=${F[$N]} count=2048
-               L[$N]=$(losetup -f)
-               losetup ${L[$N]} ${F[$N]}
-               D[$N]="/dev/mapper/sbd_${N}_${R[$N]}"
-               dmsetup create sbd_${N}_${R[$N]} --table "0 2048 linear 
${L[$N]} 0"
-               dmsetup mknodes sbd_${N}_${R[$N]}
+               sbd_wipe_disk ${F[$N]}
+               if [[ "${SBD_USE_DM}" == "yes" ]]; then
+                       R[$N]=$(echo ${F[$N]}|cut -f4 -d.)
+                       L[$N]=$(losetup -f)
+                       losetup ${L[$N]} ${F[$N]}
+                       D[$N]="/dev/mapper/sbd_${N}_${R[$N]}"
+                       dmsetup create sbd_${N}_${R[$N]} --table "0 2048 linear 
${L[$N]} 0"
+                       dmsetup mknodes sbd_${N}_${R[$N]}
+               else
+                       D[$N]=${F[$N]}
+               fi
        done
+       if [[ "${SBD_USE_DM}" != "yes" ]]; then
+               SBD_DEVICE="${F[1]};${F[2]};${F[3]}"
+       fi
+       SBD_PIDFILE=$(mktemp /tmp/sbd.pidfile.XXXXXX)
+       SBD_PRELOAD_LOG=$(mktemp /tmp/sbd.logfile.XXXXXX)
 }
 
 sbd_teardown() {
        for N in $(seq 3) ; do
-               dmsetup remove sbd_${N}_${R[$N]}
-               losetup -d ${L[$N]}
+               if [[ "${SBD_USE_DM}" == "yes" ]]; then
+                       dmsetup remove sbd_${N}_${R[$N]}
+                       losetup -d ${L[$N]}
+               fi
                rm -f ${F[$N]}
+               sbd_daemon_cleanup
+               rm -f ${SBD_PIDFILE}
+               rm -f ${SBD_PRELOAD_LOG}
        done
 }
 
 sbd_dev_fail() {
-       dmsetup wipe_table sbd_${1}_${R[$1]}
+       if [[ "${SBD_USE_DM}" == "yes" ]]; then
+               dmsetup wipe_table sbd_${1}_${R[$1]}
+       else
+               D[$1]=/tmp/fail123456789
+       fi
 }
 
 sbd_dev_resume() {
-       dmsetup suspend sbd_${1}_${R[$1]}
-       dmsetup load sbd_${1}_${R[$1]} --table "0 2048 linear ${L[$1]} 0"
-       dmsetup resume sbd_${1}_${R[$1]}
+       if [[ "${SBD_USE_DM}" == "yes" ]]; then
+               dmsetup suspend sbd_${1}_${R[$1]}
+               dmsetup load sbd_${1}_${R[$1]} --table "0 2048 linear ${L[$1]} 
0"
+               dmsetup resume sbd_${1}_${R[$1]}
+       else
+               D[$1]=${F[$1]}
+       fi
+}
+
+sbd_daemon_cleanup() {
+       echo > ${SBD_PRELOAD_LOG}
+       pkill -TERM --pidfile ${SBD_PIDFILE} 2>/dev/null
+       sleep 5
+       pkill -KILL --pidfile ${SBD_PIDFILE} 2>/dev/null
+       pkill -KILL --parent $(cat ${SBD_PIDFILE} 2>/dev/null) 2>/dev/null
+       echo > ${SBD_PIDFILE}
 }
 
 _ok() {
@@ -86,6 +123,16 @@
        return 0
 }
 
+_in_log() {
+       grep "$@" ${SBD_PRELOAD_LOG} >/dev/null
+       if [ $? -ne 0 ]; then
+               echo "didn't find '$@' in log:"
+               cat ${SBD_PRELOAD_LOG}
+               sbd_daemon_cleanup
+               exit 1
+       fi
+}
+
 test_1() {
        echo "Creating three devices"
        _ok sbd -d ${D[1]} -d ${D[2]} -d ${D[3]} create
@@ -168,9 +215,112 @@
        _ok sbd -h
 }
 
+test_watchdog() {
+       echo "Basic watchdog test"
+       echo > ${SBD_PRELOAD_LOG}
+       sbd test-watchdog < /dev/null
+       _in_log "watchdog fired"
+}
+
+test_stall_inquisitor() {
+       echo "Stall inquisitor test"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} -d ${D[2]} -d ${D[3]} -n test-1 watch
+       sleep 10
+       _ok kill -0 $(cat ${SBD_PIDFILE})
+       kill -STOP $(cat ${SBD_PIDFILE})
+       sleep 10
+       kill -CONT $(cat ${SBD_PIDFILE}) 2>/dev/null
+       _in_log "watchdog fired"
+}
+
+test_wipe_slots1() {
+       echo "Wipe slots test (with watchdog)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} -n test-1 watch
+       sleep 2
+       sbd_wipe_disk ${D[1]}
+       sleep 15
+       _in_log "watchdog fired"
+}
+
+test_wipe_slots2() {
+       echo "Wipe slots test (without watchdog)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd_wipe_disk ${D[1]}
+       sleep 15
+       _in_log "sysrq-trigger ('b')"
+       _in_log "reboot (reboot)"
+}
+
+test_message1() {
+       echo "Message test (reset)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd -d ${D[1]} message test-1 reset
+       sleep 2
+       _in_log "sysrq-trigger ('b')"
+       _in_log "reboot (reboot)"
+}
+
+test_message2() {
+       echo "Message test (off)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd -d ${D[1]} message test-1 off
+       sleep 2
+       _in_log "sysrq-trigger ('o')"
+       _in_log "reboot (poweroff)"
+}
+
+test_message3() {
+       echo "Message test (crashdump)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd -d ${D[1]} message test-1 crashdump
+       sleep 2
+       _in_log "sysrq-trigger ('c')"
+}
+
+test_timeout_action1() {
+       echo "Timeout action test (off)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       SBD_TIMEOUT_ACTION=off sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd_wipe_disk ${D[1]}
+       sleep 10
+       _in_log "sysrq-trigger ('o')"
+       _in_log "reboot (poweroff)"
+}
+
+test_timeout_action2() {
+       echo "Timeout action test (crashdump)"
+       sbd_daemon_cleanup
+       sbd -d ${D[1]} create
+       SBD_TIMEOUT_ACTION=crashdump sbd -d ${D[1]} -w /dev/null -n test-1 watch
+       sleep 2
+       sbd_wipe_disk ${D[1]}
+       sleep 10
+       _in_log "sysrq-trigger ('c')"
+}
+
 sbd_setup
 
-for T in $(seq 9); do
+if [[ "${SBD_PRELOAD}" != "" ]]; then
+       SBD_DAEMON_TESTS="watchdog stall_inquisitor wipe_slots1 wipe_slots2 
message1 message2 message3 timeout_action1 timeout_action2"
+fi
+
+for T in $(seq 9) ${SBD_DAEMON_TESTS}; do
        if ! test_$T ; then
                echo "FAILURE: Test $T"
                break
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sbd-1.4.0+20190919.2758632/tests/sbd-testbed.c 
new/sbd-1.4.0+20191029.695f9ca/tests/sbd-testbed.c
--- old/sbd-1.4.0+20190919.2758632/tests/sbd-testbed.c  1970-01-01 
01:00:00.000000000 +0100
+++ new/sbd-1.4.0+20191029.695f9ca/tests/sbd-testbed.c  2019-10-29 
23:38:48.000000000 +0100
@@ -0,0 +1,729 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/reboot.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <libaio.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <glib.h>
+#include <errno.h>
+
+#if __GLIBC_PREREQ(2,36)
+#include <glib-unix.h>
+#else
+#include <glib/giochannel.h>
+
+typedef gboolean (*GUnixFDSourceFunc) (gint         fd,
+                                       GIOCondition condition,
+                                       gpointer     user_data);
+
+static gboolean
+GIOFunc2GUnixFDSourceFunc(GIOChannel *source,
+            GIOCondition condition,
+            gpointer data)
+{
+    return ((GUnixFDSourceFunc) data) (
+        g_io_channel_unix_get_fd(source),
+        condition, NULL);
+}
+
+static guint
+g_unix_fd_add(gint fd,
+               GIOCondition condition,
+               GUnixFDSourceFunc function,
+               gpointer user_data)
+{
+    GIOChannel *chan = g_io_channel_unix_new (fd);
+
+    if (chan == NULL) {
+        return 0;
+    } else {
+        return g_io_add_watch(chan,
+                   condition,
+                   GIOFunc2GUnixFDSourceFunc,
+                   (gpointer) function);
+    }
+}
+#endif
+
+typedef int (*orig_open_f_type)(const char *pathname, int flags, ...);
+typedef int (*orig_ioctl_f_type)(int fd, unsigned long int request, ...);
+typedef ssize_t (*orig_write_f_type)(int fd, const void *buf, size_t count);
+typedef int (*orig_close_f_type)(int fd);
+typedef FILE *(*orig_fopen_f_type)(const char *pathname, const char *mode);
+typedef int (*orig_fclose_f_type)(FILE *fp);
+typedef int (*orig_io_setup_f_type)(int nr_events, io_context_t *ctx_idp);
+typedef int (*orig_io_submit_f_type)(io_context_t ctx_id, long nr, struct iocb 
*ios[]);
+typedef int (*orig_io_getevents_f_type)(io_context_t ctx_id, long min_nr, long 
nr,
+                struct io_event *events, struct timespec *timeout);
+typedef int (*orig_io_cancel_f_type)(io_context_t ctx_id, struct iocb *iocb,
+                struct io_event *result);
+
+static int is_init = 0;
+static FILE *log_fp = NULL;
+
+static char *sbd_device[3] = {NULL, NULL, NULL};
+static int sbd_device_fd[3] = {-1, -1, -1};
+
+static FILE *sysrq_fp = NULL;
+static FILE *sysrq_trigger_fp = NULL;
+
+static char *watchdog_device = NULL;
+static int watchdog_device_fd = -1;
+static int watchdog_timeout = -1;
+static pid_t watchdog_pid = -1;
+static int watchdog_pipe[2] = {-1, -1};
+static guint watchdog_source_id = 0;
+static int watchdog_timer_id = 0;
+
+static orig_open_f_type orig_open = NULL;
+static orig_ioctl_f_type orig_ioctl = NULL;
+static orig_write_f_type orig_write = NULL;
+static orig_close_f_type orig_close = NULL;
+static orig_fopen_f_type orig_fopen = NULL;
+static orig_fclose_f_type orig_fclose = NULL;
+static orig_io_setup_f_type orig_io_setup = NULL;
+static orig_io_submit_f_type orig_io_submit = NULL;
+static orig_io_getevents_f_type orig_io_getevents = NULL;
+static orig_io_cancel_f_type orig_io_cancel = NULL;
+
+/* fprintf is inlined as __fprintf_chk or
+ * we have vfprintf.
+ * For fscanf we have vfscanf.
+ * For reboot we anyway don't want that to be
+ * called in any case.
+ */
+
+static struct iocb *pending_iocb = NULL;
+struct io_context { int context_num; };
+static struct io_context our_io_context = {.context_num = 1};
+static int translate_aio = 0;
+
+static GMainLoop *mainloop = NULL;
+
+#if 0
+static void
+watchdog_shutdown(int nsig)
+{
+    if (watchdog_timer_id > 0) {
+        fprintf(log_fp, "exiting with watchdog-timer armed\n");
+    }
+}
+#endif
+
+static void*
+dlsym_fatal(void *handle, const char *symbol)
+{
+    void *rv = dlsym(handle, symbol);
+
+    if (!rv) {
+        fprintf(stderr, "Failed looking up symbol %s\n", symbol);
+        exit(1);
+    }
+    return rv;
+}
+
+static void
+init (void)
+{
+    void *handle;
+
+    if (!is_init) {
+        const char *value;
+        int i;
+        char *token, *str, *str_orig;
+
+        is_init = 1;
+
+        orig_open         = (orig_open_f_type)dlsym_fatal(RTLD_NEXT,"open");
+        orig_ioctl        = (orig_ioctl_f_type)dlsym_fatal(RTLD_NEXT,"ioctl");
+        orig_close        = (orig_close_f_type)dlsym_fatal(RTLD_NEXT,"close");
+        orig_write        = (orig_write_f_type)dlsym_fatal(RTLD_NEXT,"write");
+        orig_fopen        = (orig_fopen_f_type)dlsym_fatal(RTLD_NEXT,"fopen");
+        orig_fclose       = 
(orig_fclose_f_type)dlsym_fatal(RTLD_NEXT,"fclose");
+
+        handle = dlopen("libaio.so.1",  RTLD_NOW);
+        if (!handle) {
+            fprintf(stderr, "Failed opening libaio.so.1\n");
+            exit(1);
+        }
+        orig_io_setup     = 
(orig_io_setup_f_type)dlsym_fatal(handle,"io_setup");
+        orig_io_submit    = 
(orig_io_submit_f_type)dlsym_fatal(handle,"io_submit");
+        orig_io_getevents = 
(orig_io_getevents_f_type)dlsym_fatal(handle,"io_getevents");
+        orig_io_cancel    = 
(orig_io_cancel_f_type)dlsym_fatal(handle,"io_cancel");
+        dlclose(handle);
+
+        value = getenv("SBD_PRELOAD_LOG");
+        if (value) {
+            log_fp = fopen(value, "a");
+        } else {
+            int fd = dup(fileno(stderr));
+            if (fd >= 0) {
+                log_fp = fdopen(fd, "w");
+            }
+        }
+        if (log_fp == NULL) {
+            fprintf(stderr, "couldn't open log-file\n");
+        }
+
+        value = getenv("SBD_WATCHDOG_DEV");
+        if (value) {
+            watchdog_device = strdup(value);
+        }
+
+        value = getenv("SBD_DEVICE");
+        if ((value) && (str = str_orig = strdup(value))) {
+            for (i = 0; i < 3; i++, str = NULL) {
+                token = strtok(str, ";");
+                if (token == NULL) {
+                    break;
+                }
+                sbd_device[i] = strdup(token);
+            }
+            free(str_orig);
+        }
+
+        value = getenv("SBD_TRANSLATE_AIO");
+        if ((value) && !strcmp(value, "yes")) {
+            translate_aio = 1;
+        }
+    }
+}
+
+// ***** end - handling of watchdog & block-devices ****
+
+static gboolean
+watchdog_timeout_notify(gpointer data)
+{
+    fprintf(log_fp, "watchdog fired after %ds - killing process group\n",
+            watchdog_timeout);
+    fclose(log_fp);
+    log_fp = NULL;
+    killpg(0, SIGKILL);
+    exit(1);
+}
+
+static gboolean
+watchdog_dispatch_callback (gint fd,
+                            GIOCondition condition,
+                            gpointer user_data)
+{
+    char buf[256];
+    int i = 0;
+
+    if (condition & G_IO_HUP) {
+        return FALSE;
+    }
+    if (watchdog_timer_id > 0) {
+        g_source_remove(watchdog_timer_id);
+    }
+    watchdog_timer_id = 0;
+    for (i = 0; i < sizeof(buf)-1; i++) {
+        ssize_t len;
+
+        do {
+            len = read(watchdog_pipe[0], &buf[i], 1);
+        } while ((len == -1) && (errno == EINTR));
+        if (len <= 0) {
+            if (len == -1) {
+                fprintf(log_fp, "Couldn't read from watchdog-pipe\n");
+            }
+            buf[i] = '\0';
+            break;
+        }
+        if (buf[i] == '\n') {
+            buf[i] = '\0';
+            break;
+        }
+    }
+    buf[sizeof(buf)-1] = '\0';
+    if (sscanf(buf, "trigger %ds", &watchdog_timeout) == 1) {
+        watchdog_timer_id = g_timeout_add(watchdog_timeout * 1000, 
watchdog_timeout_notify, NULL);
+    } else if (strcmp(buf, "disarm") == 0) {
+        // timer is stopped already
+    } else {
+        fprintf(log_fp, "unknown watchdog command\n");
+    }
+    return TRUE;
+}
+
+static void
+watchdog_arm (void) {
+    char buf[256];
+
+    if ((watchdog_timeout > 0) && (watchdog_pipe[1] >= 0)) {
+        sprintf(buf, "trigger %ds\n", watchdog_timeout);
+        if (write(watchdog_pipe[1], buf, strlen(buf)) != strlen(buf)) {
+            fprintf(log_fp, "Failed tickling watchdog via pipe\n");
+        }
+    }
+}
+
+static void
+watchdog_disarm (void) {
+    char buf[256];
+
+    watchdog_timeout = -1;
+    if (watchdog_pipe[1] >= 0) {
+        sprintf(buf, "disarm\n");
+        if (write(watchdog_pipe[1], buf, strlen(buf)) != strlen(buf)) {
+            fprintf(log_fp, "Failed disarming watchdog via pipe\n");
+        }
+    }
+}
+
+int
+open(const char *pathname, int flags, ...)
+{
+    int i, fd;
+    int devnum = -1;
+    int is_wd_dev = 0;
+    va_list ap;
+
+    init();
+
+    for (i=0; i < 3; i++) {
+        if (sbd_device[i]) {
+            if (strcmp(sbd_device[i], pathname) == 0) {
+                devnum = i;
+                flags &= ~O_DIRECT;
+                break;
+            }
+        }
+    }
+    if (watchdog_device) {
+        if (strcmp(watchdog_device, pathname) == 0) {
+            is_wd_dev = 1;
+            if (watchdog_pipe[1] == -1) {
+                if (pipe(watchdog_pipe) == -1) {
+                    fprintf(log_fp, "Creating pipe for watchdog failed\n");
+                } else {
+                    int i;
+
+                    watchdog_pid = fork();
+                    switch (watchdog_pid) {
+                        case -1:
+                            fprintf(log_fp, "Forking watchdog-child failed\n");
+                            break;
+                        case 0:
+                            free(watchdog_device);
+                            watchdog_device = NULL;
+                            for (i = 0; i < 3; i++) {
+                                free(sbd_device[i]);
+                                sbd_device[i] = NULL;
+                            }
+                            close(watchdog_pipe[1]);
+                            if (fcntl(watchdog_pipe[0], F_SETFL, O_NONBLOCK) 
== -1) {
+                                // don't block on read for timer to be handled
+                                fprintf(log_fp,
+                                        "Failed setting watchdog-pipe-read to 
non-blocking");
+                            }
+                            mainloop = g_main_loop_new(NULL, FALSE);
+                            // mainloop_add_signal(SIGTERM, watchdog_shutdown);
+                            // mainloop_add_signal(SIGINT, watchdog_shutdown);
+                            watchdog_source_id = 
g_unix_fd_add(watchdog_pipe[0],
+                                                    G_IO_IN,
+                                                    watchdog_dispatch_callback,
+                                                    NULL);
+                            if (watchdog_source_id == 0) {
+                                fprintf(log_fp, "Failed creating source for 
watchdog-pipe\n");
+                                exit(1);
+                            }
+                            g_main_loop_run(mainloop);
+                            g_main_loop_unref(mainloop);
+                            exit(0);
+                        default:
+                            close(watchdog_pipe[0]);
+                            if (fcntl(watchdog_pipe[1], F_SETFL, O_NONBLOCK) 
== -1) {
+                                fprintf(log_fp,
+                                        "Failed setting watchdog-pipe-write to 
non-blocking");
+                            }
+                    }
+                }
+            }
+            pathname = "/dev/null";
+        }
+    }
+
+    va_start (ap, flags);
+    fd = (flags & (O_CREAT
+#ifdef O_TMPFILE
+                   | O_TMPFILE
+#endif
+                  ))?
+             orig_open(pathname, flags, va_arg(ap, mode_t)):
+             orig_open(pathname, flags);
+    va_end (ap);
+
+    if (devnum >= 0) {
+        sbd_device_fd[devnum] = fd;
+    } else if (is_wd_dev) {
+        watchdog_device_fd = fd;
+    }
+
+    return fd;
+}
+
+ssize_t
+write(int fd, const void *buf, size_t count)
+{
+    init();
+
+    if ((fd == watchdog_device_fd) && (count >= 1)) {
+        if (*(const char *)buf == 'V') {
+            watchdog_disarm();
+        } else {
+            watchdog_arm();
+        }
+    }
+
+    return orig_write(fd, buf, count);
+}
+
+int
+ioctl(int fd, unsigned long int request, ...)
+{
+    int rv = -1;
+    va_list ap;
+    int i;
+
+    init();
+
+    va_start(ap, request);
+    switch (request) {
+        case BLKSSZGET:
+            for (i=0; i < 3; i++) {
+                if (sbd_device_fd[i] == fd) {
+                    rv = 0;
+                    *(va_arg(ap, int *)) = 512;
+                    break;
+                }
+                if (i == 2) {
+                    rv = orig_ioctl(fd, request, va_arg(ap, int *));
+                }
+            }
+            break;
+        case WDIOC_SETTIMEOUT:
+            if (fd == watchdog_device_fd) {
+                watchdog_timeout = *va_arg(ap, int *);
+
+                watchdog_arm();
+                rv = 0;
+                break;
+            }
+            rv = orig_ioctl(fd, request, va_arg(ap, int *));
+            break;
+        case WDIOC_SETOPTIONS:
+            if (fd == watchdog_device_fd) {
+                int flags = *va_arg(ap, int *);
+
+                if (flags & WDIOS_DISABLECARD) {
+                    watchdog_disarm();
+                }
+                rv = 0;
+                break;
+            }
+            rv = orig_ioctl(fd, request, va_arg(ap, int *));
+            break;
+        case WDIOC_GETSUPPORT:
+            rv = orig_ioctl(fd, request, va_arg(ap, struct watchdog_info *));
+            break;
+        default:
+            fprintf(log_fp, "ioctl using unknown request = 0x%08lx", request);
+            rv = orig_ioctl(fd, request, va_arg(ap, void *));
+    }
+    va_end(ap);
+
+    return rv;
+}
+
+int
+close(int fd)
+{
+    int i;
+
+    init();
+
+    if (fd == watchdog_device_fd) {
+        watchdog_device_fd = -1;
+    } else {
+        for (i = 0; i < 3; i++) {
+            if (sbd_device_fd[i] == fd) {
+                sbd_device_fd[i] = -1;
+                break;
+            }
+        }
+    }
+    return orig_close(fd);
+}
+
+// ***** end - handling of watchdog & block-devices ****
+
+// ***** handling of sysrq, sysrq-trigger & reboot ****
+
+FILE *
+fopen(const char *pathname, const char *mode)
+{
+    int is_sysrq = 0;
+    int is_sysrq_trigger = 0;
+    FILE *fp;
+
+    init();
+
+    if ((strcmp("/proc/sys/kernel/sysrq", pathname) == 0) &&
+        strcmp("w", mode)) {
+        pathname = "/dev/null";
+        is_sysrq = 1;
+    } else if (strcmp("/proc/sysrq-trigger", pathname) == 0) {
+        pathname = "/dev/null";
+        is_sysrq_trigger = 1;
+    }
+    fp = orig_fopen(pathname, mode);
+    if (is_sysrq) {
+        sysrq_fp = fp;
+    } else if (is_sysrq_trigger) {
+        sysrq_trigger_fp = fp;
+    }
+    return fp;
+}
+
+int
+fclose(FILE *fp)
+{
+    init();
+
+    if (fp == sysrq_fp) {
+        sysrq_fp = NULL;
+    } else if (fp == sysrq_trigger_fp) {
+        sysrq_trigger_fp = NULL;
+    }
+    return orig_fclose(fp);
+}
+
+#if defined(__USE_FORTIFY_LEVEL) && (__USE_FORTIFY_LEVEL > 1)
+int
+__fprintf_chk(FILE *stream, int flag, const char *format, ...)
+#else
+int
+fprintf(FILE *stream, const char *format, ...)
+#endif
+{
+    va_list ap;
+    int rv;
+
+    init();
+    va_start (ap, format);
+    if (stream == sysrq_trigger_fp) {
+        char buf[256];
+
+        rv = vsnprintf(buf, sizeof(buf), format, ap);
+        if (rv >= 1) {
+            fprintf(log_fp, "sysrq-trigger ('%c') - %s\n", buf[0],
+                    (buf[0] == 'c')?"killing process group":"don't kill but 
wait for reboot-call");
+            if (buf[0] == 'c') {
+                fclose(log_fp);
+                log_fp = NULL;
+                killpg(0, SIGKILL);
+                exit(1);
+            }
+        }
+    } else {
+        rv = vfprintf(stream, format, ap);
+    }
+    va_end (ap);
+    return rv;
+}
+
+int
+fscanf(FILE *stream, const char *format, ...)
+{
+    va_list ap;
+    int rv;
+
+    init();
+    va_start (ap, format);
+    rv = vfscanf(stream, format, ap);
+    va_end (ap);
+    return rv;
+}
+
+int
+reboot (int __howto)
+{
+    fprintf(log_fp, "reboot (%s) - exiting inquisitor process\n",
+            (__howto == RB_POWER_OFF)?"poweroff":"reboot");
+    fclose(log_fp);
+    log_fp = NULL;
+    killpg(0, SIGKILL);
+    exit(1);
+}
+
+// ***** end - handling of sysrq, sysrq-trigger & reboot ****
+
+// ***** aio translate ****
+
+#if 0
+struct iocb {
+    void *data;
+    unsigned key;
+    short aio_lio_opcode;
+    short aio_reqprio;
+    int aio_fildes;
+};
+
+static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t 
count, long long offset)
+{
+       memset(iocb, 0, sizeof(*iocb));
+       iocb->aio_fildes = fd;
+       iocb->aio_lio_opcode = IO_CMD_PREAD;
+       iocb->aio_reqprio = 0;
+       iocb->u.c.buf = buf;
+       iocb->u.c.nbytes = count;
+       iocb->u.c.offset = offset;
+}
+
+static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t 
count, long long offset)
+{
+       memset(iocb, 0, sizeof(*iocb));
+       iocb->aio_fildes = fd;
+       iocb->aio_lio_opcode = IO_CMD_PWRITE;
+       iocb->aio_reqprio = 0;
+       iocb->u.c.buf = buf;
+       iocb->u.c.nbytes = count;
+       iocb->u.c.offset = offset;
+}
+#endif
+
+int io_setup(int nr_events, io_context_t *ctx_idp)
+{
+    init();
+
+    if (!translate_aio) {
+        return orig_io_setup(nr_events, ctx_idp);
+    }
+
+    if (nr_events == 0) {
+        return EINVAL;
+    }
+    if (nr_events > 1) {
+        return EAGAIN;
+    }
+    if (ctx_idp == NULL) {
+        return EFAULT;
+    }
+    *ctx_idp = &our_io_context;
+    return 0;
+}
+
+
+int io_submit(io_context_t ctx_id, long nr, struct iocb *ios[])
+{
+    init();
+
+    if (!translate_aio) {
+        return orig_io_submit(ctx_id, nr, ios);
+    }
+
+    if ((pending_iocb != NULL) ||
+        (nr > 1)) {
+        return EAGAIN;
+    }
+    if ((nr == 1) && ((ios == NULL) || (ios[0] == NULL))) {
+        return EFAULT;
+    }
+    if ((ctx_id != &our_io_context) ||
+        (nr < 0) ||
+        ((nr == 1) &&
+         (ios[0]->aio_lio_opcode != IO_CMD_PREAD) &&
+         (ios[0]->aio_lio_opcode != IO_CMD_PWRITE))) {
+        return EINVAL;
+    }
+    if ((fcntl(ios[0]->aio_fildes, F_GETFD) == -1) && (errno == EBADF)) {
+        return EBADF;
+    }
+    if (nr == 1) {
+        pending_iocb = ios[0];
+    }
+    return nr;
+}
+
+int io_getevents(io_context_t ctx_id, long min_nr, long nr,
+                        struct io_event *events, struct timespec *timeout)
+{
+    init();
+
+    if (!translate_aio) {
+        return orig_io_getevents(ctx_id, min_nr, nr, events, timeout);
+    }
+
+    if ((ctx_id != &our_io_context) ||
+        (min_nr != 1) ||
+        (nr != 1)) {
+        return EINVAL;
+    }
+    if (pending_iocb == NULL) {
+        return 0;
+    }
+
+       switch (pending_iocb->aio_lio_opcode) {
+               case IO_CMD_PWRITE:
+                       events->res = pwrite(pending_iocb->aio_fildes,
+                                                               
pending_iocb->u.c.buf,
+                                                               
pending_iocb->u.c.nbytes,
+                                                               
pending_iocb->u.c.offset);
+                       break;
+               case IO_CMD_PREAD:
+                       events->res = pread(pending_iocb->aio_fildes,
+                                                               
pending_iocb->u.c.buf,
+                                                               
pending_iocb->u.c.nbytes,
+                                                               
pending_iocb->u.c.offset);
+                       break;
+               default:
+                       events->res = 0;
+       }
+
+    events->data = pending_iocb->data;
+    events->obj  = pending_iocb;
+
+    events->res2  = 0;
+    pending_iocb = NULL;
+    return 1;
+}
+
+int io_cancel(io_context_t ctx_id, struct iocb *iocb,
+                     struct io_event *result)
+{
+    init();
+
+    if (!translate_aio) {
+        return orig_io_cancel(ctx_id, iocb, result);
+    }
+
+    if (ctx_id != &our_io_context) {
+        return EINVAL;
+    }
+    if ((iocb == NULL) || (result == NULL)) {
+        return EFAULT;
+    }
+    if (pending_iocb != iocb) {
+        return EAGAIN;
+    }
+    result->data = iocb->data;
+    result->obj  = iocb;
+    result->res  = 0;
+    result->res2  = 0;
+    pending_iocb = NULL;
+    return 0;
+}
+
+// ***** end - aio translate ****


Reply via email to