X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=miscutils%2Fwatchdog.c;h=07ae64e52afbae01f090a6e7c01d6b34018b84bb;hb=179e88bec91cfe58096900dc5509a080ff37b083;hp=b1167dc90c8a4eb2b4a36dafdc59ec3f00bc166f;hpb=cde8f53c6054d35e1ec327bb2952aebeadc9ae48;p=oweals%2Fbusybox.git diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index b1167dc90..07ae64e52 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -3,79 +3,123 @@ * Mini watchdog implementation for busybox * * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2006 Bernhard Reutner-Fischer + * Copyright (C) 2008 Darius Augulis * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config WATCHDOG +//config: bool "watchdog" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: The watchdog utility is used with hardware or software watchdog +//config: device drivers. It opens the specified watchdog device special file +//config: and periodically writes a magic character to the device. If the +//config: watchdog applet ever fails to write the magic character within a +//config: certain amount of time, the watchdog device assumes the system has +//config: hung, and will cause the hardware to reboot. + +//applet:IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) -#include -#include -#include -#include -#include -#include "busybox.h" +//kbuild:lib-$(CONFIG_WATCHDOG) += watchdog.o -/* Userspace timer duration, in seconds */ -static unsigned int timer_duration = 30; +//usage:#define watchdog_trivial_usage +//usage: "[-t N[ms]] [-T N[ms]] [-F] DEV" +//usage:#define watchdog_full_usage "\n\n" +//usage: "Periodically write to watchdog device DEV\n" +//usage: "\n -T N Reboot after N seconds if not reset (default 60)" +//usage: "\n -t N Reset every N seconds (default 30)" +//usage: "\n -F Run in foreground" +//usage: "\n" +//usage: "\nUse 500ms to specify period in milliseconds" -/* Watchdog file descriptor */ -static int fd; +#include "libbb.h" +#include "linux/types.h" /* for __u32 */ +#include "linux/watchdog.h" -static void watchdog_shutdown(int unused) +#define OPT_FOREGROUND (1 << 0) +#define OPT_STIMER (1 << 1) +#define OPT_HTIMER (1 << 2) + +static void watchdog_shutdown(int sig UNUSED_PARAM) { - write(fd, "V", 1); /* Magic */ - close(fd); - exit(0); + static const char V = 'V'; + + remove_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); + write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ + if (ENABLE_FEATURE_CLEAN_UP) + close(3); + _exit(EXIT_SUCCESS); } -extern int watchdog_main(int argc, char **argv) +int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int watchdog_main(int argc, char **argv) { - int opt; - - while ((opt = getopt(argc, argv, "t:")) > 0) { - switch (opt) { - case 't': - timer_duration = bb_xgetlarg(optarg, 10, 0, INT_MAX); - break; - default: - bb_show_usage(); - } - } + static const struct suffix_mult suffixes[] = { + { "ms", 1 }, + { "", 1000 }, + { "", 0 } + }; - /* We're only interested in the watchdog device .. */ - if (optind < argc - 1 || argc == 1) - bb_show_usage(); + unsigned opts; + unsigned stimer_duration; /* how often to restart */ + unsigned htimer_duration = 60000; /* reboots after N ms if not restarted */ + char *st_arg; + char *ht_arg; - if (daemon(0, 1) < 0) - bb_perror_msg_and_die("Failed forking watchdog daemon"); + opt_complementary = "=1"; /* must have exactly 1 argument */ + opts = getopt32(argv, "Ft:T:", &st_arg, &ht_arg); - signal(SIGHUP, watchdog_shutdown); - signal(SIGINT, watchdog_shutdown); + /* We need to daemonize *before* opening the watchdog as many drivers + * will only allow one process at a time to do so. Since daemonizing + * is not perfect (child may run before parent finishes exiting), we + * can't rely on parent exiting before us (let alone *cleanly* releasing + * the watchdog fd -- something else that may not even be allowed). + */ + if (!(opts & OPT_FOREGROUND)) + bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); - fd = bb_xopen(argv[argc - 1], O_WRONLY); + if (opts & OPT_HTIMER) + htimer_duration = xatou_sfx(ht_arg, suffixes); + stimer_duration = htimer_duration / 2; + if (opts & OPT_STIMER) + stimer_duration = xatou_sfx(st_arg, suffixes); - while (1) { - /* - * Make sure we clear the counter before sleeping, as the counter value - * is undefined at this point -- PFM - */ - write(fd, "\0", 1); - sleep(timer_duration); + bb_signals(BB_FATAL_SIGS, watchdog_shutdown); + + /* Use known fd # - avoid needing global 'int fd' */ + xmove_fd(xopen(argv[argc - 1], O_WRONLY), 3); + + /* WDIOC_SETTIMEOUT takes seconds, not milliseconds */ + htimer_duration = htimer_duration / 1000; +#ifndef WDIOC_SETTIMEOUT +# error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet +#else +# if defined WDIOC_SETOPTIONS && defined WDIOS_ENABLECARD + { + static const int enable = WDIOS_ENABLECARD; + ioctl_or_warn(3, WDIOC_SETOPTIONS, (void*) &enable); } +# endif + ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration); +#endif + +#if 0 + ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration); + printf("watchdog: SW timer is %dms, HW timer is %ds\n", + stimer_duration, htimer_duration * 1000); +#endif - watchdog_shutdown(0); + write_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); - return EXIT_SUCCESS; + while (1) { + /* + * Make sure we clear the counter before sleeping, + * as the counter value is undefined at this point -- PFM + */ + write(3, "", 1); /* write zero byte */ + usleep(stimer_duration * 1000L); + } + return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */ }