【问题标题】:Why is setting 'echo V > /dev/watchdog1' not working when inside a 'systemd' service?为什么设置 \'echo V > /dev/watchdog1\' 在 \'systemd\' 服务中不起作用?
【发布时间】:2023-01-19 21:51:09
【问题描述】:

如果我手动停止我的服务然后执行echo V > /dev/watchdog1,看门狗会正常停止。

如果我在我的 systemd 服务中执行相同的 echo 命令,我得到:

看门狗没有停下!

ExecStopPost=echo V > /dev/watchdog1

为什么行为不一样?

【问题讨论】:

    标签: linux systemd watchdog


    【解决方案1】:

    由于这篇文章中提到的相同原因,这不起作用:Execute multiple commands with && in systemd service ExecStart on RedHat 7.9

    来自 systemd 服务内部的命令不会在适当的 shell 环境中执行。即便如此,我也没有明确说明这一点的某种来源。根据经验,单个 systemd exec 的功能如下: 运行一个带有参数的命令(不是多个命令,没有输出重定向等)。

    就像在引用的帖子中一样,解决方案可以如下编写:

    ExecStopPost=/bin/bash -c 'echo V > /dev/watchdog1'
    

    【讨论】:

    • 我尝试了您的解决方案,但进入了串口“watchdog:watchdog1:watchdoge 没有停止!”。在我在我的应用程序中配置的延迟之后,操作系统重新启动。
    • 只是想补充一点,不要忘记看门狗已经从 ExecStart 下的代码启动。我认为该代码具有对 watchdog1 文件的独占访问权限,并且在进程真正“被杀死”之前无法执行任何操作,因为从 systemctl stop myservice 返回后相同的“echo”命令起作用
    • 我的坏...它正在工作。看起来是因为我将结果和错误推送到一个文件,所以它不起作用 (echo V > /dev/watchdog1 >> myfile 2>> myfile
    【解决方案2】:

    您可以通过回声与您的看门狗互动,但我强烈建议您不要这样做。

    回声会在每次运行时打开/关闭您的看门狗,需要将其配置为不可停止的看门狗。此外,对于每次打开/关闭,您都会在 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 包。

    【讨论】:

    • 谢谢你的建议。查看您的代码,我看到您将“V”设置为 /dev/watchdog。就我而言,我应该改为将其更改为 /dev/watchdog1 还是无关紧要?
    • @david 根据您的需要更改WATCHDOG_DEV,也可以是/dev/watchdog1。关于编写 V 字符,也称为“魔法关闭”,它允许您在看门狗驱动程序中配置 NOWAYOUT=Y 时禁用看门狗。换句话说,如果您不编写魔术关闭和 NOWAYOUT=Y,您将无法在关闭其文件描述符后停止看门狗,并且您的机器将重新启动。在Documentation/watchdog/watchdog-api.txt 中阅读更多关于 magic close/nowayout 功能的信息
    【解决方案3】:

    我知道这与 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 2022-11-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多