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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel