[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