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

Time:05-05

If I manually stop my service and then execute echo V > /dev/watchdog1, the watchdog stops properly.

If I do the same echo command in my systemd service, I get: watchdog did not stop!

ExecStopPost=echo V > /dev/watchdog1

Why the behavior is not the same?

CodePudding user response:

This does not work for the same reason mentioned in this post: Execute multiple commands with && in systemd service ExecStart on RedHat 7.9

The commands from inside a systemd service are not executed in a proper shell environment. Even so I do not have some kind of source that explicitly states this, from experience the capabilities of a single systemd exec are the following: Run one command with parameters (not multiple commands, no output redirection, etc.).

Just like in the referenced post the solution could be writing it as follows:

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

CodePudding user response:

You can interact with your watchdog through echoes, but I would strongly advise you against it.

An echo is opening and closing your watchdog on every run, needing to configure it as a non-stoppable watchdog. Also, for each open/close you are getting a warn in the kmsg log, receiving an unnecessary insane spam.

Do it right, do it by writing your own application and handling its file descriptor. Do not use echoes anymore! See the below example:

#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 successly\n");

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

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

  return 0;
}

Another (and easier) option could be to setup a ready-made watchdog service. See the watchdog package for Debian/Ubuntu: https://manpages.debian.org/stable/watchdog/watchdog.conf.5.en.html

  • Related