[systemd-devel] [PATCH REPOST 4/4] WIP: add basic watchdog daemon

Michael Olbrich m.olbrich at pengutronix.de
Thu Jan 5 07:00:28 PST 2012


This patch introduces a small watchdog daemon that supervises systemd
and handles /dev/watchdog. This is mostly a prove of concept for now.
---
 Makefile.am                        |   22 ++++-
 src/99-systemd.rules.in            |    2 +
 src/watchdogd.c                    |  178 ++++++++++++++++++++++++++++++++++++
 units/systemd-watchdogd.service.in |   16 +++
 4 files changed, 216 insertions(+), 2 deletions(-)
 create mode 100644 src/watchdogd.c
 create mode 100644 units/systemd-watchdogd.service.in

diff --git a/Makefile.am b/Makefile.am
index 7eea06f..3a72a34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -194,7 +194,9 @@ rootlibexec_PROGRAMS = \
 	systemd-timestamp \
 	systemd-ac-power \
 	systemd-detect-virt \
-	systemd-sysctl
+	systemd-sysctl \
+	systemd-watchdogd
+
 
 systemgenerator_PROGRAMS = \
 	systemd-getty-generator
@@ -330,6 +332,7 @@ nodist_systemunit_DATA = \
 	units/systemd-ask-password-wall.service \
 	units/systemd-ask-password-console.service \
 	units/systemd-sysctl.service \
+	units/systemd-watchdogd.service \
 	units/halt.service \
 	units/poweroff.service \
 	units/reboot.service \
@@ -364,6 +367,7 @@ EXTRA_DIST += \
 	units/systemd-ask-password-wall.service.in \
 	units/systemd-ask-password-console.service.in \
 	units/systemd-sysctl.service.in \
+	units/systemd-watchdogd.service.in \
 	units/halt.service.in \
 	units/poweroff.service.in \
 	units/reboot.service.in \
@@ -939,6 +943,19 @@ systemctl_LDADD = \
 	libsystemd-journal.la \
 	$(DBUS_LIBS)
 
+systemd_watchdogd_SOURCES = \
+	src/watchdogd.c \
+	src/dbus-common.c
+
+systemd_watchdogd_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(DBUS_CFLAGS)
+
+systemd_watchdogd_LDADD = \
+	libsystemd-basic.la \
+	libsystemd-daemon.la \
+	$(DBUS_LIBS)
+
 systemd_notify_SOURCES = \
 	src/notify.c \
 	src/readahead/sd-readahead.c
@@ -2274,7 +2291,8 @@ systemd-install-data-hook:
 		$(LN_S) ../systemd-kmsg-syslogd.service )
 	( cd $(DESTDIR)$(systemunitdir)/basic.target.wants && \
 		rm -f systemd-tmpfiles-clean.timer && \
-		$(LN_S) ../systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.timer )
+		$(LN_S) ../systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.timer && \
+		$(LN_S) ../systemd-watchdogd.service systemd-watchdogd.service )
 	( cd $(DESTDIR)$(dbussessionservicedir) && \
 		rm -f org.freedesktop.systemd1.service && \
 		$(LN_S) ../system-services/org.freedesktop.systemd1.service org.freedesktop.systemd1.service )
diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in
index d306f71..8cb9e41 100644
--- a/src/99-systemd.rules.in
+++ b/src/99-systemd.rules.in
@@ -12,6 +12,8 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*", TAG+="systemd"
 
 KERNEL=="vport*", TAG+="systemd"
 
+KERNEL=="watchdog", TAG+="systemd"
+
 SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd"
 SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
 
