[Debian-ha-commits] [sbd] 01/09: New upstream version 1.3.1

Valentin Vidic vvidic-guest at moszumanska.debian.org
Thu Nov 9 10:41:26 UTC 2017


This is an automated email from the git hooks/post-receive script.

vvidic-guest pushed a commit to branch master
in repository sbd.

commit 0c55a699f0dfed929568d947b7dbf1f29494cea7
Author: Valentin Vidic <Valentin.Vidic at CARNet.hr>
Date:   Wed Nov 8 21:16:08 2017 +0100

    New upstream version 1.3.1
---
 .travis.yml               |  25 ++++
 agent/{sbd => sbd.in}     |   6 +-
 configure.ac              |  27 +++-
 man/sbd.8.pod             |   7 +-
 sbd.spec                  |  14 +-
 src/sbd-cluster.c         | 166 ++++++++++++++++++++--
 src/sbd-common.c          | 346 +++++++++++++++++++++++++++++++++++++++++-----
 src/sbd-inquisitor.c      | 122 ++++++++++------
 src/sbd-md.c              |  58 +++-----
 src/sbd.h                 |  14 +-
 src/sbd.service.in        |   4 +-
 src/{sbd.sh => sbd.sh.in} |   2 +-
 src/sbd_remote.service.in |   8 +-
 tests/regressions.sh      |   5 +-
 14 files changed, 653 insertions(+), 151 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bae79a9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,25 @@
+sudo: required
+language: c
+
+env:
+  global:
+    - DOCKER_BUILD_IMAGE=alectolytic/rpmbuilder
+    - OS_ARCH=x86_64
+    - PACKAGE=sbd
+  matrix:
+    - OS_TYPE=centos OS_DIST=epel OS_VERSION=7
+    - OS_TYPE=centos OS_DIST=epel OS_VERSION=6
+
+services:
+  - docker
+
+install: true
+
+script:
+  - make -f Makefile.am spec export PACKAGE=${PACKAGE}
+  - docker pull ${DOCKER_BUILD_IMAGE}:${OS_TYPE}-${OS_VERSION}
+  - docker run -v ${PWD}:/sources -v ${PWD}:/output ${DOCKER_BUILD_IMAGE}:${OS_TYPE}-${OS_VERSION}
+  - ls ${PWD}/sbd*.${OS_ARCH}.rpm
+  - docker pull ${OS_TYPE}:${OS_TYPE}${OS_VERSION}
+  - docker run --privileged -v ${PWD}:/rpms -v ${PWD}/tests:/tests ${OS_TYPE}:${OS_TYPE}${OS_VERSION} /bin/bash -c "yum install -y device-mapper /rpms/${PACKAGE}*.${OS_ARCH}.rpm && /tests/regressions.sh && touch /rpms/regressions.sh.SUCCESS"
+  - ls ${PWD}/regressions.sh.SUCCESS
diff --git a/agent/sbd b/agent/sbd.in
similarity index 97%
rename from agent/sbd
rename to agent/sbd.in
index 5645213..4bc0245 100644
--- a/agent/sbd
+++ b/agent/sbd.in
@@ -22,8 +22,8 @@
 # Main code
 
 if [ -z "$sbd_device" ]; then
-	if [ -f /etc/sysconfig/sbd ]; then
-		source /etc/sysconfig/sbd
+	if [ -f @CONFIGDIR@/sbd ]; then
+		source @CONFIGDIR@/sbd
 		sbd_device=$SBD_DEVICE
 	fi
 fi
@@ -150,7 +150,7 @@ The block device used for the SBD partition. Up to three
 can be specified if separated by a semicolon. (Please check
 the documentation if specifying two.)
 
-If not specified, will default to the value from /etc/sysconfig/sbd.
+If not specified, will default to the value from @CONFIGDIR@/sbd.
 
 </longdesc>
 </parameter>
diff --git a/configure.ac b/configure.ac
index a7e3e70..1eb8758 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ dnl     checks for library functions
 dnl     checks for system services
 
 AC_INIT([sbd], 
-	[1.3.0],
+	[1.3.1],
 	[lmb at suse.com])
 AC_CANONICAL_HOST
 AC_CONFIG_AUX_DIR(.)
@@ -32,6 +32,8 @@ AM_PROG_CC_C_O
 PKG_CHECK_MODULES(glib, [glib-2.0])
 dnl PKG_CHECK_MODULES(libcoroipcc, [libcoroipcc])
 
+PKG_CHECK_MODULES(cmap, [libcmap], HAVE_cmap=1, HAVE_cmap=0)
+
 dnl pacemaker > 1.1.8
 PKG_CHECK_MODULES(pacemaker, [pacemaker, pacemaker-cib], HAVE_pacemaker=1, HAVE_pacemaker=0)
 
@@ -44,6 +46,11 @@ if test $HAVE_pacemaker = 0 -a $HAVE_pcmk = 0; then
     AC_MSG_ERROR(No package 'pacemaker' found)
 elif test $HAVE_pacemaker = 1; then
     CPPFLAGS="$CPPFLAGS $glib_CFLAGS $pacemaker_CFLAGS"
+    if test $HAVE_cmap = 0; then
+        AC_MSG_NOTICE(No package 'cmap' found)
+    else
+	CPPFLAGS="$CPPFLAGS $cmap_CFLAGS"
+    fi
 fi
 
 PKG_CHECK_MODULES(libxml, [libxml-2.0])
@@ -58,6 +65,7 @@ AC_CHECK_LIB(pe_status, pe_find_node, , missing="yes")
 AC_CHECK_LIB(pe_rules, test_rule, , missing="yes")
 AC_CHECK_LIB(crmcluster, crm_peer_init, , missing="yes")
 AC_CHECK_LIB(uuid, uuid_unparse, , missing="yes")
+AC_CHECK_LIB(cmap, cmap_initialize, , HAVE_cmap=0)
 
 dnl pacemaker >= 1.1.8
 AC_CHECK_HEADERS(pacemaker/crm/cluster.h)
@@ -89,6 +97,16 @@ then
 	AC_DEFINE_UNQUOTED(HAVE_PROC_PID, 1, Define to 1 if /proc/{pid} is supported.)
 fi
 
+AC_DEFINE_UNQUOTED(CHECK_TWO_NODE, $HAVE_cmap, Turn on checking for 2-node cluster)
+AM_CONDITIONAL(CHECK_TWO_NODE, test "$HAVE_cmap" = "1")
+
+CONFIGDIR=""
+AC_ARG_WITH(configdir,
+    [  --with-configdir=DIR
+       Directory for SBD configuration file [${CONFIGDIR}]],
+    [ CONFIGDIR="$withval" ]
+)
+
 dnl **********************************************************************
 dnl Check for various argv[] replacing functions on various OSs
 dnl
