【发布时间】:2023-01-19 21:51:09
【问题描述】:
如果我手动停止我的服务然后执行echo V > /dev/watchdog1,看门狗会正常停止。
如果我在我的 systemd 服务中执行相同的 echo 命令,我得到:
看门狗没有停下!
ExecStopPost=echo V > /dev/watchdog1为什么行为不一样?
【问题讨论】:
如果我手动停止我的服务然后执行echo V > /dev/watchdog1,看门狗会正常停止。
如果我在我的 systemd 服务中执行相同的 echo 命令,我得到:
看门狗没有停下!
ExecStopPost=echo V > /dev/watchdog1为什么行为不一样?
【问题讨论】:
由于这篇文章中提到的相同原因,这不起作用:Execute multiple commands with && in systemd service ExecStart on RedHat 7.9
来自 systemd 服务内部的命令不会在适当的 shell 环境中执行。即便如此,我也没有明确说明这一点的某种来源。根据经验,单个 systemd exec 的功能如下: 运行一个带有参数的命令(不是多个命令,没有输出重定向等)。
就像在引用的帖子中一样,解决方案可以如下编写:
ExecStopPost=/bin/bash -c 'echo V > /dev/watchdog1'
【讨论】:
您可以通过回声与您的看门狗互动,但我强烈建议您不要这样做。
回声会在每次运行时打开/关闭您的看门狗,需要将其配置为不可停止的看门狗。此外,对于每次打开/关闭,您都会在 kmsg log 中收到警告,收到不必要的疯狂垃圾邮件。
做对了;通过编写您自己的应用程序并处理其文件描述符来实现。不要再使用回声了!请参阅以下示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
// Read more:
// https://www.kernel.org/doc/Documentation/watchdog/watchdog-api.txt
#include <linux/watchdog.h>
#define WATCHDOG_DEV "/dev/watchdog"
int main(int argc, char** argv) {
/* Open your watchdog */
int fd = open(WATCHDOG_DEV, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Error: %s
", strerror(errno));
exit(EXIT_FAILURE);
}
/* Query timeout */
int timeout = 0;
if (ioctl(fd, WDIOC_GETTIMEOUT, &timeout) < 0) {
fprintf(stderr, "Error: Cannot read watchdog timeout: %s
", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "The timeout is %d seconds
", timeout);
/* Query timeleft */
int timeleft = 0;
if (ioctl(fd, WDIOC_GETTIMELEFT, &timeleft) < 0) {
fprintf(stderr, "Error: Cannot read watchdog timeleft: %s
", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "The timeleft is %d seconds
", timeleft);
/* Touch your watchdog */
if (ioctl(fd, WDIOC_KEEPALIVE, NULL) < 0) {
fprintf(stderr, "Error: Cannot write watchdog keepalive: %s
", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Keepalive written successfully
");
/* Stop your watchdog */
write(fd, "V", 1);
/* Close your watchdog */
close(fd);
return 0;
}
另一个(更简单的)选择是设置现成的看门狗服务。请参阅 Debian/Ubuntu 的 watchdog 包。
【讨论】:
WATCHDOG_DEV,也可以是/dev/watchdog1。关于编写 V 字符,也称为“魔法关闭”,它允许您在看门狗驱动程序中配置 NOWAYOUT=Y 时禁用看门狗。换句话说,如果您不编写魔术关闭和 NOWAYOUT=Y,您将无法在关闭其文件描述符后停止看门狗,并且您的机器将重新启动。在Documentation/watchdog/watchdog-api.txt 中阅读更多关于 magic close/nowayout 功能的信息
我知道这与 OP 的问题略有不同,但您也可以使用 systemd 的套接字 API 将看门狗管理委托给 systemd。
[Unit]
Description=My Unit
[Service]
ExecStart=/my/app args
WatchdogSec=30 # 30s, but you can specify whatever you want
# Optional: Restart=on-watchdog # Restart app on watchdog failure
# Optional: WatchdogSignal=SIGABRT # Change signal sent to kill app
#
然后,您必须定期从您的应用程序中重置看门狗:
sd_notify(0, "WATCHDOG=1");
还有一些选项可以让systemd在服务失败时重启机器,但我不记得是哪一个了。
如果您需要更多信息,可以在这里查看综合指南:https://0pointer.de/blog/projects/watchdog.html
【讨论】: