为什么在 'systemd' 服务中设置 'echo V > /dev/watchdog1' 不起作用?

Why is setting 'echo V > /dev/watchdog1' not working when inside a 'systemd' service?

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

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

watchdog did not stop!

ExecStopPost=echo V > /dev/watchdog1

为什么行为不一样?

由于 post 中提到的相同原因,这不起作用:

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

就像引用的post一样,解决方案可以这样写:

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

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

在每个 运行 上回显 opens/closes 你的看门狗,需要将其配置为 non-stoppable 看门狗。此外,对于每个 open/close,您都会在 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\n", 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\n", strerror(errno));
    exit(EXIT_FAILURE);
  }
  fprintf(stdout, "The timeout is %d seconds\n", timeout);

  /* Query timeleft */
  int timeleft = 0;
  if (ioctl(fd, WDIOC_GETTIMELEFT, &timeleft) < 0) {
    fprintf(stderr, "Error: Cannot read watchdog timeleft: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }
  fprintf(stdout, "The timeleft is %d seconds\n", timeleft);

  /* Touch your watchdog */
  if (ioctl(fd, WDIOC_KEEPALIVE, NULL) < 0) {
    fprintf(stderr, "Error: Cannot write watchdog keepalive: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }
  fprintf(stdout, "Keepalive written successfully\n");

  /* Stop your watchdog */
  write(fd, "V", 1);

  /* Close your watchdog */
  close(fd);

  return 0;
}

另一个(更简单的)选项是设置 ready-made 看门狗服务。请参阅 Debian/Ubuntu 的 watchdog 包。