From 378472a4375759dc0c73cbe54f87847b724f06ef Mon Sep 17 00:00:00 2001 From: Alex Hornung Date: Sun, 4 Oct 2009 11:27:36 +0100 Subject: [PATCH] watchdogd - Import from OpenBSD * Because the wdog kernel part was designed to be mostly compatible with OpenBSD's API, we can import watchdogd from OpenBSD and just change a bunch of things. Obtained-from: OpenBSD --- usr.sbin/watchdogd/Makefile | 12 +++ usr.sbin/watchdogd/watchdogd.8 | 95 ++++++++++++++++++ usr.sbin/watchdogd/watchdogd.c | 171 +++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 usr.sbin/watchdogd/Makefile create mode 100644 usr.sbin/watchdogd/watchdogd.8 create mode 100644 usr.sbin/watchdogd/watchdogd.c diff --git a/usr.sbin/watchdogd/Makefile b/usr.sbin/watchdogd/Makefile new file mode 100644 index 0000000000..aafe94fa61 --- /dev/null +++ b/usr.sbin/watchdogd/Makefile @@ -0,0 +1,12 @@ +# $OpenBSD: mickey $ + +PROG= watchdogd +SRCS= watchdogd.c + +CFLAGS+= -Wall +LINTFLAGS+= -u -z +LDSTATIC= ${STATIC} + +MAN= watchdogd.8 + +.include diff --git a/usr.sbin/watchdogd/watchdogd.8 b/usr.sbin/watchdogd/watchdogd.8 new file mode 100644 index 0000000000..01b8640f80 --- /dev/null +++ b/usr.sbin/watchdogd/watchdogd.8 @@ -0,0 +1,95 @@ +.\" $OpenBSD: jmc $ +.\" +.\" Copyright (c) 2005 Marc Balmer +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt WATCHDOGD 8 +.Os +.Sh NAME +.Nm watchdogd +.Nd watchdog timer retrigger daemon +.Sh SYNOPSIS +.Nm watchdogd +.Op Fl dnq +.Op Fl i Ar interval +.Op Fl p Ar period +.Sh DESCRIPTION +.Nm +is a daemon to activate and periodically retrigger the +.Xr watchdog 4 +timer device from userland. +.Nm +is designed to work in high load environments, +where other methods +(such as a shell script invoking +.Xr sysctl 8 ) +would involve too much overhead. +.Pp +The basic premise is that +after every +.Ar interval +seconds, +.Nm +resets the hardware timer to +.Ar period . +See also +.Xr watchdog 4 +for more information on how watchdog timers work. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Do not daemonize. +If this option is specified, +.Nm +will run in the foreground. +.It Fl i Ar interval +Specify how often, in seconds, +.Nm +should retrigger the hardware timer. +If no interval is specified, +the value of +.Ar period +(see below) +divided by three is used. +.It Fl n +Do not restore the watchdog to its original values once it has been activated. +With this set, the system will be rebooted by the watchdog even after a +.Xr halt 8 . +.It Fl p Ar period +Set the hardware timer to expire in +.Ar period +seconds. +The default is 30 seconds. +.It Fl q +Be quiet. +With this option specified, +.Nm +will not output a warning message if the underlying hardware adjusted the +timeout period. +.El +.Sh SEE ALSO +.Xr watchdog 4 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +program +first appeared in +.Ox 3.8 . +.Sh AUTHORS +.Nm +was written by +.An Marc Balmer Aq mbalmer@openbsd.org . diff --git a/usr.sbin/watchdogd/watchdogd.c b/usr.sbin/watchdogd/watchdogd.c new file mode 100644 index 0000000000..9893b562fb --- /dev/null +++ b/usr.sbin/watchdogd/watchdogd.c @@ -0,0 +1,171 @@ +/* $OpenBSD: sthen $ */ + +/* + * Copyright (c) 2005 Marc Balmer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +volatile sig_atomic_t quit = 0; + +__dead void usage(void); +void sighdlr(int); +int main(int, char *[]); + +__dead void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-dnq] [-i interval] [-p period]\n", + __progname); + exit(1); +} + +/* ARGSUSED */ +void +sighdlr(int signum) +{ + quit = 1; +} + +int +main(int argc, char *argv[]) +{ + struct rlimit rlim; + const char *errstr; + size_t len; + u_int interval = 0, period = 30, nperiod; + int ch, trigauto, sauto, speriod; + int quiet = 0, daemonize = 1, retval = 1, do_restore = 1; + int mib[3]; + + while ((ch = getopt(argc, argv, "di:np:q")) != -1) { + switch (ch) { + case 'd': + daemonize = 0; + break; + case 'i': + interval = (u_int)strtonum(optarg, 1LL, 86400LL, + &errstr); + if (errstr) + errx(1, "interval is %s: %s", errstr, optarg); + break; + case 'n': + do_restore = 0; + break; + case 'p': + period = (u_int)strtonum(optarg, 2LL, 86400LL, &errstr); + if (errstr) + errx(1, "period is %s: %s", errstr, optarg); + break; + case 'q': + quiet = 1; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc > 0) + usage(); + + if (interval == 0 && (interval = period / 3) == 0) + interval = 1; + + if (period <= interval) + errx(1, "retrigger interval too long"); + + /* save kern.watchdog.period and kern.watchdog.auto for restore */ + mib[0] = CTL_KERN; + mib[1] = KERN_WATCHDOG; + mib[2] = KERN_WATCHDOG_PERIOD; + + len = sizeof(speriod); + if (sysctl(mib, 3, &speriod, &len, &period, sizeof(period)) == -1) { + if (errno == EOPNOTSUPP) + errx(1, "no watchdog timer available"); + else + err(1, "can't access kern.watchdog.period"); + } + + mib[2] = KERN_WATCHDOG_AUTO; + len = sizeof(sauto); + trigauto = 0; + + if (sysctl(mib, 3, &sauto, &len, &trigauto, sizeof(trigauto)) == -1) + err(1, "can't access kern.watchdog.auto"); + + /* Double check the timeout period, some devices change the value */ + mib[2] = KERN_WATCHDOG_PERIOD; + len = sizeof(nperiod); + if (sysctl(mib, 3, &nperiod, &len, NULL, 0) == -1) { + warnx("can't read back kern.watchdog.period, " + "restoring original values"); + goto restore; + } + + if (nperiod != period && !quiet) + warnx("period adjusted to %d by device", nperiod); + + if (nperiod <= interval) { + warnx("retrigger interval %d too long, " + "restoring original values", interval); + goto restore; + } + + if (daemonize && daemon(0, 0)) { + warn("can't daemonize, restoring original values"); + goto restore; + } + + /* + * mlockall() below will wire the whole stack up to the limit + * thus we have to reduce stack size to avoid resource abuse + */ + rlim.rlim_cur = 256 * 1024; + rlim.rlim_max = 256 * 1024; + (void)setrlimit(RLIMIT_STACK, &rlim); + + (void)mlockall(MCL_CURRENT | MCL_FUTURE); + setpriority(PRIO_PROCESS, getpid(), -5); + + signal(SIGTERM, sighdlr); + + retval = 0; + while (!quit) { + if (sysctl(mib, 3, NULL, 0, &period, sizeof(period)) == -1) + quit = retval = 1; + sleep(interval); + } + + if (do_restore) { +restore: sysctl(mib, 3, NULL, 0, &speriod, sizeof(speriod)); + mib[2] = KERN_WATCHDOG_AUTO; + sysctl(mib, 3, NULL, 0, &sauto, sizeof(sauto)); + } + + return retval; +} -- 2.41.0