#define WD_SOCK_PATH "/run/watchdog-mux.sock"
#define WD_ACTIVE_MARKER "/run/watchdog-mux.active"
-#define LISTEN_BACKLOG 32 /* set same value in watchdog-mux.socket */
+#define LISTEN_BACKLOG 32
#define MAX_EVENTS 10
#define WATCHDOG_DEV "/dev/watchdog"
+#define JOURNALCTL_BIN "/bin/journalctl"
+
int watchdog_fd = -1;
int watchdog_timeout = 10;
int client_watchdog_timeout = 60;
-int update_watchdog = 1;
+int update_watchdog = 1;
typedef struct {
int fd;
count++;
}
}
-
+
return count;
}
-static void
+static void
watchdog_close(void)
{
if (watchdog_fd != -1) {
watchdog_fd = -1;
}
-
-int
+
+static void
+sync_journal_unsafe(void)
+{
+
+ pid_t child = fork();
+
+ // do not care about fork error or collecting the childs exit status,
+ // we are resetting soon anyway and just want to sync out the journal
+ if (child == 0) {
+ execl(JOURNALCTL_BIN, JOURNALCTL_BIN, "--sync", NULL);
+ exit(-1);
+ }
+}
+
+int
main(void)
{
struct sockaddr_un my_addr, peer_addr;
if (stat(WD_ACTIVE_MARKER, &fs) == 0) {
fprintf(stderr, "watchdog active - unable to restart watchdog-mux\n");
- exit(EXIT_FAILURE);
+ exit(EXIT_FAILURE);
}
/* if you want to debug, set options in /lib/modprobe.d/aliases.conf
perror("watchdog open");
exit(EXIT_FAILURE);
}
-
+
if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &watchdog_timeout) == -1) {
perror("watchdog set timeout");
watchdog_close();
strncpy(my_addr.sun_path, WD_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
if (bind(listen_sock, (struct sockaddr *) &my_addr,
- sizeof(struct sockaddr_un)) == -1) {
+ sizeof(struct sockaddr_un)) == -1) {
perror("socket bind");
exit(EXIT_FAILURE);
}
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGHUP);
-
+
sigprocmask(SIG_BLOCK, &mask, NULL);
-
+
if ((sigfd = signalfd(-1, &mask, SFD_NONBLOCK)) < 0) {
perror("unable to open signalfd");
goto err;
perror("epoll_ctl add sigfd");
goto err;
}
-
+
for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1000);
if (nfds == -1) {
if (errno == EINTR)
continue;
-
+
perror("epoll_pwait");
goto err;
}
if (client_list[i].fd != 0 && client_list[i].time != 0 &&
((ctime - client_list[i].time) > client_watchdog_timeout)) {
update_watchdog = 0;
- fprintf(stderr, "client watchdog expired - disable watchdog updates\n");
+ fprintf(stderr, "client watchdog expired - disable watchdog updates\n");
}
}
}
perror("watchdog update failed");
}
}
-
+
continue;
}
if (!update_watchdog)
break;
-
+
int terminate = 0;
-
+
int n;
for (n = 0; n < nfds; ++n) {
wd_client_t *wd_client = events[n].data.ptr;
fprintf(stderr, "unable to alloc wd_client structure\n");
goto err; // fixme;
}
-
+
mkdir(WD_ACTIVE_MARKER, 0600);
-
+
ev.events = EPOLLIN;
ev.data.ptr = new_client;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
perror("epoll_ctl: add conn_sock");
- goto err; // fixme
+ goto err; // fixme
}
} else if (wd_client->fd == sigfd) {
fprintf(stderr, "got terminate request\n");
}
}
-
+
} else {
char buf[4096];
int cfd = wd_client->fd;
-
+
ssize_t bytes = read(cfd, buf, sizeof(buf));
if (bytes == -1) {
perror("read");
- goto err; // fixme
+ goto err; // fixme
} else if (bytes > 0) {
int i;
for (i = 0; i < bytes; i++) {
//printf("GOT %016x event\n", events[n].events);
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, cfd, NULL) == -1) {
perror("epoll_ctl: del conn_sock");
- goto err; // fixme
+ goto err; // fixme
}
if (close(cfd) == -1) {
perror("close conn_sock");
- goto err; // fixme
+ goto err; // fixme
}
if (!wd_client->magic_close) {
fprintf(stderr, "client did not stop watchdog - disable watchdog updates\n");
+ sync_journal_unsafe();
update_watchdog = 0;
} else {
free_client(wd_client);
}
-
+
if (!active_client_count()) {
rmdir(WD_ACTIVE_MARKER);
}
int active_count = active_client_count();
if (active_count > 0) {
fprintf(stderr, "exit watchdog-mux with active connections\n");
+ sync_journal_unsafe();
} else {
fprintf(stderr, "clean exit\n");
watchdog_close();