]> git.proxmox.com Git - pve-ha-manager.git/blob - src/watchdog-mux.c
update watchdog timer each second
[pve-ha-manager.git] / src / watchdog-mux.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/ioctl.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #include <sys/epoll.h>
13
14 #include <linux/types.h>
15 #include <linux/watchdog.h>
16
17 #include <systemd/sd-daemon.h>
18
19 #define MY_SOCK_PATH "/run/watchdog-mux.sock"
20 #define LISTEN_BACKLOG 50
21 #define MAX_EVENTS 10
22
23 #define WATCHDOG_DEV "/dev/watchdog"
24
25 int watchdog_fd = -1;
26 int watchdog_timeout = 20;
27
28 static void
29 watchdog_close(void)
30 {
31 if (watchdog_fd != -1) {
32 if (write(watchdog_fd, "V", 1) == -1) {
33 perror("write magic watchdog close");
34 }
35 if (close(watchdog_fd) == -1) {
36 perror("write magic watchdog close");
37 }
38 }
39
40 watchdog_fd = -1;
41 }
42
43 int
44 main(void)
45 {
46 struct sockaddr_un my_addr, peer_addr;
47 socklen_t peer_addr_size;
48 struct epoll_event ev, events[MAX_EVENTS];
49 int socket_count, listen_sock, nfds, epollfd;
50
51 struct stat fs;
52 if (stat(WATCHDOG_DEV, &fs) == -1) {
53 system("modprobe -q softdog soft_noboot=1"); // fixme
54 }
55
56 if ((watchdog_fd = open(WATCHDOG_DEV, O_WRONLY)) == -1) {
57 perror("watchdog open");
58 exit(EXIT_FAILURE);
59 }
60
61 if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &watchdog_timeout) == -1) {
62 perror("watchdog set timeout");
63 watchdog_close();
64 exit(EXIT_FAILURE);
65 }
66
67 /* read and log watchdog identity */
68 struct watchdog_info wdinfo;
69 if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &wdinfo) == -1) {
70 perror("read watchdog info");
71 watchdog_close();
72 exit(EXIT_FAILURE);
73 }
74
75 wdinfo.identity[sizeof(wdinfo.identity) - 1] = 0; // just to be sure
76 fprintf(stderr, "Watchdog driver '%s', version %x\n",
77 wdinfo.identity, wdinfo.firmware_version);
78
79 socket_count = sd_listen_fds(0);
80
81 if (socket_count > 1) {
82
83 perror("too many file descriptors received.\n");
84 goto err;
85
86 } else if (socket_count == 1) {
87
88 listen_sock = SD_LISTEN_FDS_START + 0;
89
90 } else {
91
92 unlink(MY_SOCK_PATH);
93
94 listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
95 if (listen_sock == -1) {
96 perror("socket create");
97 exit(EXIT_FAILURE);
98 }
99
100 memset(&my_addr, 0, sizeof(struct sockaddr_un));
101 my_addr.sun_family = AF_UNIX;
102 strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
103
104 if (bind(listen_sock, (struct sockaddr *) &my_addr,
105 sizeof(struct sockaddr_un)) == -1) {
106 perror("socket bind");
107 exit(EXIT_FAILURE);
108 }
109
110 if (listen(listen_sock, LISTEN_BACKLOG) == -1) {
111 perror("socket listen");
112 goto err;
113 }
114 }
115
116 epollfd = epoll_create(10);
117 if (epollfd == -1) {
118 perror("epoll_create");
119 goto err;
120 }
121
122 ev.events = EPOLLIN;
123 ev.data.fd = listen_sock;
124 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
125 perror("epoll_ctl: listen_sock");
126 goto err;
127 }
128
129 for (;;) {
130 nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1000);
131 if (nfds == -1) {
132 if (errno == EINTR)
133 continue;
134
135 perror("epoll_pwait");
136 goto err;
137 }
138
139 if (nfds == 0) { // timeout
140
141 if (ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0) == -1) {
142 perror("watchdog update failed");
143 }
144
145 continue;
146 }
147
148 int n;
149 for (n = 0; n < nfds; ++n) {
150 if (events[n].data.fd == listen_sock) {
151 int conn_sock = accept(listen_sock, (struct sockaddr *) &peer_addr, &peer_addr_size);
152 if (conn_sock == -1) {
153 perror("accept");
154 goto err; // fixme
155 }
156 if (fcntl(conn_sock, F_SETFL, O_NONBLOCK) == -1) {
157 perror("setnonblocking");
158 goto err; // fixme
159 }
160
161 ev.events = EPOLLIN;
162 ev.data.fd = conn_sock;
163 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
164 perror("epoll_ctl: add conn_sock");
165 goto err; // fixme
166 }
167 } else {
168 char buf[4096];
169 int cfd = events[n].data.fd;
170
171 ssize_t bytes = read(cfd, buf, sizeof(buf));
172 if (bytes == -1) {
173 perror("read");
174 goto err; // fixme
175 } else if (bytes > 0) {
176 printf("GOT %zd bytes\n", bytes);
177 } else {
178 if (events[n].events & EPOLLHUP || events[n].events & EPOLLERR) {
179 printf("GOT %016x event\n", events[n].events);
180 if (epoll_ctl(epollfd, EPOLL_CTL_DEL, cfd, NULL) == -1) {
181 perror("epoll_ctl: del conn_sock");
182 goto err; // fixme
183 }
184 if (close(cfd) == -1) {
185 perror("close conn_sock");
186 goto err; // fixme
187 }
188 }
189 }
190 }
191 }
192 }
193
194 printf("DONE\n");
195
196 // out:
197
198 watchdog_close();
199 unlink(MY_SOCK_PATH);
200 exit(EXIT_SUCCESS);
201
202 err:
203 unlink(MY_SOCK_PATH);
204 exit(EXIT_FAILURE);
205 }