]>
git.proxmox.com Git - pve-ha-manager.git/blob - src/watchdog-mux.c
11 #include <sys/socket.h>
13 #include <sys/epoll.h>
15 #include <sys/signalfd.h>
17 #include <linux/types.h>
18 #include <linux/watchdog.h>
20 #include <systemd/sd-daemon.h>
22 #define MY_SOCK_PATH "/run/watchdog-mux.sock"
23 #define WD_ACTIVE_MARKER "/run/watchdog-mux.active"
25 #define LISTEN_BACKLOG 50
28 #define WATCHDOG_DEV "/dev/watchdog"
31 int watchdog_timeout
= 20;
40 #define MAX_CLIENTS 100
42 static wd_client_t client_list
[MAX_CLIENTS
];
45 alloc_client(int fd
, time_t time
)
49 for (i
= 0; i
< MAX_CLIENTS
; i
++) {
50 if (client_list
[i
].fd
== 0) {
51 client_list
[i
].fd
= fd
;
52 client_list
[i
].time
= time
;
53 client_list
[i
].magic_close
= 0;
54 return &client_list
[i
];
62 free_client(wd_client_t
*wd_client
)
69 wd_client
->magic_close
= 0;
73 active_client_count(void)
77 for (i
= 0; i
< MAX_CLIENTS
; i
++) {
78 if (client_list
[i
].fd
!= 0 && client_list
[i
].time
!= 0) {
89 if (watchdog_fd
!= -1) {
90 if (write(watchdog_fd
, "V", 1) == -1) {
91 perror("write magic watchdog close");
93 if (close(watchdog_fd
) == -1) {
94 perror("write magic watchdog close");
104 struct sockaddr_un my_addr
, peer_addr
;
105 socklen_t peer_addr_size
;
106 struct epoll_event ev
, events
[MAX_EVENTS
];
107 int socket_count
, listen_sock
, nfds
, epollfd
, sigfd
;
112 if (stat(WD_ACTIVE_MARKER
, &fs
) == 0) {
113 fprintf(stderr
, "watchdog active - unable to restart watchdog-mux\n");
117 if (stat(WATCHDOG_DEV
, &fs
) == -1) {
118 system("modprobe -q softdog soft_noboot=1"); // fixme
121 if ((watchdog_fd
= open(WATCHDOG_DEV
, O_WRONLY
)) == -1) {
122 perror("watchdog open");
126 if (ioctl(watchdog_fd
, WDIOC_SETTIMEOUT
, &watchdog_timeout
) == -1) {
127 perror("watchdog set timeout");
132 /* read and log watchdog identity */
133 struct watchdog_info wdinfo
;
134 if (ioctl(watchdog_fd
, WDIOC_GETSUPPORT
, &wdinfo
) == -1) {
135 perror("read watchdog info");
140 wdinfo
.identity
[sizeof(wdinfo
.identity
) - 1] = 0; // just to be sure
141 fprintf(stderr
, "Watchdog driver '%s', version %x\n",
142 wdinfo
.identity
, wdinfo
.firmware_version
);
144 socket_count
= sd_listen_fds(0);
146 if (socket_count
> 1) {
148 perror("too many file descriptors received.\n");
151 } else if (socket_count
== 1) {
153 listen_sock
= SD_LISTEN_FDS_START
+ 0;
157 unlink(MY_SOCK_PATH
);
159 listen_sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
160 if (listen_sock
== -1) {
161 perror("socket create");
165 memset(&my_addr
, 0, sizeof(struct sockaddr_un
));
166 my_addr
.sun_family
= AF_UNIX
;
167 strncpy(my_addr
.sun_path
, MY_SOCK_PATH
, sizeof(my_addr
.sun_path
) - 1);
169 if (bind(listen_sock
, (struct sockaddr
*) &my_addr
,
170 sizeof(struct sockaddr_un
)) == -1) {
171 perror("socket bind");
175 if (listen(listen_sock
, LISTEN_BACKLOG
) == -1) {
176 perror("socket listen");
181 epollfd
= epoll_create(10);
183 perror("epoll_create");
188 ev
.data
.ptr
= alloc_client(listen_sock
, 0);
189 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, listen_sock
, &ev
) == -1) {
190 perror("epoll_ctl add listen_sock");
196 sigaddset(&mask
, SIGINT
);
197 sigaddset(&mask
, SIGTERM
);
198 sigaddset(&mask
, SIGHUP
);
200 sigprocmask(SIG_BLOCK
, &mask
, NULL
);
202 if ((sigfd
= signalfd(-1, &mask
, SFD_NONBLOCK
)) < 0) {
203 perror("unable to open signalfd");
208 ev
.data
.ptr
= alloc_client(sigfd
, 0);
209 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, sigfd
, &ev
) == -1) {
210 perror("epoll_ctl add sigfd");
215 nfds
= epoll_wait(epollfd
, events
, MAX_EVENTS
, 1000);
220 perror("epoll_pwait");
224 if (nfds
== 0) { // timeout
226 if (ioctl(watchdog_fd
, WDIOC_KEEPALIVE
, 0) == -1) {
227 perror("watchdog update failed");
236 for (n
= 0; n
< nfds
; ++n
) {
237 wd_client_t
*wd_client
= events
[n
].data
.ptr
;
238 if (wd_client
->fd
== listen_sock
) {
239 int conn_sock
= accept(listen_sock
, (struct sockaddr
*) &peer_addr
, &peer_addr_size
);
240 if (conn_sock
== -1) {
244 if (fcntl(conn_sock
, F_SETFL
, O_NONBLOCK
) == -1) {
245 perror("setnonblocking");
249 wd_client_t
*new_client
= alloc_client(conn_sock
, time(NULL
));
250 if (new_client
== NULL
) {
251 fprintf(stderr
, "unable to alloc wd_client structure\n");
255 mkdir(WD_ACTIVE_MARKER
, 0600);
258 ev
.data
.ptr
= new_client
;
259 if (epoll_ctl(epollfd
, EPOLL_CTL_ADD
, conn_sock
, &ev
) == -1) {
260 perror("epoll_ctl: add conn_sock");
263 } else if (wd_client
->fd
== sigfd
) {
265 /* signal handling */
268 struct signalfd_siginfo si
;
270 if ((rv
= read(sigfd
, &si
, sizeof(si
))) && rv
>= 0) {
271 if (si
.ssi_signo
== SIGHUP
) {
272 perror("got SIGHUP - ignored");
275 fprintf(stderr
, "got terminate request\n");
281 int cfd
= wd_client
->fd
;
283 ssize_t bytes
= read(cfd
, buf
, sizeof(buf
));
287 } else if (bytes
> 0) {
289 for (i
= 0; i
< bytes
; i
++) {
291 wd_client
->magic_close
= 1;
293 wd_client
->magic_close
= 0;
296 wd_client
->time
= time(NULL
);
298 if (events
[n
].events
& EPOLLHUP
|| events
[n
].events
& EPOLLERR
) {
299 //printf("GOT %016x event\n", events[n].events);
300 if (epoll_ctl(epollfd
, EPOLL_CTL_DEL
, cfd
, NULL
) == -1) {
301 perror("epoll_ctl: del conn_sock");
304 if (close(cfd
) == -1) {
305 perror("close conn_sock");
309 if (!wd_client
->magic_close
) {
310 fprintf(stderr
, "client did not stop watchdog\n");
312 free_client(wd_client
);
315 if (!active_client_count()) {
316 rmdir(WD_ACTIVE_MARKER
);
326 int active_count
= active_client_count();
327 if (active_count
> 0) {
328 fprintf(stderr
, "exit watchdog-mux with active connections\n");
330 fprintf(stderr
, "clean exit\n");
334 unlink(MY_SOCK_PATH
);
338 unlink(MY_SOCK_PATH
);