1*5b133f3fSguenther /* $OpenBSD: watchdogd.c,v 1.16 2023/03/08 04:43:15 guenther Exp $ */
21469ed6eSmbalmer
31469ed6eSmbalmer /*
4a9c1aa39Smbalmer * Copyright (c) 2005 Marc Balmer <mbalmer@openbsd.org>
51469ed6eSmbalmer *
61469ed6eSmbalmer * Permission to use, copy, modify, and distribute this software for any
71469ed6eSmbalmer * purpose with or without fee is hereby granted, provided that the above
81469ed6eSmbalmer * copyright notice and this permission notice appear in all copies.
91469ed6eSmbalmer *
101469ed6eSmbalmer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111469ed6eSmbalmer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121469ed6eSmbalmer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131469ed6eSmbalmer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141469ed6eSmbalmer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151469ed6eSmbalmer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161469ed6eSmbalmer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171469ed6eSmbalmer */
181469ed6eSmbalmer
19b9fc9a72Sderaadt #include <sys/types.h>
20991f7995Smillert #include <sys/resource.h>
21b9fc9a72Sderaadt #include <sys/signal.h>
221469ed6eSmbalmer #include <sys/sysctl.h>
231469ed6eSmbalmer #include <sys/mman.h>
241469ed6eSmbalmer
251469ed6eSmbalmer #include <err.h>
261469ed6eSmbalmer #include <errno.h>
271469ed6eSmbalmer #include <stdio.h>
281469ed6eSmbalmer #include <stdlib.h>
291469ed6eSmbalmer #include <unistd.h>
301469ed6eSmbalmer
311469ed6eSmbalmer volatile sig_atomic_t quit = 0;
321469ed6eSmbalmer
33de70259aShenning __dead void usage(void);
34de70259aShenning void sighdlr(int);
35de70259aShenning int main(int, char *[]);
36de70259aShenning
371469ed6eSmbalmer __dead void
usage(void)381469ed6eSmbalmer usage(void)
391469ed6eSmbalmer {
401469ed6eSmbalmer extern char *__progname;
411469ed6eSmbalmer
4217046616Smbalmer fprintf(stderr, "usage: %s [-dnq] [-i interval] [-p period]\n",
431469ed6eSmbalmer __progname);
441469ed6eSmbalmer exit(1);
451469ed6eSmbalmer }
461469ed6eSmbalmer
471469ed6eSmbalmer void
sighdlr(int signum)481469ed6eSmbalmer sighdlr(int signum)
491469ed6eSmbalmer {
501469ed6eSmbalmer quit = 1;
511469ed6eSmbalmer }
521469ed6eSmbalmer
531469ed6eSmbalmer int
main(int argc,char * argv[])541469ed6eSmbalmer main(int argc, char *argv[])
551469ed6eSmbalmer {
56d6f310deSsthen struct rlimit rlim;
571469ed6eSmbalmer const char *errstr;
58de70259aShenning size_t len;
59bd755cd0Smbalmer u_int interval = 0, period = 30, nperiod;
60c1c14ec1Smbalmer int ch, trigauto, sauto, speriod;
6125f7cff5Smbalmer int quiet = 0, daemonize = 1, retval = 1, do_restore = 1;
62de70259aShenning int mib[3];
631469ed6eSmbalmer
6417046616Smbalmer while ((ch = getopt(argc, argv, "di:np:q")) != -1) {
651469ed6eSmbalmer switch (ch) {
661469ed6eSmbalmer case 'd':
671469ed6eSmbalmer daemonize = 0;
681469ed6eSmbalmer break;
691469ed6eSmbalmer case 'i':
70bd755cd0Smbalmer interval = (u_int)strtonum(optarg, 1LL, 86400LL,
71bd755cd0Smbalmer &errstr);
721469ed6eSmbalmer if (errstr)
731469ed6eSmbalmer errx(1, "interval is %s: %s", errstr, optarg);
741469ed6eSmbalmer break;
7517046616Smbalmer case 'n':
7625f7cff5Smbalmer do_restore = 0;
7717046616Smbalmer break;
781469ed6eSmbalmer case 'p':
79bd755cd0Smbalmer period = (u_int)strtonum(optarg, 2LL, 86400LL, &errstr);
801469ed6eSmbalmer if (errstr)
811469ed6eSmbalmer errx(1, "period is %s: %s", errstr, optarg);
821469ed6eSmbalmer break;
83a0bc59dfSmbalmer case 'q':
84a0bc59dfSmbalmer quiet = 1;
85a0bc59dfSmbalmer break;
861469ed6eSmbalmer default:
871469ed6eSmbalmer usage();
881469ed6eSmbalmer }
891469ed6eSmbalmer }
901469ed6eSmbalmer
91fde55bc4Spyr argc -= optind;
92fde55bc4Spyr argv += optind;
93fde55bc4Spyr if (argc > 0)
94fde55bc4Spyr usage();
95fde55bc4Spyr
96de70259aShenning if (interval == 0 && (interval = period / 3) == 0)
971469ed6eSmbalmer interval = 1;
981469ed6eSmbalmer
991469ed6eSmbalmer if (period <= interval)
1001469ed6eSmbalmer errx(1, "retrigger interval too long");
1011469ed6eSmbalmer
1021469ed6eSmbalmer /* save kern.watchdog.period and kern.watchdog.auto for restore */
1031469ed6eSmbalmer mib[0] = CTL_KERN;
1041469ed6eSmbalmer mib[1] = KERN_WATCHDOG;
1051469ed6eSmbalmer mib[2] = KERN_WATCHDOG_PERIOD;
1061469ed6eSmbalmer
1071469ed6eSmbalmer len = sizeof(speriod);
1081469ed6eSmbalmer if (sysctl(mib, 3, &speriod, &len, &period, sizeof(period)) == -1) {
1091469ed6eSmbalmer if (errno == EOPNOTSUPP)
1101469ed6eSmbalmer errx(1, "no watchdog timer available");
1111469ed6eSmbalmer else
1121469ed6eSmbalmer err(1, "can't access kern.watchdog.period");
1131469ed6eSmbalmer }
1141469ed6eSmbalmer
1151469ed6eSmbalmer mib[2] = KERN_WATCHDOG_AUTO;
1161469ed6eSmbalmer len = sizeof(sauto);
1171469ed6eSmbalmer trigauto = 0;
1181469ed6eSmbalmer
1191469ed6eSmbalmer if (sysctl(mib, 3, &sauto, &len, &trigauto, sizeof(trigauto)) == -1)
1201469ed6eSmbalmer err(1, "can't access kern.watchdog.auto");
1211469ed6eSmbalmer
1221469ed6eSmbalmer /* Double check the timeout period, some devices change the value */
1231469ed6eSmbalmer mib[2] = KERN_WATCHDOG_PERIOD;
1241469ed6eSmbalmer len = sizeof(nperiod);
1251469ed6eSmbalmer if (sysctl(mib, 3, &nperiod, &len, NULL, 0) == -1) {
1261469ed6eSmbalmer warnx("can't read back kern.watchdog.period, "
1271469ed6eSmbalmer "restoring original values");
1281469ed6eSmbalmer goto restore;
1291469ed6eSmbalmer }
1301469ed6eSmbalmer
131a0bc59dfSmbalmer if (nperiod != period && !quiet)
1321469ed6eSmbalmer warnx("period adjusted to %d by device", nperiod);
1331469ed6eSmbalmer
1341469ed6eSmbalmer if (nperiod <= interval) {
1351469ed6eSmbalmer warnx("retrigger interval %d too long, "
1361469ed6eSmbalmer "restoring original values", interval);
1371469ed6eSmbalmer goto restore;
1381469ed6eSmbalmer }
1391469ed6eSmbalmer
1401469ed6eSmbalmer if (daemonize && daemon(0, 0)) {
1411469ed6eSmbalmer warn("can't daemonize, restoring original values");
1421469ed6eSmbalmer goto restore;
1431469ed6eSmbalmer }
1441469ed6eSmbalmer
145d6f310deSsthen /*
146d6f310deSsthen * mlockall() below will wire the whole stack up to the limit
147d6f310deSsthen * thus we have to reduce stack size to avoid resource abuse
148d6f310deSsthen */
149d6f310deSsthen rlim.rlim_cur = 256 * 1024;
150d6f310deSsthen rlim.rlim_max = 256 * 1024;
151d6f310deSsthen (void)setrlimit(RLIMIT_STACK, &rlim);
152d6f310deSsthen
15382846cdaSmickey (void)mlockall(MCL_CURRENT | MCL_FUTURE);
154fb815d12Smickey setpriority(PRIO_PROCESS, getpid(), -5);
15582846cdaSmickey
1561469ed6eSmbalmer signal(SIGTERM, sighdlr);
1571469ed6eSmbalmer
1581469ed6eSmbalmer retval = 0;
1591469ed6eSmbalmer while (!quit) {
1601469ed6eSmbalmer if (sysctl(mib, 3, NULL, 0, &period, sizeof(period)) == -1)
161fb815d12Smickey quit = retval = 1;
1621469ed6eSmbalmer sleep(interval);
1631469ed6eSmbalmer }
1641469ed6eSmbalmer
16525f7cff5Smbalmer if (do_restore) {
16617046616Smbalmer restore: sysctl(mib, 3, NULL, 0, &speriod, sizeof(speriod));
1671469ed6eSmbalmer mib[2] = KERN_WATCHDOG_AUTO;
1681469ed6eSmbalmer sysctl(mib, 3, NULL, 0, &sauto, sizeof(sauto));
16917046616Smbalmer }
1701469ed6eSmbalmer
171c4c4febbSmbalmer return retval;
1721469ed6eSmbalmer }
173