@@ -202,8 +220,13 @@ eval oldincludedir="`eval echo ${oldincludedir}`"
 eval infodir="`eval echo ${infodir}`"
 eval mandir="`eval echo ${mandir}`"
 
+if test x"${CONFIGDIR}" = x""; then
+    CONFIGDIR="${sysconfdir}/sysconfig"
+fi
+AC_SUBST(CONFIGDIR)
+
 dnl The Makefiles and shell scripts we output
-AC_CONFIG_FILES([Makefile src/Makefile agent/Makefile man/Makefile src/sbd.service src/sbd_remote.service])
+AC_CONFIG_FILES([Makefile src/Makefile agent/Makefile man/Makefile agent/sbd src/sbd.service src/sbd_remote.service src/sbd.sh])
 
 dnl Now process the entire list of files added by previous 
 dnl  calls to AC_CONFIG_FILES()
diff --git a/man/sbd.8.pod b/man/sbd.8.pod
index b410a27..c1bf67a 100644
--- a/man/sbd.8.pod
+++ b/man/sbd.8.pod
@@ -62,7 +62,7 @@ Enable some verbose debug logging.
 
 Display a concise summary of C<sbd> options.
 
-=item B<-c> I<node>
+=item B<-n> I<node>
 
 Set local node name; defaults to C<uname -n>. This should not need to be
 set.
@@ -267,7 +267,10 @@ If set to zero, processes will be restarted indefinitely and immediately.
 
 =item B<-P>
 
-Check Pacemaker quorum and node health.
+Enable Pacemaker integration which checks Pacemaker quorum and node health.
+Specify this once to enable, twice to disable.
+
+Defaults to I<enabled>.
 
 =item B<-S> I<N>
 
diff --git a/sbd.spec b/sbd.spec
index e643c53..e016579 100644
--- a/sbd.spec
+++ b/sbd.spec
@@ -15,7 +15,7 @@
 
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
-%global commit 4ee36fa33b57a1ad95678363911cfb02a92e1edb
+%global commit a180176c23e57ee904ebb08ab449cfb3d90a0383
 %global shortcommit %(c=%{commit}; echo ${c:0:7})
 %global github_owner beekhof
 %global buildnum 1
@@ -24,7 +24,7 @@ Name:           sbd
 Summary:        Storage-based death
 License:        GPLv2+
 Group:          System Environment/Daemons
-Version:        1.3.0
+Version:        1.3.1
 Release:        0.%{buildnum}.%{shortcommit}.git%{?dist}
 Url:            https://github.com/%{github_owner}/%{name}
 Source0:        https://github.com/%{github_owner}/%{name}/archive/%{commit}/%{name}-%{commit}.tar.gz
@@ -41,6 +41,7 @@ BuildRequires:  libuuid-devel
 BuildRequires:  libxml2-devel
 BuildRequires:  pkgconfig
 BuildRequires:  python-devel
+BuildRequires:  make
 
 %if 0%{?rhel} > 0
 ExclusiveArch: i686 x86_64 s390x
@@ -113,6 +114,15 @@ rm -rf %{buildroot}
 %doc COPYING
 
 %changelog
+* Fri Nov  3 2017 <klaus.wenninger at aon.at> - 1.3.1-0.1.a180176c.git
+- Add commands to test/query watchdogs
+- Allow 2-node-operation with a single shared-disk
+- Overhaul of the command-line options & config-file
+- Proper handling of off instead of reboot
+- Refactored disk-servant for more robust communication with parent
+- Fix config for Debian + configurable location of config
+- Fixes in sbd.sh - multiple SBD devices and others
+
 * Sun Mar 26 2016 <klaus.wenninger at aon.at> - 1.3.0-0.1.4ee36fa3.git
 - Changes since v1.2.0 like adding the possibility to have a
   watchdog-only setup without shared-block-devices
diff --git a/src/sbd-cluster.c b/src/sbd-cluster.c
index 0ed56e7..de99d0c 100644
--- a/src/sbd-cluster.c
+++ b/src/sbd-cluster.c
@@ -33,6 +33,10 @@
 #include <crm/cluster.h>
 #include <crm/common/mainloop.h>
 
+#if CHECK_TWO_NODE
+#include <glib-unix.h>
+#endif
+
 #include "sbd.h"
 
 //undef SUPPORT_PLUGIN
@@ -48,6 +52,7 @@ static gboolean sbd_remote_check(gpointer user_data);
 static long unsigned int find_pacemaker_remote(void);
 static void sbd_membership_destroy(gpointer user_data);
 
