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