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