+
 #if SUPPORT_PLUGIN
 static void
 sbd_plugin_membership_dispatch(cpg_handle_t handle,
@@ -67,6 +72,55 @@ sbd_plugin_membership_dispatch(cpg_handle_t handle,
 #endif
 
 #if SUPPORT_COROSYNC
+
+static bool two_node = false;
+static bool ever_seen_both = false;
+static int cpg_membership_entries = -1;
+
+#if CHECK_TWO_NODE
+#include <corosync/cmap.h>
+
+static cmap_handle_t cmap_handle = 0;
+static cmap_track_handle_t track_handle = 0;
+static GSource *cmap_source = NULL;
+#endif
+
+void
+sbd_cpg_membership_health_update()
+{
+    if(cpg_membership_entries > 0) {
+        bool quorum_is_suspect =
+            (two_node && ever_seen_both && cpg_membership_entries == 1);
+
+        if (!quorum_is_suspect) {
+            set_servant_health(pcmk_health_online, LOG_INFO,
+                           "Connected to %s (%u members)",
+                           name_for_cluster_type(get_cluster_type()),
+                           cpg_membership_entries
+                          );
+        } else {
+            /* Alternative would be asking votequorum for number of votes.
+             * Using pacemaker's cpg as source for number of active nodes
+             * avoids binding to an additional library, is definitely
+             * less code to write and we wouldn't have to combine data
+             * from 3 sources (cmap, cpq & votequorum) in a potentially
+             * racy environment.
+             */
+            set_servant_health(pcmk_health_noquorum, LOG_WARNING,
+                           "Connected to %s but requires both nodes present",
+                           name_for_cluster_type(get_cluster_type())
+                          );
+        }
+
+        if (cpg_membership_entries > 1) {
+            ever_seen_both = true;
+        }
+    } else {
+        set_servant_health(pcmk_health_unclean, LOG_WARNING,
+                           "Empty %s membership", name_for_cluster_type(get_cluster_type()));
+    }
+}
+
 void
 sbd_cpg_membership_dispatch(cpg_handle_t handle,
                     const struct cpg_name *groupName,
@@ -74,16 +128,104 @@ sbd_cpg_membership_dispatch(cpg_handle_t handle,
                     const struct cpg_address *left_list, size_t left_list_entries,
                     const struct cpg_address *joined_list, size_t joined_list_entries)
 {
-    if(member_list_entries > 0) {
-        set_servant_health(pcmk_health_online, LOG_INFO,
-                           "Connected to %s", name_for_cluster_type(get_cluster_type()));
+    cpg_membership_entries = member_list_entries;
+    sbd_cpg_membership_health_update();
+    notify_parent();
+}
+
+#if CHECK_TWO_NODE
+static void sbd_cmap_notify_fn(
+    cmap_handle_t cmap_handle,
+    cmap_track_handle_t cmap_track_handle,
+    int32_t event,
+    const char *key_name,
+    struct cmap_notify_value new_val,
+    struct cmap_notify_value old_val,
+    void *user_data)
+{
+    if (new_val.type == CMAP_VALUETYPE_UINT8) {
+        switch (event) {
+            case CMAP_TRACK_ADD:
+            case CMAP_TRACK_MODIFY:
+                two_node = *((uint8_t *) new_val.data);
+                break;
+            case CMAP_TRACK_DELETE:
+                two_node = false;
+                break;
+            default:
+                return;
+        }
+        sbd_cpg_membership_health_update();
+        notify_parent();
+    }
+}
+
+static gboolean
+cmap_dispatch_callback (gpointer user_data)
+{
+    cmap_dispatch(cmap_handle, CS_DISPATCH_ALL);
+    return TRUE;
+}
+
+static gboolean
+sbd_get_two_node(void)
+{
+    uint8_t two_node_u8 = 0;
+    int cmap_fd;
+
+    if (!track_handle) {
+        if (cmap_initialize(&cmap_handle) != CS_OK) {
+            cl_log(LOG_WARNING, "Cannot initialize CMAP service\n");
+            goto out;
+        }
+
+        if (cmap_track_add(cmap_handle, "quorum.two_node",
+                            CMAP_TRACK_DELETE|CMAP_TRACK_MODIFY|CMAP_TRACK_ADD,
+                            sbd_cmap_notify_fn, NULL, &track_handle) != CS_OK) {
+            cl_log(LOG_WARNING, "Failed adding CMAP tracker for 2Node-mode\n");
+            goto out;
+        }
+
+        /* add the tracker to mainloop */
+        if (cmap_fd_get(cmap_handle, &cmap_fd) != CS_OK) {
+            cl_log(LOG_WARNING, "Failed to get a file handle for cmap\n");
+            goto out;
+        }
+
+        if (!(cmap_source = g_unix_fd_source_new (cmap_fd, G_IO_IN))) {
+            cl_log(LOG_WARNING, "Couldn't create source for cmap\n");
+            goto out;
+        }
+        g_source_set_callback(cmap_source, cmap_dispatch_callback, NULL, NULL);
+        g_source_attach(cmap_source, NULL);
+    }
+
+    if (cmap_get_uint8(cmap_handle, "quorum.two_node", &two_node_u8) == CS_OK) {
+        cl_log(LOG_NOTICE, "Corosync is%s in 2Node-mode", two_node_u8?"":" not");
+        two_node = two_node_u8;
     } else {
-        set_servant_health(pcmk_health_unclean, LOG_WARNING,
-                           "Empty %s membership", name_for_cluster_type(get_cluster_type()));
+        cl_log(LOG_NOTICE, "quorum.two_node present in cmap\n");
     }
-    notify_parent();
+    return TRUE;
+
+out:
+    if (cmap_source) {
+        g_source_destroy(cmap_source);
+        cmap_source = NULL;
+    }
+    if (track_handle) {
+        cmap_track_delete(cmap_handle, track_handle);
+        track_handle = 0;
+    }
+    if (cmap_handle) {
+        cmap_finalize(cmap_handle);
+        cmap_handle = 0;
+    }
+
+    return FALSE;
 }
 #endif
+#endif
 
 static gboolean
 notify_timer_cb(gpointer data)
@@ -143,9 +285,17 @@ sbd_membership_connect(void)
         } else {
             cl_log(LOG_INFO, "Attempting connection to %s", name_for_cluster_type(stack));
 
-            if(crm_cluster_connect(&cluster)) {
-                connected = true;
+#if SUPPORT_COROSYNC && CHECK_TWO_NODE
+            if (sbd_get_two_node()) {
+#endif
+
+                if(crm_cluster_connect(&cluster)) {
+                    connected = true;
+                }
+
+#if SUPPORT_COROSYNC && CHECK_TWO_NODE
             }
+#endif
         }
 
         if(connected == false) {
diff --git a/src/sbd-common.c b/src/sbd-common.c
index 0f3fd62..803bc3a 100644
--- a/src/sbd-common.c
+++ b/src/sbd-common.c
@@ -19,7 +19,10 @@
 #include "sbd.h"
 #include <sys/reboot.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <pwd.h>
+#include <unistd.h>
+#include <dirent.h>
 
 #ifdef _POSIX_MEMLOCK
 #  include <sys/mman.h>
@@ -46,6 +49,7 @@ int	skip_rt			= 0;
 int	debug			= 0;
 int	debug_mode		= 0;
 char *watchdogdev		= NULL;
+bool watchdogdev_is_default = false;
 char *	local_uname;
 
 /* Global, non-tunable variables: */
@@ -102,35 +106,53 @@ usage(void)
 "		Writes the specified message to node's slot.\n"
 #endif
 "watch		Loop forever, monitoring own slot\n"
+"query-watchdog	Check for available watchdog-devices and print some info\n"
+"test-watchdog	Test the watchdog-device selected.\n"
+"		Attention: This will arm the watchdog and have your system reset\n"
+"		           in case your watchdog is working properly!\n"
                 , cmdname);
 }
 
+static int
+watchdog_init_interval_fd(int wdfd, int timeout)
+{
+	if (ioctl(wdfd, WDIOC_SETTIMEOUT, &timeout) < 0) {
+		cl_perror( "WDIOC_SETTIMEOUT"
+				": Failed to set watchdog timer to %u seconds.",
+				timeout);
+		cl_log(LOG_CRIT, "Please validate your watchdog configuration!");
+		cl_log(LOG_CRIT, "Choose a different watchdog driver or specify -T to skip this if you are completely sure.");
+		return -1;
+	}
+	return 0;
+}
+
 int
 watchdog_init_interval(void)
 {
-	int     timeout = timeout_watchdog;
-
 	if (watchdogfd < 0) {
 		return 0;
 	}
 
-
 	if (watchdog_set_timeout == 0) {
 		cl_log(LOG_INFO, "NOT setting watchdog timeout on explicit user request!");
 		return 0;
 	}
 
-	if (ioctl(watchdogfd, WDIOC_SETTIMEOUT, &timeout) < 0) {
-		cl_perror( "WDIOC_SETTIMEOUT"
-				": Failed to set watchdog timer to %u seconds.",
-				timeout);
-		cl_log(LOG_CRIT, "Please validate your watchdog configuration!");
-		cl_log(LOG_CRIT, "Choose a different watchdog driver or specify -T to skip this if you are completely sure.");
+	if (watchdog_init_interval_fd(watchdogfd, timeout_watchdog) < 0) {
 		return -1;
-	} else {
-		cl_log(LOG_INFO, "Set watchdog timeout to %u seconds.",
-				timeout);
 	}
+	cl_log(LOG_INFO, "Set watchdog timeout to %u seconds.", (int) timeout_watchdog);
+	return 0;
+}
+
+static int
+watchdog_tickle_fd(int wdfd, char *wddev)
+{
+	if (write(wdfd, "", 1) != 1) {
+			cl_perror("Watchdog write failure: %s!", wddev);
+			return -1;
+		}
 	return 0;
 }
 
@@ -138,67 +160,284 @@ int
 watchdog_tickle(void)
 {
 	if (watchdogfd >= 0) {
-		if (write(watchdogfd, "", 1) != 1) {
-			cl_perror("Watchdog write failure: %s!",
-					watchdogdev);
+		return watchdog_tickle_fd(watchdogfd, watchdogdev);
+	}
+	return 0;
+}
+
+static int
+watchdog_init_fd(char *wddev, int timeout)
+{
+	int wdfd;
+
+	wdfd = open(wddev, O_WRONLY);
+	if (wdfd >= 0) {
+		if (((timeout >= 0) && (watchdog_init_interval_fd(wdfd, timeout) < 0))
+					|| (watchdog_tickle_fd(wdfd, wddev) < 0)) {
+			close(wdfd);
 			return -1;
 		}
+	} else {
+		cl_perror("Cannot open watchdog device '%s'", wddev);
+		return -1;
 	}
-	return 0;
+	return wdfd;
 }
 
 int
 watchdog_init(void)
 {
 	if (watchdogfd < 0 && watchdogdev != NULL) {
-		watchdogfd = open(watchdogdev, O_WRONLY);
+		int timeout = timeout_watchdog;
+
+		if (watchdog_set_timeout == 0) {
+			cl_log(LOG_INFO, "NOT setting watchdog timeout on explicit user request!");
+			timeout = -1;
+		}
+		watchdogfd = watchdog_init_fd(watchdogdev, timeout);
 		if (watchdogfd >= 0) {
 			cl_log(LOG_NOTICE, "Using watchdog device '%s'", watchdogdev);
-			if ((watchdog_init_interval() < 0)
-					|| (watchdog_tickle() < 0)) {
-				return -1;
+			if (watchdog_set_timeout) {
+				cl_log(LOG_INFO, "Set watchdog timeout to %u seconds.", (int) timeout_watchdog);
 			}
-		}else{
-			cl_perror("Cannot open watchdog device '%s'", watchdogdev);
+		} else {
 			return -1;
 		}
 	}
 	return 0;
 }
 
-void
-watchdog_close(bool disarm)
+static void
+watchdog_close_fd(int wdfd, char *wddev, bool disarm)
 {
-    if (watchdogfd < 0) {
-        return;
-    }
-
     if (disarm) {
         int r;
         int flags = WDIOS_DISABLECARD;;
 
         /* Explicitly disarm it */
-        r = ioctl(watchdogfd, WDIOC_SETOPTIONS, &flags);
+        r = ioctl(wdfd, WDIOC_SETOPTIONS, &flags);
         if (r < 0) {
-            cl_perror("Failed to disable hardware watchdog %s", watchdogdev);
+            cl_perror("Failed to disable hardware watchdog %s", wddev);
         }
 
         /* To be sure, use magic close logic, too */
         for (;;) {
-            if (write(watchdogfd, "V", 1) > 0) {
+            if (write(wdfd, "V", 1) > 0) {
                 break;
             }
-            cl_perror("Cannot disable watchdog device %s", watchdogdev);
+            cl_perror("Cannot disable watchdog device %s", wddev);
         }
     }
 
-    if (close(watchdogfd) < 0) {
-        cl_perror("Watchdog close(%d) failed", watchdogfd);
+    if (close(wdfd) < 0) {
+        cl_perror("Watchdog close(%d) failed", wdfd);
     }
+}
 
+void
+watchdog_close(bool disarm)
+{
+    if (watchdogfd < 0) {
+        return;
+    }
+
+    watchdog_close_fd(watchdogfd, watchdogdev, disarm);
     watchdogfd = -1;
 }
 
+#define MAX_WATCHDOGS 64
+#define SYS_CLASS_WATCHDOG "/sys/class/watchdog"
+#define SYS_CHAR_DEV_DIR "/sys/dev/char"
+#define WATCHDOG_NODEDIR "/dev"
+
+struct watchdog_list_item {
+	dev_t dev;
+	char *dev_node;
+	char *dev_ident;
+	char *dev_driver;
+	struct watchdog_list_item *next;
+};
+
+static struct watchdog_list_item *watchdog_list = NULL;
+static int watchdog_list_items = 0;
+
+static void
+watchdog_populate_list(void)
+{
+	dev_t watchdogs[MAX_WATCHDOGS + 1] =
+		{makedev(10,130), 0};
+	int num_watchdogs = 1;
+	struct dirent *entry;
+	char entry_name[64];
+	DIR *dp;
+	char buf[256] = "";
+
+	if (watchdog_list != NULL) {
+		return;
+	}
+
+	/* get additional devices from /sys/class/watchdog */
+	dp = opendir(SYS_CLASS_WATCHDOG);
+	if (dp) {
+		while ((entry = readdir(dp))) {
+			if (entry->d_type == DT_LNK) {
+				FILE *file;
+
+				snprintf(entry_name, sizeof(entry_name),
+						SYS_CLASS_WATCHDOG "/%s/dev", entry->d_name);
+				file = fopen(entry_name, "r");
+				if (file) {
+					int major, minor;
+
+					if (fscanf(file, "%d:%d", &major, &minor) == 2) {
+						watchdogs[num_watchdogs++] = makedev(major, minor);
+					}
+					fclose(file);
+					if (num_watchdogs == MAX_WATCHDOGS) {
+						break;
+					}
+				}
+			}
+		}
+		closedir(dp);
+	}
+
+	/* search for watchdog nodes in /dev */
+	dp = opendir(WATCHDOG_NODEDIR);
+	if (dp) {
+		while ((entry = readdir(dp))) {
+			if ((entry->d_type == DT_CHR) || (entry->d_type == DT_LNK)) {
+				struct stat statbuf;
+
+				snprintf(entry_name, sizeof(entry_name),
+						WATCHDOG_NODEDIR "/%s", entry->d_name);
+				if(!stat(entry_name, &statbuf) && S_ISCHR(statbuf.st_mode)) {
+					int i;
+
+					for (i=0; i<num_watchdogs; i++) {
+						if (statbuf.st_rdev == watchdogs[i]) {
+							int wdfd = watchdog_init_fd(entry_name, -1);
+							struct watchdog_list_item *wdg =
+									calloc(1, sizeof(struct watchdog_list_item));
+
+							wdg->dev = watchdogs[i];
+							wdg->dev_node = strdup(entry_name);
+							wdg->next = watchdog_list;
+							watchdog_list = wdg;
+							watchdog_list_items++;
+
+							if (wdfd >= 0) {
+								struct watchdog_info ident;
+
+								ident.identity[0] = '\0';
+								ioctl(wdfd, WDIOC_GETSUPPORT, &ident);
+								watchdog_close_fd(wdfd, entry_name, true);
+								if (ident.identity[0]) {
+									wdg->dev_ident = strdup((char *) ident.identity);
+								}
+							}
+
+							snprintf(entry_name, sizeof(entry_name),
+								SYS_CHAR_DEV_DIR "/%d:%d/device/driver",
+								major(watchdogs[i]), minor(watchdogs[i]));
+							if (readlink(entry_name, buf, sizeof(buf)) > 0) {
+								wdg->dev_driver = strdup(basename(buf));
+							} else if ((wdg->dev_ident) &&
+										(strcmp(wdg->dev_ident,
+												"Software Watchdog") == 0)) {
+								wdg->dev_driver = strdup("softdog");
+							}
+							break;
+						}
+					}
+				}
+			}
+		}
+		closedir(dp);
+	}
+}
+
+int watchdog_info(void)
+{
+	struct watchdog_list_item *wdg;
+	int wdg_cnt = 0;
+
+	watchdog_populate_list();
+	printf("\nDiscovered %d watchdog devices:\n", watchdog_list_items);
+	for (wdg = watchdog_list; wdg != NULL; wdg = wdg->next) {
+		wdg_cnt++;
+		printf("\n[%d] %s\nIdentity: %s\nDriver: %s\n",
+				wdg_cnt, wdg->dev_node,
+				wdg->dev_ident?wdg->dev_ident:"Error: Check if hogged by e.g. sbd-daemon!",
+				wdg->dev_driver?wdg->dev_driver:"<unknown>");
+		if ((wdg->dev_driver) && (strcmp(wdg->dev_driver, "softdog") == 0)) {
+			printf("CAUTION: Not recommended for use with sbd.\n"); 
+		}
+	}
+
+	return 0;
+}
+
+int watchdog_test(void)
+{
+	int i;
+
+	if ((watchdog_set_timeout == 0) || !watchdog_use) {
+		printf("\nWatchdog is disabled - aborting test!!!\n");
+		return 0;
+	}
+	if (watchdogdev_is_default) {
+		watchdog_populate_list();
+		if (watchdog_list_items > 1) {
+			printf("\nError: Multiple watchdog devices discovered.\n"
+				   "       Use -w <watchdog> or SBD_WATCHDOG_DEV to specify\n"
+				   "       which device to reset the system with\n");
+			watchdog_info();
+			return -1;
+		}
+	}
+	if ((isatty(fileno(stdin)))) {
+		char buffer[16];
+		printf("\nWARNING: This operation is expected to force-reboot this system\n"
+			   "         without following any shutdown procedures.\n\n"
+			   "Proceed? [NO/Proceed] ");
+
+		if ((fgets(buffer, 16, stdin) == NULL) ||
+			strcmp(buffer, "Proceed\n")) {
+			printf("\nAborting watchdog test!!!\n");
+			return 0;
+		}
+		printf("\n");
+	}
+	printf("Initializing %s with a reset countdown of %d seconds ...\n",
+		watchdogdev, (int) timeout_watchdog);
+	if ((watchdog_init() < 0) || (watchdog_init_interval() < 0)) {
+		printf("Failed to initialize watchdog!!!\n");
+		return -1;
+	}
+	printf("\n");
+	printf("NOTICE: The watchdog device is expected to reset the system\n"
+		   "        in %d seconds.  If system remains active beyond that time,\n"
+		   "        watchdog may not be functional.\n\n", (int) timeout_watchdog);
+	for (i=timeout_watchdog; i>1; i--) {
+		printf("Reset countdown ... %d seconds\n", i);
+		sleep(1);
+	}
+	for (i=2; i>0; i--) {
+		printf("System expected to reset any moment ...\n");
+		sleep(1);
+	}
+	for (i=5; i>0; i--) {
+		printf("System should have reset ...\n");
+		sleep(1);
+	}
+	printf("Error: The watchdog device has failed to reboot the system,\n"
+		   "       and it may not be suitable for usage with sbd.\n");
+
+	/* test should trigger a reboot thus returning is actually bad */
+	return -1;
+}
+
 /* This duplicates some code from linux/ioprio.h since these are not included
  * even in linux-kernel-headers. Sucks. See also
  * /usr/src/linux/Documentation/block/ioprio.txt and ioprio_set(2) */
@@ -487,10 +726,8 @@ do_exit(char kind)
     } else {
         watchdog_close(false);
         sysrq_trigger(kind);
-        if (kind != 'o') {
-            if(reboot(RB_AUTOBOOT) < 0) {
-                cl_perror("Reboot failed");
-            }
+        if (reboot((kind == 'o')?RB_POWER_OFF:RB_AUTOBOOT) < 0) {
+            cl_perror("%s failed", (kind == 'o')?"Poweroff":"Reboot");
         }
     }
 
@@ -696,3 +933,36 @@ set_servant_health(enum pcmk_health state, int level, char const *format, ...)
         free(string);
     }
 }
+
+bool
+sbd_is_disk(struct servants_list_item *servant)
+{
+    if ((servant != NULL) &&
+        (servant->devname != NULL) &&
+        (servant->devname[0] == '/')) {
+        return true;
+    }
+    return false;
+}
+
+bool
+sbd_is_cluster(struct servants_list_item *servant)
+{
+    if ((servant != NULL) &&
+        (servant->devname != NULL) &&
+        (strcmp("cluster", servant->devname) == 0)) {
+        return true;
+    }
+    return false;
+}
+
+bool
+sbd_is_pcmk(struct servants_list_item *servant)
+{
+    if ((servant != NULL) &&
+        (servant->devname != NULL) &&
+        (strcmp("pcmk", servant->devname) == 0)) {
+        return true;
+    }
+    return false;
+}
diff --git a/src/sbd-inquisitor.c b/src/sbd-inquisitor.c
index 3c3a5a0..59408b3 100644
--- a/src/sbd-inquisitor.c
+++ b/src/sbd-inquisitor.c
@@ -23,8 +23,8 @@
 static struct servants_list_item *servants_leader = NULL;
 
 int     disk_priority = 1;
-int	check_pcmk = 0;
-int	check_cluster = 0;
+int	check_pcmk = 1;
+int	check_cluster = 1;
 int	disk_count	= 0;
 int	servant_count	= 0;
 int	servant_restart_interval = 5;
@@ -34,17 +34,6 @@ char*	pidfile = NULL;
 
 int parse_device_line(const char *line);
 
-bool
-sbd_is_disk(struct servants_list_item *servant) 
-{
-    if (servant == NULL
-        || servant->devname == NULL
-        || servant->devname[0] == '/') {
-        return true;
-    }
-    return false;
-}
-
 void recruit_servant(const char *devname, pid_t pid)
 {
 	struct servants_list_item *s = servants_leader;
@@ -162,11 +151,11 @@ void servant_start(struct servants_list_item *s)
                 cl_log(LOG_ERR, "Shared disk functionality not supported");
                 return;
 #endif
-	} else if(strcmp("pcmk", s->devname) == 0) {
+	} else if(sbd_is_pcmk(s)) {
 		DBGLOG(LOG_INFO, "Starting Pacemaker servant");
 		s->pid = assign_servant(s->devname, servant_pcmk, start_mode, NULL);
 
-	} else if(strcmp("cluster", s->devname) == 0) {
+	} else if(sbd_is_cluster(s)) {
 		DBGLOG(LOG_INFO, "Starting Cluster servant");
 		s->pid = assign_servant(s->devname, servant_cluster, start_mode, NULL);
 
@@ -401,7 +390,7 @@ int cluster_alive(bool all)
     }
 
     for (s = servants_leader; s; s = s->next) {
-        if (sbd_is_disk(s) == false) {
+        if (sbd_is_cluster(s) || sbd_is_pcmk(s)) {
             if(s->outdated) {
                 alive = 0;
             } else if(all == false) {
@@ -454,7 +443,6 @@ void inquisitor_child(void)
 	sigaddset(&procmask, SIG_LIVENESS);
 	sigaddset(&procmask, SIG_EXITREQ);
 	sigaddset(&procmask, SIG_TEST);
-	sigaddset(&procmask, SIG_IO_FAIL);
 	sigaddset(&procmask, SIG_PCMK_UNHEALTHY);
 	sigaddset(&procmask, SIG_RESTART);
 	sigaddset(&procmask, SIGUSR1);
@@ -485,28 +473,44 @@ void inquisitor_child(void)
 				if (pid == -1 && errno == ECHILD) {
 					break;
 				} else {
+					s = lookup_servant_by_pid(pid);
+					if (sbd_is_disk(s)) {
+						if (WIFEXITED(status)) {
+							switch(WEXITSTATUS(status)) {
+								case EXIT_MD_IO_FAIL:
+									DBGLOG(LOG_INFO, "Servant for %s requests to be disowned",
+										s->devname);
+									break;
+								case EXIT_MD_REQUEST_RESET:
+									cl_log(LOG_WARNING, "%s requested a reset", s->devname);
+									do_reset();
+									break;
+								case EXIT_MD_REQUEST_SHUTOFF:
+									cl_log(LOG_WARNING, "%s requested a shutoff", s->devname);
+									do_off();
+									break;
+								case EXIT_MD_REQUEST_CRASHDUMP:
+									cl_log(LOG_WARNING, "%s requested a crashdump", s->devname);
+									do_crashdump();
+									break;
+								default:
+									break;
+							}
+						}
+					}
 					cleanup_servant_by_pid(pid);
 				}
 			}
 		} else if (sig == SIG_PCMK_UNHEALTHY) {
 			s = lookup_servant_by_pid(sinfo.si_pid);
-			if (sbd_is_disk(s)) {
-				cl_log(LOG_WARNING, "Ignoring SIG_PCMK_UNHEALTHY from unknown source");
-
-                        } else {
-                            if(s->outdated == 0) {
-                                cl_log(LOG_WARNING, "%s health check: UNHEALTHY", s->devname);
-                            }
-                            s->t_last.tv_sec = 1;
-			}
-
-		} else if (sig == SIG_IO_FAIL) {
-			s = lookup_servant_by_pid(sinfo.si_pid);
-			if (s) {
-				DBGLOG(LOG_INFO, "Servant for %s requests to be disowned",
-						s->devname);
-				cleanup_servant_by_pid(sinfo.si_pid);
-			}
+			if (sbd_is_cluster(s) || sbd_is_pcmk(s)) {
+                if (s->outdated == 0) {
+                    cl_log(LOG_WARNING, "%s health check: UNHEALTHY", s->devname);
+                }
+                s->t_last.tv_sec = 1;
+            } else {
+                cl_log(LOG_WARNING, "Ignoring SIG_PCMK_UNHEALTHY from unknown source");
+            }
 		} else if (sig == SIG_LIVENESS) {
 			s = lookup_servant_by_pid(sinfo.si_pid);
 			if (s) {
@@ -799,11 +803,19 @@ parse_device_line(const char *line)
     return found;
 }
 
+int
+arg_enabled(int arg_count)
+{
+    return arg_count % 2;
+}
+
 int main(int argc, char **argv, char **envp)
 {
 	int exit_status = 0;
 	int c;
-	int w = 0;
+	int W_count = 0;
+	int c_count = 0;
+	int P_count = 0;
         int qb_facility;
         const char *value = NULL;
         int start_delay = 0;
@@ -815,6 +827,7 @@ int main(int argc, char **argv, char **envp)
 	}
 
         watchdogdev = strdup("/dev/watchdog");
+        watchdogdev_is_default = true;
         qb_facility = qb_log_facility2int("daemon");
         qb_log_init(cmdname, qb_facility, LOG_WARNING);
         sbd_set_format_string(QB_LOG_SYSLOG, "sbd");
@@ -860,6 +873,14 @@ int main(int argc, char **argv, char **envp)
         if(value) {
             free(watchdogdev);
             watchdogdev = strdup(value);
+            watchdogdev_is_default = false;
+        }
+
+        /* SBD_WATCHDOG has been dropped from sbd.sysconfig example.
+         * This is for backward compatibility. */
+        value = getenv("SBD_WATCHDOG");
+        if(value) {
+            watchdog_use = crm_is_true(value);
         }
 
         value = getenv("SBD_WATCHDOG_TIMEOUT");
@@ -921,12 +942,13 @@ int main(int argc, char **argv, char **envp)
 			cl_log(LOG_INFO, "Setting watchdog timeout disabled; using defaults.");
 			break;
 		case 'W':
-			w++;
+			W_count++;
 			break;
 		case 'w':
                         cl_log(LOG_NOTICE, "Using watchdog device '%s'", watchdogdev);
                         free(watchdogdev);
                         watchdogdev = strdup(optarg);
+                        watchdogdev_is_default = false;
 			break;
 		case 'd':
 #if SUPPORT_SHARED_DISK
@@ -938,10 +960,10 @@ int main(int argc, char **argv, char **envp)
 #endif
 			break;
 		case 'c':
-			check_cluster = 1;
+			c_count++;
 			break;
 		case 'P':
-			check_pcmk = 1;
+			P_count++;
 			break;
 		case 'z':
 			disk_priority = 0;
@@ -1004,11 +1026,11 @@ int main(int argc, char **argv, char **envp)
 		}
 	}
 
-	if (w > 0) {
-            watchdog_use = w % 2;
-
-	} else if(watchdogdev == NULL || strcmp(watchdogdev, "/dev/null") == 0) {
+	if (watchdogdev == NULL || strcmp(watchdogdev, "/dev/null") == 0) {
             watchdog_use = 0;
+
+	} else if (W_count > 0) {
+            watchdog_use = arg_enabled(W_count);
         }
 
 	if (watchdog_use) {
@@ -1017,6 +1039,14 @@ int main(int argc, char **argv, char **envp)
 		cl_log(LOG_INFO, "Watchdog disabled.");
 	}
 
+	if (c_count > 0) {
+		check_cluster = arg_enabled(c_count);
+	}
+
+	if (P_count > 0) {
+		check_pcmk = arg_enabled(P_count);
+	}
+
 	if ((disk_count > 0) && (strlen(local_uname) > SECTOR_NAME_MAX)) {
 		fprintf(stderr, "Node name mustn't be longer than %d chars.\n",
 			SECTOR_NAME_MAX);
@@ -1079,8 +1109,12 @@ int main(int argc, char **argv, char **envp)
 		exit_status = -2;
 	}
 #endif
-        
-        if (strcmp(argv[optind], "watch") == 0) {
+
+        if (strcmp(argv[optind], "query-watchdog") == 0) {
+            exit_status = watchdog_info();
+        } else if (strcmp(argv[optind], "test-watchdog") == 0) {
+            exit_status = watchdog_test();
+        } else if (strcmp(argv[optind], "watch") == 0) {
             /* sleep $(sbd $SBD_DEVICE_ARGS dump | grep -m 1 msgwait | awk '{print $4}') 2>/dev/null */
 
                 /* We only want this to have an effect during watch right now;
diff --git a/src/sbd-md.c b/src/sbd-md.c
index 10b1925..54ac580 100644
--- a/src/sbd-md.c
+++ b/src/sbd-md.c
@@ -29,7 +29,6 @@
 #define MBOX_TO_SECTOR(mbox) (2+mbox*2)
 
 extern int disk_count;
-static int servant_inform_parent = 0;
 
 /* These have to match the values in the header of the partition */
 static char		sbd_magic[8] = "SBD_SBD_";
@@ -833,7 +832,7 @@ int ping_via_slots(const char *name, struct servants_list_item *servants)
 					break;
 				} else {
 					s = lookup_servant_by_pid(pid);
-					if (s && sbd_is_disk(s)) {
+					if (sbd_is_disk(s)) {
 						servants_finished++;
 					}
 				}
@@ -1025,20 +1024,6 @@ static int servant_check_timeout_inconsistent(struct sector_header_s *hdr)
 	return 0;
 }
 
-/* This is a bit hackish, but the easiest way to rewire all process
- * exits to send the desired signal to the parent. */
-void servant_exit(void)
-{
-	pid_t ppid;
-	union sigval signal_value;
-
-	ppid = getppid();
-	if (servant_inform_parent) {
-		memset(&signal_value, 0, sizeof(signal_value));
-		sigqueue(ppid, SIG_IO_FAIL, signal_value);
-	}
-}
-
 int servant(const char *diskname, int mode, const void* argp)
 {
 	struct sector_mbox_s *s_mbox = NULL;
@@ -1072,24 +1057,21 @@ int servant(const char *diskname, int mode, const void* argp)
 	/* FIXME: check error */
 	sigprocmask(SIG_SETMASK, &servant_masks, NULL);
 
-	atexit(servant_exit);
-	servant_inform_parent = 1;
-
 	st = open_device(diskname, LOG_WARNING);
 	if (!st) {
-		return -1;
+		exit(EXIT_MD_IO_FAIL);
 	}
 
 	s_header = header_get(st);
 	if (!s_header) {
 		cl_log(LOG_ERR, "Not a valid header on %s", diskname);
-		return -1;
+		exit(EXIT_MD_IO_FAIL);
 	}
 
 	if (servant_check_timeout_inconsistent(s_header) < 0) {
 		cl_log(LOG_ERR, "Timeouts on %s do not match first device",
 				diskname);
-		return -1;
+		exit(EXIT_MD_IO_FAIL);
 	}
 
 	if (s_header->minor_version > 0) {
@@ -1102,14 +1084,14 @@ int servant(const char *diskname, int mode, const void* argp)
 		cl_log(LOG_ERR,
 		       "No slot allocated, and automatic allocation failed for disk %s.",
 		       diskname);
-		rc = -1;
+		rc = EXIT_MD_IO_FAIL;
 		goto out;
 	}
 	s_node = sector_alloc();
 	if (slot_read(st, mbox, s_node) < 0) {
 		cl_log(LOG_ERR, "Unable to read node entry on %s",
 				diskname);
-		exit(1);
+		exit(EXIT_MD_IO_FAIL);
 	}
 
 	DBGLOG(LOG_INFO, "Monitoring slot %d on disk %s", mbox, diskname);
@@ -1125,7 +1107,7 @@ int servant(const char *diskname, int mode, const void* argp)
 		if (mode > 0) {
 			if (mbox_read(st, mbox, s_mbox) < 0) {
 				cl_log(LOG_ERR, "mbox read failed during start-up in servant.");
-				rc = -1;
+				rc = EXIT_MD_IO_FAIL;
 				goto out;
 			}
 			if (s_mbox->cmd != SBD_MSG_EXIT &&
@@ -1141,7 +1123,7 @@ int servant(const char *diskname, int mode, const void* argp)
 		DBGLOG(LOG_INFO, "First servant start - zeroing inbox");
 		memset(s_mbox, 0, sizeof(*s_mbox));
 		if (mbox_write(st, mbox, s_mbox) < 0) {
-			rc = -1;
+			rc = EXIT_MD_IO_FAIL;
 			goto out;
 		}
 	}
@@ -1170,28 +1152,28 @@ int servant(const char *diskname, int mode, const void* argp)
 		s_header_retry = header_get(st);
 		if (!s_header_retry) {
 			cl_log(LOG_ERR, "No longer found a valid header on %s", diskname);
-			exit(1);
+			exit(EXIT_MD_IO_FAIL);
 		}
 		if (memcmp(s_header, s_header_retry, sizeof(*s_header)) != 0) {
 			cl_log(LOG_ERR, "Header on %s changed since start-up!", diskname);
-			exit(1);
+			exit(EXIT_MD_IO_FAIL);
 		}
 		free(s_header_retry);
 
 		s_node_retry = sector_alloc();
 		if (slot_read(st, mbox, s_node_retry) < 0) {
 			cl_log(LOG_ERR, "slot read failed in servant.");
-			exit(1);
+			exit(EXIT_MD_IO_FAIL);
 		}
 		if (memcmp(s_node, s_node_retry, sizeof(*s_node)) != 0) {
 			cl_log(LOG_ERR, "Node entry on %s changed since start-up!", diskname);
-			exit(1);
+			exit(EXIT_MD_IO_FAIL);
 		}
 		free(s_node_retry);
 
 		if (mbox_read(st, mbox, s_mbox) < 0) {
 			cl_log(LOG_ERR, "mbox read failed in servant.");
-			exit(1);
+			exit(EXIT_MD_IO_FAIL);
 		}
 
 		if (s_mbox->cmd > 0) {
@@ -1206,17 +1188,14 @@ int servant(const char *diskname, int mode, const void* argp)
 				sigqueue(ppid, SIG_TEST, signal_value);
 				break;
 			case SBD_MSG_RESET:
-				do_reset();
-				break;
+				exit(EXIT_MD_REQUEST_RESET);
 			case SBD_MSG_OFF:
-				do_off();
-				break;
+				exit(EXIT_MD_REQUEST_SHUTOFF);
 			case SBD_MSG_EXIT:
 				sigqueue(ppid, SIG_EXITREQ, signal_value);
 				break;
 			case SBD_MSG_CRASHDUMP:
-				do_crashdump();
-				break;
+				exit(EXIT_MD_REQUEST_CRASHDUMP);
 			default:
 				/* FIXME:
 				   An "unknown" message might result
@@ -1247,10 +1226,7 @@ int servant(const char *diskname, int mode, const void* argp)
  out:
 	free(s_mbox);
 	close_device(st);
-	if (rc == 0) {
-		servant_inform_parent = 0;
-	}
-	return rc;
+	exit(rc);
 }
 
 
diff --git a/src/sbd.h b/src/sbd.h
index 07a476d..0f8847a 100644
--- a/src/sbd.h
+++ b/src/sbd.h
@@ -50,10 +50,15 @@
 #define SIG_EXITREQ  (SIGRTMIN + 2)	/* exit request to inquisitor */
 #define SIG_TEST     (SIGRTMIN + 3)	/* trigger self test */
 #define SIG_RESTART  (SIGRTMIN + 4)	/* trigger restart of all failed disk */
-#define SIG_IO_FAIL  (SIGRTMIN + 5)	/* the IO child requests to be considered failed */
-#define SIG_PCMK_UNHEALTHY  (SIGRTMIN + 6)
+#define SIG_PCMK_UNHEALTHY  (SIGRTMIN + 5)
 /* FIXME: should add dynamic check of SIG_XX >= SIGRTMAX */
 
+/* exit status for disk-servant */
+#define EXIT_MD_IO_FAIL             20
+#define EXIT_MD_REQUEST_RESET       21
+#define EXIT_MD_REQUEST_SHUTOFF     22
+#define EXIT_MD_REQUEST_CRASHDUMP   23
+
 #define HOG_CHAR	0xff
 #define SECTOR_NAME_MAX 63
 
@@ -119,6 +124,8 @@ int watchdog_tickle(void);
 int watchdog_init(void);
 void sysrq_init(void);
 void watchdog_close(bool disarm);
+int watchdog_info(void);
+int watchdog_test(void);
 void sysrq_trigger(char t);
 void do_crashdump(void);
 void do_reset(void);
@@ -144,6 +151,7 @@ extern int  skip_rt;
 extern int  debug;
 extern int  debug_mode;
 extern char *watchdogdev;
+extern bool watchdogdev_is_default;
 extern char*  local_uname;
 
 /* Global, non-tunable variables: */
@@ -191,3 +199,5 @@ extern int servant_health;
 void set_servant_health(enum pcmk_health state, int level, char const *format, ...) __attribute__ ((__format__ (__printf__, 3, 4)));
 
 bool sbd_is_disk(struct servants_list_item *servant);
+bool sbd_is_pcmk(struct servants_list_item *servant);
+bool sbd_is_cluster(struct servants_list_item *servant);
diff --git a/src/sbd.service.in b/src/sbd.service.in
index a7f4e7f..ef1bd16 100644
--- a/src/sbd.service.in
+++ b/src/sbd.service.in
@@ -9,8 +9,8 @@ RefuseManualStart=true
 [Service]
 Type=forking
 PIDFile=@localstatedir@/run/sbd.pid
-EnvironmentFile=- at sysconfdir@/sysconfig/sbd
-ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch 
+EnvironmentFile=- at CONFIGDIR@/sbd
+ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch
 ExecStop=@bindir@/kill -TERM $MAINPID
 
 # Could this benefit from exit codes for restart?
diff --git a/src/sbd.sh b/src/sbd.sh.in
similarity index 98%
rename from src/sbd.sh
rename to src/sbd.sh.in
index 35b0e92..386f89b 100644
--- a/src/sbd.sh
+++ b/src/sbd.sh.in
@@ -17,7 +17,7 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 #
 
-SBD_CONFIG=/etc/sysconfig/sbd
+SBD_CONFIG=@CONFIGDIR@/sbd
 SBD_BIN="/usr/sbin/sbd"
 
 test -x $SBD_BIN || exit 1
diff --git a/src/sbd_remote.service.in b/src/sbd_remote.service.in
index 73eaa89..e05f80e 100644
--- a/src/sbd_remote.service.in
+++ b/src/sbd_remote.service.in
@@ -7,10 +7,10 @@ RefuseManualStart=true
 
 [Service]
 Type=forking
-PIDFile=/var/run/sbd.pid
-EnvironmentFile=-/etc/sysconfig/sbd
-ExecStart=/usr/sbin/sbd $SBD_OPTS -p /var/run/sbd.pid watch
-ExecStop=/usr/bin/kill -TERM $MAINPID
+PIDFile=@localstatedir@/run/sbd.pid
+EnvironmentFile=- at CONFIGDIR@/sbd
+ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch
+ExecStop=@bindir@/kill -TERM $MAINPID
 
 # Could this benefit from exit codes for restart?
 # Does this need to be set to msgwait * 1.2?
diff --git a/tests/regressions.sh b/tests/regressions.sh
index 9db1c15..4c531ae 100755
--- a/tests/regressions.sh
+++ b/tests/regressions.sh
@@ -36,6 +36,7 @@ sbd_setup() {
 		losetup ${L[$N]} ${F[$N]}
 		D[$N]="/dev/mapper/sbd_$N"
 		dmsetup create sbd_$N --table "0 2048 linear ${L[$N]} 0"
+		dmsetup mknodes sbd_$N
 	done
 }
 
@@ -63,7 +64,7 @@ _ok() {
 	rc=$?
 	if [ $rc -ne 0 ]; then
 		echo "$@ failed with $rc"
-		exit
+		exit $rc
 	fi
 }
 
@@ -73,7 +74,7 @@ _no() {
 	rc=$?
 	if [ $rc -eq 0 ]; then
 		echo "$@ did NOT fail ($rc)"
-		exit
+		exit $rc
 	fi
 	return 0
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-ha/sbd.git



More information about the Debian-HA-Commits mailing list