diff --git a/src/watchdogd.c b/src/watchdogd.c
new file mode 100644
index 0000000..269f42e
--- /dev/null
+++ b/src/watchdogd.c
@@ -0,0 +1,178 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Michael Olbrich
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <linux/watchdog.h>
+
+#include "log.h"
+#include "util.h"
+#include "dbus-common.h"
+#include "sd-daemon.h"
+
+static int timeout = 10;
+static usec_t reset_delay_usec = 10 * USEC_PER_SEC;
+
+static int help(void) {
+
+        printf("%s [OPTIONS...]\n\n"
+               "Handles /dev/watchdog and monitors systemd to check when a hardware\n"
+               "reset is necessary\n\n"
+               "  -h --help               Show this help\n"
+               "  -T --timeout=TIMEOUT    Watchdog timeout in seconds\n"
+               "  -R --reset-delay=REBOOT The amount of time systemd get to reboot\n"
+               "                          the system gracefully in seconds\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        static const struct option options[] = {
+                { "help",        no_argument,       NULL, 'h' },
+                { "timeout",     required_argument, NULL, 'T' },
+                { "reset-delay", required_argument, NULL, 'R' },
+                { NULL,          0,                 NULL, 0   }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "+hT:R:", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case 'T':
+                        timeout = atoi(optarg);
+                        break;
+
+                case 'R':
+                        reset_delay_usec = atoi(optarg) * USEC_PER_SEC;
+                        break;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        help();
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
+int main(int argc, char *argv[]) {
+        int fd, ret;
+        struct timespec ts;
+        DBusConnection *bus = NULL;
+        DBusMessage *m, *reply = NULL;
+        DBusError error;
+        DBusMessageIter iter, sub;
+        usec_t watchdog_usec, now_usec;
+        const char *iface = "org.freedesktop.systemd1.Manager";
+        const char *property = "WatchdogRebootTimestampMonotonic";
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        if ((ret = parse_argv(argc, argv)) <= 0)
+                return ret;
+
+        umask(0022);
+
+        dbus_error_init(&error);
+
+        if ((ret = bus_connect(DBUS_BUS_SYSTEM, &bus, NULL, &error)) < 0) {
+                log_error("Failed to get D-Bus connection: %s", bus_error_message(&error));
+                return 1;
+        }
+        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.DBus.Properties", "Get"))) {
+                log_error("Could not allocate message.");
+                return 1;
+        }
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &iface,
+                                      DBUS_TYPE_STRING, &property,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach target and flag information to message.");
+                return 1;
+        }
+
+        if ((fd = open("/dev/watchdog", O_RDWR)) < 0) {
+                log_error("Could not open /dev/watchdog: %s", strerror(errno));
+                return 1;
+        }
+
+        if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) < 0) {
+                log_error("Failed to set watchdog timeout: %s", strerror(errno));
+                return 1;
+        }
+        log_info("Watchdog timeout set to %ds", timeout);
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Watchdog started.");
+
+        timeout /= 2;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        while (true) {
+                now_usec = timespec_load(&ts);
+                clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, 0);
+                ts.tv_sec += timeout;
+
+                if (reply)
+                        dbus_message_unref(reply);
+
+                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                        log_error("Error fetching reboot timestamp: %s", bus_error_message(&error));
+                        continue;
+                }
+                if (!dbus_message_iter_init(reply, &iter)) {
+                        log_error("Failed to parse reply (init).");
+                        continue;
+                }
+                dbus_message_iter_recurse(&iter, &sub);
+                if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT64, &watchdog_usec, false) < 0) {
+                        log_error("Failed to parse reply (value).");
+                        continue;
+                }
+                if (watchdog_usec && ((watchdog_usec + reset_delay_usec) < now_usec)) {
+                        log_error("Reboot failed: now = %llu, watchdog = %llu", now_usec, watchdog_usec);
+                        continue;
+                }
+                ioctl(fd, WDIOC_KEEPALIVE, 0);
+        }
+
+
+}
diff --git a/units/systemd-watchdogd.service.in b/units/systemd-watchdogd.service.in
new file mode 100644
index 0000000..643b3da
--- /dev/null
+++ b/units/systemd-watchdogd.service.in
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Watchdog Daemon
+DefaultDependencies=no
+BindTo=dev-watchdog.device
+After=dev-watchdog.device
+
+[Service]
+Type=notify
+ExecStart=@rootlibexecdir@/systemd-watchdogd
-- 
1.7.7.3



More information about the systemd-devel mailing list